mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 03:06:55 -04:00
Add pile
rotation mode (#1216)
* Add pile rotation mode * Fix formatting issues * Rename to .zig.zon * Update textures to those provided by ikabood-kee * Add gradual block breaking * Adapt to new model and texture changes * New duckweed textures * Add configurable state count * Rename to texturePile * Add moreData storage * Apply review suggestions --------- Co-authored-by: Carrie <carriecapp9@gmail.com>
This commit is contained in:
parent
20dfc6ba71
commit
07f5d823dd
24
assets/cubyz/blocks/duckweed.zig.zon
Normal file
24
assets/cubyz/blocks/duckweed.zig.zon
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
.{
|
||||||
|
.tags = .{.leaf},
|
||||||
|
.blockHealth = 0.2,
|
||||||
|
.drops = .{
|
||||||
|
.{.items = .{.auto}},
|
||||||
|
},
|
||||||
|
.degradable = true,
|
||||||
|
.collide = false,
|
||||||
|
.alwaysViewThrough = true,
|
||||||
|
.absorbedLight = 0x000000,
|
||||||
|
.model = .{
|
||||||
|
.model = "cubyz:plane",
|
||||||
|
.states = 4,
|
||||||
|
},
|
||||||
|
.rotation = .texturePile,
|
||||||
|
.texture0 = "cubyz:duckweed/0",
|
||||||
|
.texture1 = "cubyz:duckweed/1",
|
||||||
|
.texture2 = "cubyz:duckweed/2",
|
||||||
|
.texture3 = "cubyz:duckweed/3",
|
||||||
|
.item = .{
|
||||||
|
.texture = "duckweed.png",
|
||||||
|
},
|
||||||
|
.lodReplacement = "cubyz:air",
|
||||||
|
}
|
BIN
assets/cubyz/blocks/textures/duckweed/0.png
Normal file
BIN
assets/cubyz/blocks/textures/duckweed/0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 282 B |
BIN
assets/cubyz/blocks/textures/duckweed/1.png
Normal file
BIN
assets/cubyz/blocks/textures/duckweed/1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 362 B |
BIN
assets/cubyz/blocks/textures/duckweed/2.png
Normal file
BIN
assets/cubyz/blocks/textures/duckweed/2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 469 B |
BIN
assets/cubyz/blocks/textures/duckweed/3.png
Normal file
BIN
assets/cubyz/blocks/textures/duckweed/3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 483 B |
BIN
assets/cubyz/items/textures/duckweed.png
Normal file
BIN
assets/cubyz/items/textures/duckweed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 306 B |
@ -106,6 +106,7 @@ var _absorption: [maxBlockCount]u32 = undefined;
|
|||||||
/// GUI that is opened on click.
|
/// GUI that is opened on click.
|
||||||
var _gui: [maxBlockCount][]u8 = undefined;
|
var _gui: [maxBlockCount][]u8 = undefined;
|
||||||
var _mode: [maxBlockCount]*RotationMode = undefined;
|
var _mode: [maxBlockCount]*RotationMode = undefined;
|
||||||
|
var _modeData: [maxBlockCount]u16 = undefined;
|
||||||
var _lodReplacement: [maxBlockCount]u16 = undefined;
|
var _lodReplacement: [maxBlockCount]u16 = undefined;
|
||||||
var _opaqueVariant: [maxBlockCount]u16 = undefined;
|
var _opaqueVariant: [maxBlockCount]u16 = undefined;
|
||||||
var _friction: [maxBlockCount]f32 = undefined;
|
var _friction: [maxBlockCount]f32 = undefined;
|
||||||
@ -364,6 +365,10 @@ pub const Block = packed struct { // MARK: Block
|
|||||||
return _mode[self.typ];
|
return _mode[self.typ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn modeData(self: Block) u16 {
|
||||||
|
return _modeData[self.typ];
|
||||||
|
}
|
||||||
|
|
||||||
pub inline fn rotateZ(self: Block, angle: Degrees) Block {
|
pub inline fn rotateZ(self: Block, angle: Degrees) Block {
|
||||||
return .{.typ = self.typ, .data = self.mode().rotateZ(self.data, angle)};
|
return .{.typ = self.typ, .data = self.mode().rotateZ(self.data, angle)};
|
||||||
}
|
}
|
||||||
@ -666,7 +671,7 @@ pub const meshes = struct { // MARK: meshes
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn register(assetFolder: []const u8, _: []const u8, zon: ZonElement) void {
|
pub fn register(assetFolder: []const u8, _: []const u8, zon: ZonElement) void {
|
||||||
_modelIndex[meshes.size] = _mode[meshes.size].createBlockModel(zon.getChild("model"));
|
_modelIndex[meshes.size] = _mode[meshes.size].createBlockModel(.{.typ = @intCast(meshes.size), .data = 0}, &_modeData[meshes.size], zon.getChild("model"));
|
||||||
|
|
||||||
// The actual model is loaded later, in the rendering thread.
|
// The actual model is loaded later, in the rendering thread.
|
||||||
// But textures can be loaded here:
|
// But textures can be loaded here:
|
||||||
|
102
src/rotation.zig
102
src/rotation.zig
@ -41,7 +41,7 @@ pub const RotationMode = struct { // MARK: RotationMode
|
|||||||
fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, _: ?Neighbor, _: *Block, _: Block, blockPlacing: bool) bool {
|
fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, _: ?Neighbor, _: *Block, _: Block, blockPlacing: bool) bool {
|
||||||
return blockPlacing;
|
return blockPlacing;
|
||||||
}
|
}
|
||||||
fn createBlockModel(zon: ZonElement) ModelIndex {
|
fn createBlockModel(_: Block, _: *u16, zon: ZonElement) ModelIndex {
|
||||||
return main.models.getModelIndex(zon.as([]const u8, "cubyz:cube"));
|
return main.models.getModelIndex(zon.as([]const u8, "cubyz:cube"));
|
||||||
}
|
}
|
||||||
fn updateData(_: *Block, _: Neighbor, _: Block) bool {
|
fn updateData(_: *Block, _: Neighbor, _: Block) bool {
|
||||||
@ -126,7 +126,7 @@ pub const RotationMode = struct { // MARK: RotationMode
|
|||||||
// Rotates block data counterclockwise around the Z axis.
|
// Rotates block data counterclockwise around the Z axis.
|
||||||
rotateZ: *const fn(data: u16, angle: Degrees) u16 = DefaultFunctions.rotateZ,
|
rotateZ: *const fn(data: u16, angle: Degrees) u16 = DefaultFunctions.rotateZ,
|
||||||
|
|
||||||
createBlockModel: *const fn(zon: ZonElement) ModelIndex = &DefaultFunctions.createBlockModel,
|
createBlockModel: *const fn(block: Block, modeData: *u16, zon: ZonElement) ModelIndex = &DefaultFunctions.createBlockModel,
|
||||||
|
|
||||||
/// Updates the block data of a block in the world or places a block in the world.
|
/// Updates the block data of a block in the world or places a block in the world.
|
||||||
/// return true if the placing was successful, false otherwise.
|
/// return true if the placing was successful, false otherwise.
|
||||||
@ -176,7 +176,7 @@ pub const RotationModes = struct {
|
|||||||
rotatedModels.clearRetainingCapacity();
|
rotatedModels.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
pub fn createBlockModel(_: Block, _: *u16, zon: ZonElement) ModelIndex {
|
||||||
const modelId = zon.as([]const u8, "cubyz:cube");
|
const modelId = zon.as([]const u8, "cubyz:cube");
|
||||||
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
@ -235,7 +235,7 @@ pub const RotationModes = struct {
|
|||||||
rotatedModels.clearRetainingCapacity();
|
rotatedModels.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
pub fn createBlockModel(_: Block, _: *u16, zon: ZonElement) ModelIndex {
|
||||||
const modelId = zon.as([]const u8, "cubyz:cube");
|
const modelId = zon.as([]const u8, "cubyz:cube");
|
||||||
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
@ -355,7 +355,7 @@ pub const RotationModes = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
pub fn createBlockModel(_: Block, _: *u16, zon: ZonElement) ModelIndex {
|
||||||
const modelId = zon.as([]const u8, "cubyz:cube");
|
const modelId = zon.as([]const u8, "cubyz:cube");
|
||||||
if(fenceModels.get(modelId)) |modelIndex| return modelIndex;
|
if(fenceModels.get(modelId)) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
@ -638,7 +638,7 @@ pub const RotationModes = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
pub fn createBlockModel(_: Block, _: *u16, zon: ZonElement) ModelIndex {
|
||||||
const radius = zon.get(f32, "radius", 4);
|
const radius = zon.get(f32, "radius", 4);
|
||||||
if(branchModels.get(@bitCast(radius))) |modelIndex| return modelIndex;
|
if(branchModels.get(@bitCast(radius))) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
@ -900,7 +900,7 @@ pub const RotationModes = struct {
|
|||||||
return mem[0..faces];
|
return mem[0..faces];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(_: ZonElement) ModelIndex {
|
pub fn createBlockModel(_: Block, _: *u16, _: ZonElement) ModelIndex {
|
||||||
if(modelIndex) |idx| return idx;
|
if(modelIndex) |idx| return idx;
|
||||||
for(0..256) |i| {
|
for(0..256) |i| {
|
||||||
var quads = main.List(main.models.QuadInfo).init(main.stackAllocator);
|
var quads = main.List(main.models.QuadInfo).init(main.stackAllocator);
|
||||||
@ -1142,7 +1142,7 @@ pub const RotationModes = struct {
|
|||||||
rotatedModels.clearRetainingCapacity();
|
rotatedModels.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
pub fn createBlockModel(_: Block, _: *u16, zon: ZonElement) ModelIndex {
|
||||||
const baseModelId: []const u8 = zon.get([]const u8, "base", "cubyz:cube");
|
const baseModelId: []const u8 = zon.get([]const u8, "base", "cubyz:cube");
|
||||||
const sideModelId: []const u8 = zon.get([]const u8, "side", "cubyz:cube");
|
const sideModelId: []const u8 = zon.get([]const u8, "side", "cubyz:cube");
|
||||||
const key: []const u8 = std.mem.concat(main.stackAllocator.allocator, u8, &.{baseModelId, sideModelId}) catch unreachable;
|
const key: []const u8 = std.mem.concat(main.stackAllocator.allocator, u8, &.{baseModelId, sideModelId}) catch unreachable;
|
||||||
@ -1362,7 +1362,7 @@ pub const RotationModes = struct {
|
|||||||
rotatedModels.clearRetainingCapacity();
|
rotatedModels.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
pub fn createBlockModel(_: Block, _: *u16, zon: ZonElement) ModelIndex {
|
||||||
const modelId = zon.as([]const u8, "cubyz:cube");
|
const modelId = zon.as([]const u8, "cubyz:cube");
|
||||||
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
@ -1490,7 +1490,7 @@ pub const RotationModes = struct {
|
|||||||
modelCache = null;
|
modelCache = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
pub fn createBlockModel(_: Block, _: *u16, zon: ZonElement) ModelIndex {
|
||||||
const modelId = zon.as([]const u8, "cubyz:cube");
|
const modelId = zon.as([]const u8, "cubyz:cube");
|
||||||
if(!std.mem.eql(u8, modelId, "cubyz:cube")) {
|
if(!std.mem.eql(u8, modelId, "cubyz:cube")) {
|
||||||
std.log.err("Ores can only be use on cube models.", .{modelId});
|
std.log.err("Ores can only be use on cube models.", .{modelId});
|
||||||
@ -1540,6 +1540,88 @@ pub const RotationModes = struct {
|
|||||||
currentData.data = 0;
|
currentData.data = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
pub const TexturePile = struct {
|
||||||
|
pub const id: []const u8 = "texturePile";
|
||||||
|
var rotatedModels: std.StringHashMap(ModelIndex) = undefined;
|
||||||
|
|
||||||
|
fn init() void {
|
||||||
|
rotatedModels = .init(main.globalAllocator.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit() void {
|
||||||
|
rotatedModels.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset() void {
|
||||||
|
rotatedModels.clearRetainingCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transform(quad: *main.models.QuadInfo, data: u16) void {
|
||||||
|
quad.textureSlot = data%16;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createBlockModel(block: Block, modeData: *u16, zon: ZonElement) ModelIndex {
|
||||||
|
const modelId = zon.get([]const u8, "model", "cubyz:cube");
|
||||||
|
const stateCount = zon.get(u16, "states", 2);
|
||||||
|
const blockId = block.id();
|
||||||
|
if(stateCount <= 1) {
|
||||||
|
std.log.err("Block '{s}' uses texture pile with {} states. 'texturePile' should have at least 2 states, use 'no_rotation' instead", .{blockId, stateCount});
|
||||||
|
} else if(stateCount > 16) {
|
||||||
|
std.log.err("Block '{s}' uses texture pile with {} states. 'texturePile' can have at most 16 states.", .{blockId, stateCount});
|
||||||
|
}
|
||||||
|
modeData.* = stateCount;
|
||||||
|
|
||||||
|
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
|
const baseModel = main.models.getModelIndex(modelId).model();
|
||||||
|
|
||||||
|
const modelIndex = baseModel.transformModel(transform, .{@as(u16, @intCast(0))});
|
||||||
|
for(1..16) |data| {
|
||||||
|
_ = baseModel.transformModel(transform, .{@as(u16, @intCast(data))});
|
||||||
|
}
|
||||||
|
rotatedModels.put(modelId, modelIndex) catch unreachable;
|
||||||
|
return modelIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn model(block: Block) ModelIndex {
|
||||||
|
return .{.index = blocks.meshes.modelIndexStart(block).index + @min(block.data, block.modeData() - 1)};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, _: ?Neighbor, currentData: *Block, _: Block, blockPlacing: bool) bool {
|
||||||
|
if(blockPlacing) {
|
||||||
|
currentData.data = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(currentData.data >= currentData.modeData() - 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
currentData.data = currentData.data + 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn onBlockBreaking(_: ?main.items.Item, _: Vec3f, _: Vec3f, currentData: *Block) void {
|
||||||
|
if(currentData.data == 0) {
|
||||||
|
currentData.* = .{.typ = 0, .data = 0};
|
||||||
|
} else {
|
||||||
|
currentData.data = currentData.data - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn canBeChangedInto(oldBlock: Block, newBlock: Block, item: main.items.ItemStack, shouldDropSourceBlockOnSuccess: *bool) RotationMode.CanBeChangedInto {
|
||||||
|
switch(RotationMode.DefaultFunctions.canBeChangedInto(oldBlock, newBlock, item, shouldDropSourceBlockOnSuccess)) {
|
||||||
|
.no, .yes_costsDurability, .yes_dropsItems => return .no,
|
||||||
|
.yes, .yes_costsItems => {
|
||||||
|
const amountChange = @as(i32, newBlock.data) - if(oldBlock.typ == newBlock.typ) @as(i32, oldBlock.data) else 0;
|
||||||
|
if(amountChange <= 0) {
|
||||||
|
return .{.yes_dropsItems = @intCast(-amountChange)};
|
||||||
|
} else {
|
||||||
|
if(item.item == null or item.item.? != .baseItem or item.item.?.baseItem.block != newBlock.typ) return .no;
|
||||||
|
return .{.yes_costsItems = @intCast(amountChange)};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// MARK: init/register
|
// MARK: init/register
|
||||||
|
Loading…
x
Reference in New Issue
Block a user