Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Revamp the procedural crafting system. #974

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/Inventory.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1057,14 +1057,20 @@ pub const Command = struct { // MARK: Command
fn serialize(self: Open, data: *main.List(u8)) void {
std.mem.writeInt(u32, data.addMany(4)[0..4], self.inv.id, .big);
std.mem.writeInt(usize, data.addMany(8)[0..8], self.inv._items.len, .big);
data.append(@intFromEnum(self.inv.type));
data.append(@intFromEnum(std.meta.activeTag(self.inv.type)));
data.append(@intFromEnum(self.source));
switch (self.source) {
.playerInventory, .hand => |val| {
std.mem.writeInt(u32, data.addMany(4)[0..4], val, .big);
},
else => {}
}
switch(self.inv.type) {
.normal, .creative, .crafting => {},
.workbench => {
data.appendSlice(self.inv.type.workbench.id);
},
}
switch(self.source) {
.playerInventory, .sharedTestingInventory, .hand, .other => {},
.alreadyFreed => unreachable,
Expand All @@ -1076,7 +1082,7 @@ pub const Command = struct { // MARK: Command
if(side != .server or user == null) return error.Invalid;
const id = std.mem.readInt(u32, data[0..4], .big);
const len = std.mem.readInt(usize, data[4..12], .big);
const typ: Inventory.Type = @enumFromInt(data[12]);
const typeEnum: TypeEnum = @enumFromInt(data[12]);
const sourceType: SourceType = @enumFromInt(data[13]);
const source: Source = switch(sourceType) {
.playerInventory => .{.playerInventory = std.mem.readInt(u32, data[14..18], .big)},
Expand All @@ -1085,6 +1091,15 @@ pub const Command = struct { // MARK: Command
.other => .{.other = {}},
.alreadyFreed => unreachable,
};
const remainingLen: usize = switch(sourceType) {
.playerInventory, .hand => 18,
.sharedTestingInventory, .other => 14,
.alreadyFreed => unreachable,
};
const typ: Type = switch(typeEnum) {
inline .normal, .creative, .crafting => |tag| tag,
.workbench => .{.workbench = main.items.getToolTypeByID(data[remainingLen..]) orelse return error.Invalid},
};
Sync.ServerSide.createInventory(user.?, id, len, typ, source);
return .{
.inv = Sync.ServerSide.getInventory(user.?, id) orelse return error.Invalid,
Expand Down Expand Up @@ -1667,12 +1682,18 @@ const Source = union(SourceType) {

const Inventory = @This(); // MARK: Inventory

const Type = enum(u8) {
const TypeEnum = enum(u8) {
normal = 0,
creative = 1,
crafting = 2,
workbench = 3,
};
const Type = union(TypeEnum) {
normal: void,
creative: void,
crafting: void,
workbench: *const main.items.ToolType,
};
type: Type,
id: u32,
_items: []ItemStack,
Expand Down
21 changes: 18 additions & 3 deletions src/assets.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ var arenaAllocator: NeverFailingAllocator = undefined;
var commonBlocks: std.StringHashMap(ZonElement) = undefined;
var commonBiomes: std.StringHashMap(ZonElement) = undefined;
var commonItems: std.StringHashMap(ZonElement) = undefined;
var commonTools: std.StringHashMap(ZonElement) = undefined;
var commonRecipes: std.StringHashMap(ZonElement) = undefined;
var commonModels: std.StringHashMap([]const u8) = undefined;

Expand Down Expand Up @@ -181,7 +182,7 @@ pub fn readAllObjFilesInAddonsHashmap(externalAllocator: NeverFailingAllocator,
}
}

pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u8, blocks: *std.StringHashMap(ZonElement), items: *std.StringHashMap(ZonElement), biomes: *std.StringHashMap(ZonElement), recipes: *std.StringHashMap(ZonElement), models: *std.StringHashMap([]const u8)) void {
pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u8, blocks: *std.StringHashMap(ZonElement), items: *std.StringHashMap(ZonElement), tools: *std.StringHashMap(ZonElement), biomes: *std.StringHashMap(ZonElement), recipes: *std.StringHashMap(ZonElement), models: *std.StringHashMap([]const u8)) void {
var addons = main.List(std.fs.Dir).init(main.stackAllocator);
defer addons.deinit();
var addonNames = main.List([]const u8).init(main.stackAllocator);
Expand Down Expand Up @@ -214,6 +215,7 @@ pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u

readAllZonFilesInAddons(externalAllocator, addons, addonNames, "blocks", true, blocks);
readAllZonFilesInAddons(externalAllocator, addons, addonNames, "items", true, items);
readAllZonFilesInAddons(externalAllocator, addons, addonNames, "tools", true, tools);
readAllZonFilesInAddons(externalAllocator, addons, addonNames, "biomes", true, biomes);
readAllZonFilesInAddons(externalAllocator, addons, addonNames, "recipes", false, recipes);
readAllObjFilesInAddonsHashmap(externalAllocator, addons, addonNames, "models", models);
Expand All @@ -226,11 +228,12 @@ pub fn init() void {
arenaAllocator = arena.allocator();
commonBlocks = .init(arenaAllocator.allocator);
commonItems = .init(arenaAllocator.allocator);
commonTools = .init(arenaAllocator.allocator);
commonBiomes = .init(arenaAllocator.allocator);
commonRecipes = .init(arenaAllocator.allocator);
commonModels = .init(arenaAllocator.allocator);

readAssets(arenaAllocator, "assets/", &commonBlocks, &commonItems, &commonBiomes, &commonRecipes, &commonModels);
readAssets(arenaAllocator, "assets/", &commonBlocks, &commonItems, &commonTools, &commonBiomes, &commonRecipes, &commonModels);
}

fn registerItem(assetFolder: []const u8, id: []const u8, zon: ZonElement) !*items_zig.BaseItem {
Expand All @@ -247,6 +250,10 @@ fn registerItem(assetFolder: []const u8, id: []const u8, zon: ZonElement) !*item
return items_zig.register(assetFolder, texturePath, replacementTexturePath, id, zon);
}

fn registerTool(assetFolder: []const u8, id: []const u8, zon: ZonElement) void {
items_zig.registerTool(assetFolder, id, zon);
}

fn registerBlock(assetFolder: []const u8, id: []const u8, zon: ZonElement) !void {
const block = blocks_zig.register(assetFolder, id, zon);
blocks_zig.meshes.register(assetFolder, id, zon);
Expand Down Expand Up @@ -322,14 +329,16 @@ pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, biomePal
defer blocks.clearAndFree();
var items = commonItems.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable;
defer items.clearAndFree();
var tools = commonTools.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable;
defer tools.clearAndFree();
var biomes = commonBiomes.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable;
defer biomes.clearAndFree();
var recipes = commonRecipes.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable;
defer recipes.clearAndFree();
var models = commonModels.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable;
defer models.clearAndFree();

readAssets(arenaAllocator, assetFolder, &blocks, &items, &biomes, &recipes, &models);
readAssets(arenaAllocator, assetFolder, &blocks, &items, &tools, &biomes, &recipes, &models);
errdefer unloadAssets();

var modelIterator = models.iterator();
Expand Down Expand Up @@ -363,6 +372,12 @@ pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, biomePal
_ = try registerItem(assetFolder, entry.key_ptr.*, entry.value_ptr.*);
}

// tools:
iterator = tools.iterator();
while(iterator.next()) |entry| {
registerTool(assetFolder, entry.key_ptr.*, entry.value_ptr.*);
}

// block drops:
blocks_zig.finishBlocks(blocks);

Expand Down
60 changes: 52 additions & 8 deletions src/gui/windows/workbench.zig
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,24 @@ var inv: Inventory = undefined;

var craftingResult: *ItemSlot = undefined;

var seed: u32 = undefined;

var itemSlots: [25]*ItemSlot = undefined;

pub fn onOpen() void {
seed = @truncate(@as(u128, @bitCast(std.time.nanoTimestamp())));
inv = Inventory.init(main.globalAllocator, 26, .workbench, .other);
var toolTypes: main.ListUnmanaged(*const main.items.ToolType) = .{};
var currentToolType: usize = 0;

var toolButton: *Button = undefined;

var needsUpdate: bool = false;

fn toggleTool(_: usize) void {
currentToolType += 1;
currentToolType %= toolTypes.items.len;
toolButton.child.label.updateText(toolTypes.items[currentToolType].id);
needsUpdate = true;
}

fn openInventory() void {
inv = Inventory.init(main.globalAllocator, 26, .{.workbench = toolTypes.items[currentToolType]}, .other);
const list = HorizontalList.init();
{ // crafting grid
const grid = VerticalList.init(.{0, 0}, 300, 0);
Expand All @@ -61,19 +72,52 @@ pub fn onOpen() void {
grid.finish(.center);
list.add(grid);
}
list.add(Icon.init(.{8, 0}, .{32, 32}, inventory_crafting.arrowTexture, false));
list.add(ItemSlot.init(.{8, 0}, inv, 25, .craftingResult, .takeOnly));
const verticalThing = VerticalList.init(.{0, 0}, 300, padding);
toolButton = Button.initText(.{8, 0}, 116, toolTypes.items[currentToolType].id, .{.callback = &toggleTool});
verticalThing.add(toolButton);
const buttonHeight = verticalThing.size[1];
const craftingResultList = HorizontalList.init();
craftingResultList.add(Icon.init(.{0, 0}, .{32, 32}, inventory_crafting.arrowTexture, false));
craftingResultList.add(ItemSlot.init(.{8, 0}, inv, 25, .craftingResult, .takeOnly));
craftingResultList.finish(.{padding, padding}, .center);
verticalThing.add(craftingResultList);
verticalThing.size[1] += buttonHeight + 2*padding; // Centering the thing
verticalThing.finish(.center);
list.add(verticalThing);
list.finish(.{padding, padding + 16}, .center);
window.rootComponent = list.toComponent();
window.contentSize = window.rootComponent.?.pos() + window.rootComponent.?.size() + @as(Vec2f, @splat(padding));
gui.updateWindowPositions();
}

pub fn onClose() void {
fn closeInventory() void {
main.game.Player.inventory.depositOrDrop(inv);
inv.deinit(main.globalAllocator);
if(window.rootComponent) |*comp| {
comp.deinit();
window.rootComponent = null;
}
}

pub fn update() void {
if(needsUpdate) {
needsUpdate = false;
closeInventory();
openInventory();
}
}

pub fn onOpen() void {
currentToolType = 0;
var iterator = main.items.toolTypeIterator();

while(iterator.next()) |toolType| {
toolTypes.append(main.globalAllocator, toolType);
}
openInventory();
}

pub fn onClose() void {
closeInventory();
toolTypes.clearAndFree(main.globalAllocator);
}
35 changes: 35 additions & 0 deletions src/items.zig
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,12 @@ const ToolPhysics = struct { // MARK: ToolPhysics
}
};

pub const ToolType = struct { // MARK: ToolType
id: []const u8,
blockClass: main.blocks.BlockClass,
// TODO
};

pub const Tool = struct { // MARK: Tool
craftingGrid: [25]?*const BaseItem,
materialGrid: [16][16]?*const BaseItem,
Expand Down Expand Up @@ -1191,12 +1197,17 @@ const Recipe = struct { // MARK: Recipe
};

var arena: main.utils.NeverFailingArenaAllocator = undefined;
var toolTypes: std.StringHashMap(ToolType) = undefined;
var reverseIndices: std.StringHashMap(*BaseItem) = undefined;
pub var itemList: [65536]BaseItem = undefined;
pub var itemListSize: u16 = 0;

var recipeList: main.List(Recipe) = undefined;

pub fn toolTypeIterator() std.StringHashMap(ToolType).ValueIterator {
return toolTypes.valueIterator();
}

pub fn iterator() std.StringHashMap(*BaseItem).ValueIterator {
return reverseIndices.valueIterator();
}
Expand All @@ -1207,6 +1218,7 @@ pub fn recipes() []Recipe {

pub fn globalInit() void {
arena = .init(main.globalAllocator);
toolTypes = .init(arena.allocator().allocator);
reverseIndices = .init(arena.allocator().allocator);
recipeList = .init(arena.allocator());
itemListSize = 0;
Expand All @@ -1225,6 +1237,18 @@ pub fn register(_: []const u8, texturePath: []const u8, replacementTexturePath:
return newItem;
}

pub fn registerTool(_: []const u8, id: []const u8, zon: ZonElement) void {
std.log.info("Registering tool type {s}", .{id});
if(toolTypes.contains(id)) {
std.log.err("Registered tool type with id {s} twice!", .{id});
}
const idDupe = arena.allocator().dupe(u8, id);
toolTypes.put(idDupe, .{
.id = idDupe,
.blockClass = std.meta.stringToEnum(main.blocks.BlockClass, zon.get([]const u8, "blockClass", "none")) orelse .air,
}) catch unreachable;
}

fn parseRecipeItem(zon: ZonElement) !ItemStack {
var id = zon.as([]const u8, "");
id = std.mem.trim(u8, id, &std.ascii.whitespace);
Expand Down Expand Up @@ -1266,13 +1290,15 @@ pub fn registerRecipes(zon: ZonElement) void {
}

pub fn reset() void {
toolTypes.clearAndFree();
reverseIndices.clearAndFree();
recipeList.clearAndFree();
itemListSize = 0;
_ = arena.reset(.free_all);
}

pub fn deinit() void {
toolTypes.clearAndFree();
reverseIndices.clearAndFree();
recipeList.clearAndFree();
arena.deinit();
Expand All @@ -1287,3 +1313,12 @@ pub fn getByID(id: []const u8) ?*BaseItem {
return null;
}
}

pub fn getToolTypeByID(id: []const u8) ?*const ToolType {
if(toolTypes.getPtr(id)) |result| {
return result;
} else {
std.log.err("Couldn't find item {s}.", .{id});
return null;
}
}