MMO Update!
I wasn’t going to post another update, because I thought I hadn’t really changed much since then. However, when I reviewed my previous post… I’m up to 17kloc and the ecs switch netted me negative lines.
The changes off the top of my head
- My amazing <3 and busy wife, who happens to be a graphics and UX designer, made me a sidebar gui.
- implemented a quest system. integrated with the dialog
- Moved my networking/serialization, ecs, and String Itern Pool their own public repos. I plan to continue to break off more pieces as I go!
- Fully rewrote all my zon parse to make it way easier to work with. Now the data that I read in doesn’t need 2 definitions. Previously there were a lot of RawItem → BakedItem for processing zon data into a more efficient formats in memory.
- Thanks to that I could get rid of all my std.zon.parser patches, Except permitting parsing void fields. I have several fields define as below because it’s a client/server monorepo.
entity_description: if (Role == .Client) []const u8 else void,
- Added combat, Stats, Equipment, render some eqiupment(I haven’t checked pants and don’t want to).
- Properly added animations to models
- Made most of my text translatable
- Massively improved my in Godot tooling and setup f16 heightmap → Terrain3d importer
- fixed all memory leaks(painless thanks to the debug allocator)
- Learned about kcov and started playing number-go-up and I think I’m at about 80% coverage on client and server
- Properly more, but thats what I can find in my poorly writen commit logs
=== My zon solution ===
I really took a liking to how DVUI makes unit’ed Point types with pub fn Point(comptime unit: UnitEnum) type and have been expanding on the pattern. I create an enum(Pantry) that describes which environment the type is in(zon or baked)
pub const Pantry = enum(u8) {
zon,
baked,
pub fn ClientStr(comptime s: @This()) type {
if (common.Role != .Client) return void;
return switch (s) {
.zon => zon.Str,
.baked => common.StrRef,
};
}
pub fn Reward(comptime s: @This()) type {
return zon.Reward(s);
}
pub fn ItemStack(comptime s: @This()) type {
return switch (s) {
.zon => zon.ItemStack,
.baked => common.ItemStack,
};
}
pub fn ItemTag(comptime s: @This()) type {
return switch (s) {
.zon => zon.Str,
.baked => common.Tag,
};
}
...
}
Sometime I get lucky and the data doesn’t require structural changes. Then, I can just create a function to generate the baked version! I gain a nesting level, but save on the line maintenance.
pub fn Reward(comptime p: Pantry) type {
return struct {
items: []p.ItemStack() = &.{},
exp: []p.SkillExp() = &.{},
pub fn bake(zonself: Reward(.zon), alloc: Alloc) Alloc.Error!Reward(.baked) {
const items = try ItemStack.bake_list(zonself.items, alloc);
const exp = try alloc.alloc(SkillExp(.baked), zonself.exp.len);
for (zonself.exp, exp) |z, *e| e.* = z.bake();
return .{
.items = items,
.exp = exp,
};
}
};
}









