mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 03:06:55 -04:00
Add SBB rotation parameter (#1530)
## Description This pull request adds `rotation` parameter to `cubyz:sbb` simple structure with default value `.random` which allows specifying fixed or randomized rotation for structures generated. Rotation for structure is only propagate through the strcuture children only for vertical child blocks. Additionally, a `rotation` parameter was added to structure building block children definition to allow overriding / re-enabling random rotation for children of strcuture. Default value for that parameter is `inherit` which takes the rotation of parent (only for vertical child blocks until interrupted). Valid values for rotation are `0`, `90`, `180`, `270`, `random`, `inherit`, all accepted as a string, numeric values also accepted as floats and integers. ## Links Resolves: #1529 --------- Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com>
This commit is contained in:
parent
254546c789
commit
54aab15a4e
@ -20,36 +20,47 @@ const SbbGen = @This();
|
||||
|
||||
structureRef: *const sbb.StructureBuildingBlock,
|
||||
placeMode: Blueprint.PasteMode,
|
||||
rotation: sbb.Rotation,
|
||||
|
||||
pub fn getHash(self: SbbGen) u64 {
|
||||
return std.hash.Wyhash.hash(@intFromEnum(self.placeMode), self.structureRef.id);
|
||||
}
|
||||
|
||||
pub fn loadModel(arenaAllocator: NeverFailingAllocator, parameters: ZonElement) *SbbGen {
|
||||
const structureId = parameters.get(?[]const u8, "structure", null) orelse unreachable;
|
||||
const structureId = parameters.get(?[]const u8, "structure", null) orelse {
|
||||
main.utils.panicWithMessage("Error loading generator 'cubyz:sbb' structure field is mandatory.", .{});
|
||||
};
|
||||
const structureRef = sbb.getByStringId(structureId) orelse {
|
||||
std.log.err("Could not find structure building block with id '{s}'", .{structureId});
|
||||
unreachable;
|
||||
main.utils.panicWithMessage("Could not find structure building block with id '{s}'", .{structureId});
|
||||
};
|
||||
const rotationParam = parameters.getChild("rotation");
|
||||
const rotation = sbb.Rotation.fromZon(rotationParam) catch |err| blk: {
|
||||
switch(err) {
|
||||
error.UnknownString => std.log.err("Error loading generator 'cubyz:sbb' structure '{s}': Specified unknown rotation '{s}'", .{structureId, rotationParam.as([]const u8, "")}),
|
||||
error.UnknownType => std.log.err("Error loading generator 'cubyz:sbb' structure '{s}': Unsupported type of rotation field '{s}'", .{structureId, @tagName(rotationParam)}),
|
||||
}
|
||||
break :blk .random;
|
||||
};
|
||||
const self = arenaAllocator.create(SbbGen);
|
||||
self.* = .{
|
||||
.structureRef = structureRef,
|
||||
.placeMode = std.meta.stringToEnum(Blueprint.PasteMode, parameters.get([]const u8, "placeMode", "degradable")) orelse Blueprint.PasteMode.degradable,
|
||||
.rotation = rotation,
|
||||
};
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn generate(self: *SbbGen, _: GenerationMode, x: i32, y: i32, z: i32, chunk: *ServerChunk, _: CaveMapView, _: CaveBiomeMapView, seed: *u64, _: bool) void {
|
||||
placeSbb(self, self.structureRef, Vec3i{x, y, z}, Neighbor.dirUp, chunk, seed);
|
||||
placeSbb(self, self.structureRef, Vec3i{x, y, z}, Neighbor.dirUp, self.rotation.getInitialRotation(seed), chunk, seed);
|
||||
}
|
||||
|
||||
fn placeSbb(self: *SbbGen, structure: *const sbb.StructureBuildingBlock, placementPosition: Vec3i, placementDirection: Neighbor, chunk: *ServerChunk, seed: *u64) void {
|
||||
fn placeSbb(self: *SbbGen, structure: *const sbb.StructureBuildingBlock, placementPosition: Vec3i, placementDirection: Neighbor, rotation: sbb.Rotation, chunk: *ServerChunk, seed: *u64) void {
|
||||
const origin = structure.blueprints[0].originBlock;
|
||||
const rotationCount = alignDirections(origin.direction(), placementDirection) catch |err| {
|
||||
const blueprintRotation = rotation.apply(alignDirections(origin.direction(), placementDirection) catch |err| {
|
||||
std.log.err("Could not align directions for structure '{s}' for directions '{s}'' and '{s}', error: {s}", .{structure.id, @tagName(origin.direction()), @tagName(placementDirection), @errorName(err)});
|
||||
return;
|
||||
};
|
||||
const rotated = &structure.blueprints[rotationCount];
|
||||
});
|
||||
const rotated = &structure.blueprints[@intFromEnum(blueprintRotation)];
|
||||
const rotatedOrigin = rotated.originBlock.pos();
|
||||
const pastePosition = placementPosition - rotatedOrigin - placementDirection.relPos();
|
||||
|
||||
@ -57,19 +68,13 @@ fn placeSbb(self: *SbbGen, structure: *const sbb.StructureBuildingBlock, placeme
|
||||
|
||||
for(rotated.childBlocks) |childBlock| {
|
||||
const child = structure.pickChild(childBlock, seed) orelse continue;
|
||||
placeSbb(self, child, pastePosition + childBlock.pos(), childBlock.direction(), chunk, seed);
|
||||
const childRotation = rotation.getChildRotation(seed, child.rotation, childBlock.direction());
|
||||
placeSbb(self, child, pastePosition + childBlock.pos(), childBlock.direction(), childRotation, chunk, seed);
|
||||
}
|
||||
}
|
||||
|
||||
fn alignDirections(input: Neighbor, desired: Neighbor) !usize {
|
||||
const Rotation = enum(u3) {
|
||||
@"0" = 0,
|
||||
@"90" = 1,
|
||||
@"180" = 2,
|
||||
@"270" = 3,
|
||||
NotPossibleToAlign = 4,
|
||||
};
|
||||
comptime var alignTable: [6][6]Rotation = undefined;
|
||||
fn alignDirections(input: Neighbor, desired: Neighbor) !sbb.Rotation.FixedRotation {
|
||||
comptime var alignTable: [6][6]error{NotPossibleToAlign}!sbb.Rotation.FixedRotation = undefined;
|
||||
comptime for(Neighbor.iterable) |in| {
|
||||
for(Neighbor.iterable) |out| blk: {
|
||||
var current = in;
|
||||
@ -80,11 +85,8 @@ fn alignDirections(input: Neighbor, desired: Neighbor) !usize {
|
||||
}
|
||||
current = current.rotateZ();
|
||||
}
|
||||
alignTable[in.toInt()][out.toInt()] = Rotation.NotPossibleToAlign;
|
||||
alignTable[in.toInt()][out.toInt()] = error.NotPossibleToAlign;
|
||||
}
|
||||
};
|
||||
switch(alignTable[input.toInt()][desired.toInt()]) {
|
||||
.NotPossibleToAlign => return error.NotPossibleToAlign,
|
||||
else => |v| return @intFromEnum(v),
|
||||
}
|
||||
return alignTable[input.toInt()][desired.toInt()];
|
||||
}
|
||||
|
@ -114,10 +114,78 @@ pub fn isOriginBlock(block: Block) bool {
|
||||
return block.typ == originBlockNumericId;
|
||||
}
|
||||
|
||||
pub const RotationMode = enum {
|
||||
fixed,
|
||||
random,
|
||||
inherit,
|
||||
};
|
||||
|
||||
pub const Rotation = union(RotationMode) {
|
||||
fixed: FixedRotation,
|
||||
random: void,
|
||||
inherit: void,
|
||||
|
||||
pub const FixedRotation = enum(u2) {
|
||||
@"0" = 0,
|
||||
@"90" = 1,
|
||||
@"180" = 2,
|
||||
@"270" = 3,
|
||||
};
|
||||
|
||||
pub fn apply(self: Rotation, rotation: FixedRotation) FixedRotation {
|
||||
return switch(self) {
|
||||
.fixed => |fixed| @enumFromInt(@intFromEnum(rotation) +% @intFromEnum(fixed)),
|
||||
.random, .inherit => rotation,
|
||||
};
|
||||
}
|
||||
pub fn getInitialRotation(self: Rotation, seed: *u64) Rotation {
|
||||
return switch(self) {
|
||||
.fixed => self,
|
||||
.random => sampleRandom(seed),
|
||||
.inherit => .{.fixed = .@"0"},
|
||||
};
|
||||
}
|
||||
fn sampleRandom(seed: *u64) Rotation {
|
||||
return .{.fixed = @enumFromInt(main.random.nextInt(u2, seed))};
|
||||
}
|
||||
pub fn getChildRotation(self: Rotation, seed: *u64, child: Rotation, direction: Neighbor) Rotation {
|
||||
return switch(direction) {
|
||||
.dirDown, .dirUp => switch(child) {
|
||||
.random => sampleRandom(seed),
|
||||
.inherit => self,
|
||||
else => |r| r,
|
||||
},
|
||||
else => .{.fixed = .@"0"},
|
||||
};
|
||||
}
|
||||
pub fn fromZon(zon: ZonElement) error{UnknownString, UnknownType}!Rotation {
|
||||
return switch(zon) {
|
||||
.string, .stringOwned => |str| {
|
||||
if(std.meta.stringToEnum(FixedRotation, str)) |r| {
|
||||
return .{.fixed = r};
|
||||
}
|
||||
if(std.meta.stringToEnum(RotationMode, str)) |mode| {
|
||||
return switch(mode) {
|
||||
.fixed => .{.fixed = .@"0"},
|
||||
.random => .{.random = {}},
|
||||
.inherit => .{.inherit = {}},
|
||||
};
|
||||
}
|
||||
return error.UnknownString;
|
||||
},
|
||||
.int => |value| .{.fixed = @enumFromInt(@abs(@divTrunc(value, 90))%4)},
|
||||
.float => |value| .{.fixed = @enumFromInt(@abs(@as(u64, @intFromFloat(value/90.0)))%4)},
|
||||
.null => Rotation.random,
|
||||
else => return error.UnknownType,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const StructureBuildingBlock = struct {
|
||||
id: []const u8,
|
||||
children: []AliasTable(Child),
|
||||
blueprints: *[4]BlueprintEntry,
|
||||
rotation: Rotation,
|
||||
|
||||
fn initFromZon(stringId: []const u8, zon: ZonElement) !StructureBuildingBlock {
|
||||
const blueprintId = zon.get(?[]const u8, "blueprint", null) orelse {
|
||||
@ -128,6 +196,14 @@ pub const StructureBuildingBlock = struct {
|
||||
std.log.err("['{s}'] Could not find blueprint '{s}'.", .{stringId, blueprintId});
|
||||
return error.MissingBlueprint;
|
||||
};
|
||||
const rotationParam = zon.getChild("rotation");
|
||||
const rotation = Rotation.fromZon(rotationParam) catch |err| blk: {
|
||||
switch(err) {
|
||||
error.UnknownString => std.log.err("['{s}'] specified unknown rotation '{s}'", .{stringId, rotationParam.as([]const u8, "")}),
|
||||
error.UnknownType => std.log.err("['{s}'] unsupported type of rotation field '{s}'", .{stringId, @tagName(rotationParam)}),
|
||||
}
|
||||
break :blk .inherit;
|
||||
};
|
||||
|
||||
const blueprints = arenaAllocator.create([4]BlueprintEntry);
|
||||
blueprints.* = blueprintsTemplate.*;
|
||||
@ -136,6 +212,7 @@ pub const StructureBuildingBlock = struct {
|
||||
.id = stringId,
|
||||
.children = arenaAllocator.alloc(AliasTable(Child), childBlockStringId.items.len),
|
||||
.blueprints = blueprints,
|
||||
.rotation = rotation,
|
||||
};
|
||||
const childrenZon = zon.getChild("children");
|
||||
for(childBlockStringId.items, 0..) |colorName, colorIndex| {
|
||||
@ -186,6 +263,7 @@ pub const StructureBuildingBlock = struct {
|
||||
return .{
|
||||
.id = sbbId,
|
||||
.children = &.{},
|
||||
.rotation = .inherit,
|
||||
.blueprints = blueprints,
|
||||
};
|
||||
}
|
||||
|
@ -2213,7 +2213,7 @@ test "NamedCallbacks registers functions" {
|
||||
try std.testing.expectEqual(null, testFunctions.getFunctionPointer("wrongSignatureFunction"));
|
||||
}
|
||||
|
||||
pub fn panicWithMessage(comptime fmt: []const u8, args: anytype) void {
|
||||
pub fn panicWithMessage(comptime fmt: []const u8, args: anytype) noreturn {
|
||||
const message = std.fmt.allocPrint(main.stackAllocator.allocator, fmt, args) catch unreachable;
|
||||
@panic(message);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user