Libove Blog

Personal Blog about anything - mostly programming, cooking and random thoughts

#

I've just one-shotted an iterator with a lifetime in #rust. Is this what it feels like when the language finally clicks?


#

#gamedev progress:

  • materials are loaded from a configuration file
  • Adventurers return from quests and spawn a treasure chest
  • reworked text element to automatically adjust height of element

#

I've started working on a minimal TOML parser in #zig for my game. This is already enough to parse a file into a map of structs. I'm really impressed by the comptime type info.

const std = @import("std");

const ParserError = error{
    MissingEqual,
    MissingBraket,
    MissingQuote,
    UnsupportedType,
};

pub fn parse_file(
    comptime T: type,
    allocator: std.mem.Allocator,
    file_name: []const u8,
) !std.StringHashMap(T) {
    var map = std.StringHashMap(T).init(allocator);

    var file = try std.fs.cwd().openFile(file_name, .{});
    defer file.close();
    var buf_reader = std.io.bufferedReader(file.reader());
    var in_stream = buf_reader.reader();
    var buf: [1024]u8 = undefined;
    var name: ?[]const u8 = null;
    var cur_item: T = undefined;
    while (try in_stream.readUntilDelimiterOrEof(&buf, '\n')) |line| {
        const clean = std.mem.trim(u8, line, &std.ascii.whitespace);
        // skip empty
        if (clean.len == 0) {
            continue;
        }

        if (clean[0] == '[') {
            if (name != null) {
                try map.put(name.?, cur_item);
            }
            const name_split_idx = std.mem.indexOf(u8, clean, "]") orelse return ParserError.MissingBraket;
            name = try allocator.dupe(u8, clean[1..name_split_idx]);
            continue;
        }

        const split_idx = try (std.mem.indexOf(u8, clean, "=") orelse ParserError.MissingEqual);
        const field_name = std.mem.trim(u8, clean[0..split_idx], &std.ascii.whitespace);
        const value = std.mem.trim(u8, clean[split_idx + 1 ..], &std.ascii.whitespace);

        const type_info = comptime @typeInfo(T);
        const fields = comptime type_info.@"struct".fields;
        inline for (fields) |field| {
            if (std.mem.eql(u8, field_name, field.name)) {
                switch (field.type) {
                    f32, f64 => |Float| {
                        @field(cur_item, field.name) = try std.fmt.parseFloat(Float, value);
                    },
                    u8, u32, u64, i8, i32, i64 => |Int| {
                        @field(cur_item, field.name) = try std.fmt.parseInt(Int, value, 10);
                    },
                    []u8 => {
                        if (value[0] != '"' or value[value.len - 1] != '"') {
                            return ParserError.MissingQuote;
                        }
                        @field(cur_item, field.name) = try allocator.dupe(u8, value[1 .. value.len - 1]);
                    },
                    else => {
                        return ParserError.UnsupportedType;
                    },
                }
                break;
            }
        }
    }
    if (name != null) {
        try map.put(name.?, cur_item);
    }

    return map;
}


#

https://techhub.social/@ajfriesen/115226740616849332

Maybe you should use owl-blogs ;)

Your blog is missing the webfinger. This is used my most fediverse services to check if an account exists and to get all needed infos. Maybe this helps to debug this.

https://ajfriesen.com/.well-known/webfinger/?resource=acct:blog@ajfriesen.com

https://blog.libove.org/.well-known/webfinger?resource=acct:h4kor@blog.libove.org




#

#gamedev

refactored hero logic into state pattern. So much better!

Code screenshot showing state pattern (left) and previous version.



#

#gamedev progress:

  • Trader implementation: appear regularly at the tavern selling materials for crafting.
  • Adventurers implementation: Have a quest and can be booked into rooms. When the embark on a quest after their stay.
  • Reworked items: previously I had an enum to distinguish between different items. This would become infeasible once I start adding more items. Rework to have a generic item struct.
  • Reworked recipes: similar to items, each recipe is now a struct. The recipe defines the ingredient requirements and a function to generate the resulting item.