// zig fmt: off const std = @import("std"); const Api = @import("artifacts-api"); const rl = @import("raylib"); const raylib_h = @cImport({ @cInclude("stdio.h"); @cInclude("raylib.h"); }); const App = @import("./app.zig"); pub const std_options = .{ .log_scope_levels = &[_]std.log.ScopeLevel{ .{ .scope = .api, .level = .warn }, .{ .scope = .raylib, .level = .warn }, } }; fn toRaylibTraceLogLevel(log_level: std.log.Level) rl.TraceLogLevel { return switch (log_level) { .err => rl.TraceLogLevel.log_error, .warn => rl.TraceLogLevel.log_warning, .info => rl.TraceLogLevel.log_info, .debug => rl.TraceLogLevel.log_trace, }; } fn toZigLogLevel(log_type: c_int) ?std.log.Level { return switch (log_type) { @intFromEnum(rl.TraceLogLevel.log_trace) => std.log.Level.debug, @intFromEnum(rl.TraceLogLevel.log_debug) => std.log.Level.debug, @intFromEnum(rl.TraceLogLevel.log_info) => std.log.Level.info, @intFromEnum(rl.TraceLogLevel.log_warning) => std.log.Level.warn, @intFromEnum(rl.TraceLogLevel.log_error) => std.log.Level.err, @intFromEnum(rl.TraceLogLevel.log_fatal) => std.log.Level.err, else => null, }; } fn raylibTraceLogCallback(logType: c_int, text: [*c]const u8, args: [*c]raylib_h.struct___va_list_tag_1) callconv(.C) void { const log_level = toZigLogLevel(logType) orelse return; const scope = .raylib; const raylib_log = std.log.scoped(scope); const max_tracelog_msg_length = 256; // from utils.c in raylib var buffer: [max_tracelog_msg_length:0]u8 = undefined; inline for (std.meta.fields(std.log.Level)) |field| { const message_level: std.log.Level = @enumFromInt(field.value); if (std.log.logEnabled(message_level, scope) and log_level == message_level) { @memset(&buffer, 0); const text_length = raylib_h.vsnprintf(&buffer, buffer.len, text, args); const formatted_text = buffer[0..@intCast(text_length)]; const log_function = @field(raylib_log, field.name); @call(.auto, log_function, .{ "{s}", .{formatted_text} }); } } } fn getAPITokenFromArgs(allocator: std.mem.Allocator) !?[]u8 { const args = try std.process.argsAlloc(allocator); defer std.process.argsFree(allocator, args); if (args.len < 2) { return null; } const filename = args[1]; const cwd = std.fs.cwd(); var token_buffer: [256]u8 = undefined; const token = try cwd.readFile(filename, &token_buffer); return try allocator.dupe(u8, std.mem.trim(u8, token, "\n\t ")); } pub fn main() anyerror!void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); raylib_h.SetTraceLogCallback(raylibTraceLogCallback); rl.setTraceLogLevel(toRaylibTraceLogLevel(std.log.default_level)); const token = (try getAPITokenFromArgs(allocator)) orelse return error.MissingToken; defer allocator.free(token); var store = try Api.Store.init(allocator); defer store.deinit(allocator); var server = try Api.Server.init(allocator, &store); defer server.deinit(); try server.setToken(token); std.log.info("Prefetching server data", .{}); { const cwd_path = try std.fs.cwd().realpathAlloc(allocator, "."); defer allocator.free(cwd_path); const cache_path = try std.fs.path.resolve(allocator, &.{ cwd_path, "./api-store-gui.bin" }); defer allocator.free(cache_path); try server.prefetchCached(allocator, cache_path, .{ .images = true }); } const characters = try server.getMyCharacters(allocator); characters.deinit(); rl.initWindow(800, 450, "Artificer"); defer rl.closeWindow(); rl.setWindowMinSize(200, 200); rl.setWindowState(.{ .vsync_hint = true, .window_resizable = true }); var app = try App.init(allocator, &store, &server); defer app.deinit(); while (!rl.windowShouldClose()) { try app.tick(); } }