allocator: std.mem.Allocator, lastUpdateFrame: u64 = 0, arena: std.heap.ArenaAllocator, strings: std.ArrayListUnmanaged([]u8) = .{}, pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "game.EngineTool"); pub fn create(allocator: std.mem.Allocator) !*@This() { const self = try allocator.create(@This()); self.* = .{ .allocator = allocator, .arena = std.heap.ArenaAllocator.init(allocator), }; if (core.getEngineObject(igutils.TopBar)) |topbar| { topbar.addMenuObject(self, "Engine Object Browser") catch {}; } return self; } pub fn maybeUpdate(self: *@This()) !void { const engine = core.getEngine(); if (engine.engineObjectLUF != self.lastUpdateFrame) { self.lastUpdateFrame = engine.engineObjectLUF; _ = self.arena.reset(.retain_capacity); self.strings = .{}; errdefer { _ = self.arena.reset(.retain_capacity); self.strings = .{}; } const alloc = self.arena.allocator(); for (engine.engineObjects.items) |x| { const newString = try std.fmt.allocPrint(alloc, "[{s}] {s} @ 0x{x} (size: {d} bytes) ", .{ x.vtable.singletonName orelse "n/a", x.vtable.typeName, @intFromPtr(x.ptr), x.vtable.typeSize, }); try self.strings.append(alloc, newString); } } } pub fn windowOpen(entry: *igutils.MenuEntry, dt: f64) void { _ = dt; const self: *@This() = @ptrCast(@alignCast(entry.ctx)); if (ig.begin("EngineTool", &entry.open, .{})) { self.maybeUpdate() catch { ig.textSlice("Unable to update engine tools list"); return; }; for (self.strings.items) |slice| { ig.textSlice(slice); } if (core.getEngineObject(core.ecs.EcsRegistry)) |ecsReg| { ig.separator(); for (ecsReg.containerNames.items, 0..) |*name, i| { _ = i; ig.textf("{s}", .{name.utf8()}); } } } ig.end(); } pub fn destroy(self: *@This()) void { self.arena.deinit(); self.allocator.destroy(self); } const std = @import("std"); const backlog = @import("Backlog"); const core = backlog.core; const rend = backlog.rend; const ig = backlog.imgui.api; const igutils = backlog.imgui.utils;