mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 03:06:55 -04:00
Move /set
to be method on Blueprint
(#1352)
* Move Pattern into Blueprint * Improve error message on capture failure * Change memory management
This commit is contained in:
parent
64ce0ed991
commit
86e0a9ae4b
@ -20,6 +20,9 @@ const BlockStorageType = u32;
|
||||
const BinaryWriter = main.utils.BinaryWriter;
|
||||
const BinaryReader = main.utils.BinaryReader;
|
||||
|
||||
const AliasTable = main.utils.AliasTable;
|
||||
const ListUnmanaged = main.ListUnmanaged;
|
||||
|
||||
pub const blueprintVersion = 0;
|
||||
var voidType: ?u16 = null;
|
||||
|
||||
@ -36,7 +39,7 @@ pub const Blueprint = struct {
|
||||
pub fn deinit(self: Blueprint, allocator: NeverFailingAllocator) void {
|
||||
self.blocks.deinit(allocator);
|
||||
}
|
||||
pub fn clone(self: *Blueprint, allocator: NeverFailingAllocator) Blueprint {
|
||||
pub fn clone(self: Blueprint, allocator: NeverFailingAllocator) Blueprint {
|
||||
return .{.blocks = self.blocks.clone(allocator)};
|
||||
}
|
||||
pub fn rotateZ(self: Blueprint, allocator: NeverFailingAllocator, angle: Degrees) Blueprint {
|
||||
@ -274,6 +277,62 @@ pub const Blueprint = struct {
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn set(self: *Blueprint, pattern: Pattern) void {
|
||||
for(0..self.blocks.width) |x| {
|
||||
for(0..self.blocks.depth) |y| {
|
||||
for(0..self.blocks.height) |z| {
|
||||
self.blocks.set(x, y, z, pattern.blocks.sample(&main.seed).block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const Pattern = struct {
|
||||
blocks: AliasTable(Entry),
|
||||
|
||||
const Entry = struct {
|
||||
block: Block,
|
||||
chance: f32,
|
||||
};
|
||||
|
||||
pub fn initFromString(allocator: NeverFailingAllocator, source: []const u8) !@This() {
|
||||
var specifiers = std.mem.splitScalar(u8, source, ',');
|
||||
var totalWeight: f32 = 0;
|
||||
|
||||
var weightedEntries: ListUnmanaged(struct {block: Block, weight: f32}) = .{};
|
||||
defer weightedEntries.deinit(main.stackAllocator);
|
||||
|
||||
while(specifiers.next()) |specifier| {
|
||||
var iterator = std.mem.splitScalar(u8, specifier, '%');
|
||||
|
||||
var weight: f32 = undefined;
|
||||
var block = main.blocks.parseBlock(iterator.rest());
|
||||
|
||||
const first = iterator.first();
|
||||
|
||||
weight = std.fmt.parseFloat(f32, first) catch blk: {
|
||||
// To distinguish somehow between mistyped numeric values and actual block IDs we check for addon name separator.
|
||||
if(!std.mem.containsAtLeastScalar(u8, first, 1, ':')) return error.PatternSyntaxError;
|
||||
block = main.blocks.parseBlock(first);
|
||||
break :blk 1.0;
|
||||
};
|
||||
totalWeight += weight;
|
||||
weightedEntries.append(main.stackAllocator, .{.block = block, .weight = weight});
|
||||
}
|
||||
|
||||
const entries = allocator.alloc(Entry, weightedEntries.items.len);
|
||||
for(weightedEntries.items, 0..) |entry, i| {
|
||||
entries[i] = .{.block = entry.block, .chance = entry.weight/totalWeight};
|
||||
}
|
||||
|
||||
return .{.blocks = .init(allocator, entries)};
|
||||
}
|
||||
|
||||
pub fn deinit(self: @This(), allocator: NeverFailingAllocator) void {
|
||||
self.blocks.deinit(allocator);
|
||||
allocator.free(self.blocks.items);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn registerVoidBlock(block: Block) void {
|
||||
|
@ -1,52 +0,0 @@
|
||||
const std = @import("std");
|
||||
|
||||
const main = @import("main");
|
||||
const AliasTable = main.utils.AliasTable;
|
||||
const Block = main.blocks.Block;
|
||||
const ListUnmanaged = main.ListUnmanaged;
|
||||
const NeverFailingAllocator = main.heap.NeverFailingAllocator;
|
||||
|
||||
blocks: AliasTable(Entry),
|
||||
|
||||
const Entry = struct {
|
||||
block: Block,
|
||||
chance: f32,
|
||||
};
|
||||
|
||||
pub fn initFromString(allocator: NeverFailingAllocator, source: []const u8) !@This() {
|
||||
var specifiers = std.mem.splitScalar(u8, source, ',');
|
||||
var totalWeight: f32 = 0;
|
||||
|
||||
var weightedEntries: ListUnmanaged(struct {block: Block, weight: f32}) = .{};
|
||||
defer weightedEntries.deinit(main.stackAllocator);
|
||||
|
||||
while(specifiers.next()) |specifier| {
|
||||
var iterator = std.mem.splitScalar(u8, specifier, '%');
|
||||
|
||||
var weight: f32 = undefined;
|
||||
var block = main.blocks.parseBlock(iterator.rest());
|
||||
|
||||
const first = iterator.first();
|
||||
|
||||
weight = std.fmt.parseFloat(f32, first) catch blk: {
|
||||
// To distinguish somehow between mistyped numeric values and actual block IDs we check for addon name separator.
|
||||
if(!std.mem.containsAtLeastScalar(u8, first, 1, ':')) return error.PatternSyntaxError;
|
||||
block = main.blocks.parseBlock(first);
|
||||
break :blk 1.0;
|
||||
};
|
||||
totalWeight += weight;
|
||||
weightedEntries.append(main.stackAllocator, .{.block = block, .weight = weight});
|
||||
}
|
||||
|
||||
const entries = allocator.alloc(Entry, weightedEntries.items.len);
|
||||
for(weightedEntries.items, 0..) |entry, i| {
|
||||
entries[i] = .{.block = entry.block, .chance = entry.weight/totalWeight};
|
||||
}
|
||||
|
||||
return .{.blocks = .init(allocator, entries)};
|
||||
}
|
||||
|
||||
pub fn deinit(self: @This(), allocator: NeverFailingAllocator) void {
|
||||
self.blocks.deinit(allocator);
|
||||
allocator.free(self.blocks.items);
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
const std = @import("std");
|
||||
|
||||
const main = @import("main");
|
||||
const Vec3i = main.vec.Vec3i;
|
||||
const User = main.server.User;
|
||||
const Pattern = @import("Pattern.zig");
|
||||
|
||||
const Block = main.blocks.Block;
|
||||
const Blueprint = main.blueprint.Blueprint;
|
||||
const Pattern = main.blueprint.Pattern;
|
||||
|
||||
pub const description = "Set all blocks within selection to a block.";
|
||||
pub const usage = "/set <pattern>";
|
||||
@ -27,25 +28,24 @@ pub fn execute(args: []const u8, source: *User) void {
|
||||
};
|
||||
defer pattern.deinit(main.stackAllocator);
|
||||
|
||||
const startX = @min(pos1[0], pos2[0]);
|
||||
const startY = @min(pos1[1], pos2[1]);
|
||||
const startZ = @min(pos1[2], pos2[2]);
|
||||
const posStart: Vec3i = @min(pos1, pos2);
|
||||
const posEnd: Vec3i = @max(pos1, pos2);
|
||||
|
||||
const width = @abs(pos2[0] - pos1[0]) + 1;
|
||||
const depth = @abs(pos2[1] - pos1[1]) + 1;
|
||||
const height = @abs(pos2[2] - pos1[2]) + 1;
|
||||
const selection = Blueprint.capture(main.globalAllocator, posStart, posEnd);
|
||||
|
||||
for(0..width) |x| {
|
||||
const worldX = startX +% @as(i32, @intCast(x));
|
||||
switch(selection) {
|
||||
.success => |blueprint| {
|
||||
source.worldEditData.undoHistory.push(.init(blueprint, posStart, "set"));
|
||||
source.worldEditData.redoHistory.clear();
|
||||
|
||||
for(0..depth) |y| {
|
||||
const worldY = startY +% @as(i32, @intCast(y));
|
||||
var modifiedBlueprint = blueprint.clone(main.stackAllocator);
|
||||
defer modifiedBlueprint.deinit(main.stackAllocator);
|
||||
|
||||
for(0..height) |z| {
|
||||
const worldZ = startZ +% @as(i32, @intCast(z));
|
||||
|
||||
_ = main.server.world.?.updateBlock(worldX, worldY, worldZ, pattern.blocks.sample(&main.seed).block);
|
||||
}
|
||||
}
|
||||
modifiedBlueprint.set(pattern);
|
||||
modifiedBlueprint.paste(posStart, .{.preserveVoid = true});
|
||||
},
|
||||
.failure => |err| {
|
||||
source.sendMessage("#ff0000Error: Could not capture selection. (at {}, {s})", .{err.pos, err.message});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user