From db49ef360685c1a771ca5d9ea903e9910ad820d4 Mon Sep 17 00:00:00 2001 From: Peter Li Date: Sun, 18 May 2025 14:45:06 -0700 Subject: [PATCH] module cache works --- .gitignore | 4 + engine/assets/src/assets.zig | 7 +- engine/audio/src/audio.zig | 4 +- engine/backlog.zig | 59 +++++--- engine/core/build.zig | 15 ++ engine/core/src/configVars.zig | 2 +- engine/core/src/console.zig | 2 +- engine/core/src/core.zig | 86 +++++++++-- engine/core/src/ecs.zig | 2 +- engine/core/src/engine.zig | 53 ++++--- engine/core/src/engineObject.zig | 8 +- engine/core/src/extern/externModule.zig | 142 ++++++++++++++---- engine/core/src/inputs/inputStack.zig | 2 +- engine/core/src/logging.zig | 2 +- engine/core/src/modules.zig | 9 +- engine/core/src/scene.zig | 2 +- engine/core/src/script_bindings.zig | 2 +- engine/core/tests/externalModule.zig | 20 +++ engine/core/tests/tests.zig | 22 ++- engine/imgui/src/imgui.zig | 4 +- engine/physics/src/physics.zig | 5 +- engine/platform/src/platform.zig | 4 +- engine/rend/shaders/postProc.frag.hlsl | 6 +- engine/rend/src/rend.zig | 5 +- engine/rend/src/sgpu/mesh-pool.zig | 5 +- engine/rend/src/sgpu/ssao.zig | 2 +- engine/ui/src/ui.zig | 6 +- extras/gameExtras/src/EngineTool.zig | 69 +++++++++ extras/gameExtras/src/FpCamera.zig | 2 - extras/gameExtras/src/gameExtras.zig | 1 + lib/p2/src/p2.zig | 18 ++- projects/content/bsp/testmap.map | 108 +++++++------ projects/sampleGame/externGame/externGame.zig | 6 +- projects/sampleGame/main.zig | 46 ++++-- 34 files changed, 543 insertions(+), 187 deletions(-) create mode 100644 engine/core/tests/externalModule.zig create mode 100644 extras/gameExtras/src/EngineTool.zig diff --git a/.gitignore b/.gitignore index 39032eb..699b498 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,10 @@ zig-out/ *Saved/* +.modulecache/ +*modulecache* +.modulecache/** +*.modulecache/** *zig-cache* *zig-out* .vscode/ diff --git a/engine/assets/src/assets.zig b/engine/assets/src/assets.zig index e4e5a94..9664a5c 100644 --- a/engine/assets/src/assets.zig +++ b/engine/assets/src/assets.zig @@ -28,12 +28,13 @@ pub const Module = core.ModuleDescription{ var cooking: bool = false; -pub fn start_module(comptime spec: anytype, args: anytype, allocator: std.mem.Allocator) !void { +pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void { _ = args; - if (@hasField(@TypeOf(spec), "cooking")) { + //if (@hasField(@TypeOf(spec), "cooking")) { + if (spec.get("cooking")) |x| { core.engine_logs("Cooking Enabled"); - cooking = true; + cooking = x.boolean; try cook.startup(allocator); } diff --git a/engine/audio/src/audio.zig b/engine/audio/src/audio.zig index e6d3af5..6cd20d0 100644 --- a/engine/audio/src/audio.zig +++ b/engine/audio/src/audio.zig @@ -13,9 +13,9 @@ pub const sound_logs = soundEngine.sound_logs; pub var gSoundEngine: *NeonSoundEngine = undefined; pub var gSoundLoader: *soundEngine.SoundLoader = undefined; -pub fn start_module(comptime programSpec: anytype, args: anytype, allocator: std.mem.Allocator) !void { +pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void { _ = args; - _ = programSpec; + _ = spec; if (core.isUtility()) { return; } diff --git a/engine/backlog.zig b/engine/backlog.zig index 1280953..59eba82 100644 --- a/engine/backlog.zig +++ b/engine/backlog.zig @@ -35,7 +35,7 @@ pub fn getArgs() !NwArgs { var shutdownList: std.ArrayListUnmanaged(*const fn (std.mem.Allocator) void) = .{}; var shutdownModuleNames: std.ArrayListUnmanaged([]const u8) = .{}; -pub fn start_modules(comptime programSpec: anytype, maybeArgs: ?NwArgs, allocator: std.mem.Allocator) !void { +pub fn start_modules(spec: *core.SpecVariantMap, maybeArgs: ?NwArgs, allocator: std.mem.Allocator) !void { const Backlog = @This(); var z = core.tracy.ZoneN(@src(), "Starting all Modules"); @@ -44,14 +44,15 @@ pub fn start_modules(comptime programSpec: anytype, maybeArgs: ?NwArgs, allocato inline for (modulelist) |feature| { if (@hasDecl(Backlog, feature)) { const Struct = @field(Backlog, feature); - if (comptime core.isModuleEnabled(Struct.Module, programSpec)) { + if (core.isModuleEnabled(Struct.Module, spec)) { var z1 = core.tracy.ZoneN(@src(), @ptrCast("Initializing Module")); defer z1.End(); + core.tracy.Message(Struct.Module.name); if (maybeArgs) |args| { - try Struct.start_module(programSpec, args, allocator); + try Struct.start_module(spec, args, allocator); } else { - try Struct.start_module(programSpec, NwArgs{}, allocator); + try Struct.start_module(spec, NwArgs{}, allocator); } try shutdownList.append(allocator, Struct.shutdown_module); try shutdownModuleNames.append(allocator, feature); @@ -71,7 +72,7 @@ pub fn shutdown_modules(allocator: std.mem.Allocator) void { shutdownModuleNames.deinit(allocator); } -pub fn start_everything(comptime spec: anytype, allocator: std.mem.Allocator, maybeArgs: ?NwArgs) !void { +pub fn start_everything(spec: *core.SpecVariantMap, allocator: std.mem.Allocator, maybeArgs: ?NwArgs) !void { //if (maybeArgs) |args| { // //if (args.vulkanValidation) // // graphics.setStartupSettings("vulkanValidation", true); @@ -84,15 +85,11 @@ pub fn shutdown_everything(allocator: std.mem.Allocator) void { shutdown_modules(allocator); } -pub fn run_everything(comptime GameContext: type) !void { - var canTick: bool = false; - - if (@hasDecl(GameContext, "tick")) { - canTick = true; - } +pub fn run_everything_vtable(gameVtable: *const core.EngineObjectVTable) !void { core.engine_logs("creating Game context"); - _ = try core.createObject(GameContext, .{ .can_tick = canTick }); + //_ = try core.createObject(GameContext, .{}); + _ = try core.createObjectVTable(gameVtable, .{}); core.engine_logs("calling gEngine.run"); @@ -104,8 +101,26 @@ pub fn run_everything(comptime GameContext: type) !void { } } -pub fn initializeAndRunStandardProgram(comptime GameContext: type, comptime spec: anytype) !void { - const args = try getArgs(); +pub fn run_everything(gameVtable: *const core.EngineObjectVTable) !void { + core.engine_logs("creating Game context"); + + //_ = try core.createObject(GameContext, .{}); + _ = try core.createObjectVTable(gameVtable, .{}); + + core.engine_logs("calling gEngine.run"); + + try core.gEngine.run(); + + while (!core.gEngine.exitFinished()) { + const z = core.tracy.ZoneN(@src(), "shutdown poll"); + z.End(); + } +} + +pub const createSpecVariant = core.createSpecVariant; + +pub export fn initAndRun(vtable: *const core.EngineObjectVTable, spec: *core.SpecVariantMap) bool { + const args = getArgs() catch return false; var backingAllocator: std.mem.Allocator = std.heap.c_allocator; var gpa: std.heap.GeneralPurposeAllocator(.{ @@ -119,8 +134,10 @@ pub fn initializeAndRunStandardProgram(comptime GameContext: type, comptime spec } } - if (args.useGPA) { - backingAllocator = gpa.allocator(); + if (spec.get("useGPA")) |arg| { + if (arg.boolean == true) { + backingAllocator = gpa.allocator(); + } } const memory = core.MemoryTracker; @@ -130,12 +147,10 @@ pub fn initializeAndRunStandardProgram(comptime GameContext: type, comptime spec var tracker = memory.MTGet().?; const allocator = tracker.allocator(); - if (args.vulkanValidation) { - core.engine_logs("Using vulkan validation"); - } - - try start_everything(spec, allocator, args); + start_everything(spec, allocator, args) catch return false; defer shutdown_everything(allocator); - try run_everything(GameContext); + run_everything_vtable(vtable) catch return false; + + return true; } diff --git a/engine/core/build.zig b/engine/core/build.zig index 387f257..13631da 100644 --- a/engine/core/build.zig +++ b/engine/core/build.zig @@ -33,8 +33,23 @@ pub fn build(b: *std.Build) void { .root_source_file = b.path("tests/tests.zig"), }); + const sampleGameExtern = b.addSharedLibrary(.{ + .root_source_file = b.path("tests/externalModule.zig"), + .link_libc = true, + .optimize = optimize, + .target = target, + .name = "external", + }); + + const installExtern = b.addInstallArtifact(sampleGameExtern, .{ + .dest_dir = .{ .override = .{ .custom = "modules" } }, + }); + + b.getInstallStep().dependOn(&installExtern.step); + tests.root_module.addImport("core", mod); const runArtifact = b.addRunArtifact(tests); test_step.dependOn(&runArtifact.step); + runArtifact.step.dependOn(b.getInstallStep()); b.installArtifact(tests); } diff --git a/engine/core/src/configVars.zig b/engine/core/src/configVars.zig index ec315ec..8d4fe25 100644 --- a/engine/core/src/configVars.zig +++ b/engine/core/src/configVars.zig @@ -1,7 +1,7 @@ var gConfigsObject: *ConfigRegistry = undefined; pub const ConfigRegistry = struct { - pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); + pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.ConfigRegistry"); allocator: std.mem.Allocator, configMap: ?ConfigMap = null, diff --git a/engine/core/src/console.zig b/engine/core/src/console.zig index 08a4057..eeda556 100644 --- a/engine/core/src/console.zig +++ b/engine/core/src/console.zig @@ -6,7 +6,7 @@ pub const ConsoleCommand = struct { }; pub const Console = struct { - pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); + pub const NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.Console"); allocator: std.mem.Allocator, arena: std.heap.ArenaAllocator, diff --git a/engine/core/src/core.zig b/engine/core/src/core.zig index 105312d..c462900 100644 --- a/engine/core/src/core.zig +++ b/engine/core/src/core.zig @@ -25,6 +25,8 @@ pub const debugBox = debug_draw.debugBox; pub const debugLine = debug_draw.debugLine; pub const script_bindings = script.script_bindings; +pub const engineObject = @import("engineObject.zig"); + pub usingnamespace @import("misc.zig"); pub usingnamespace @import("logging.zig"); pub usingnamespace @import("engineTime.zig"); @@ -75,11 +77,19 @@ const PackerFS = packer.PackerFS; pub const StackCompactor = stacks.StackCompactor; +var staticsInitialized = false; +var gEngine: *Engine = undefined; var gPackerFS: *PackerFS = undefined; +var gScene: *SceneSystem = undefined; +var gModuleLoader: *ModuleLoader = undefined; + +var gIsUtility: bool = false; -pub var gScene: *SceneSystem = undefined; pub const Scene = scene.Scene; +pub const externModule = @import("extern/externModule.zig"); +pub const ModuleLoader = externModule.ModuleLoader; + pub const ecs = @import("ecs.zig"); pub usingnamespace ecs; @@ -97,8 +107,6 @@ pub const Module = ModuleDescription{ .enabledByDefault = true, }; -var gIsUtility: bool = false; - pub fn isUtility() bool { return gIsUtility; } @@ -110,10 +118,14 @@ pub fn checkArgBool(args: anytype, comptime field: []const u8) bool { return false; } -pub fn start_module(comptime programSpec: anytype, args: anytype, allocator: std.mem.Allocator) !void { - if (@hasField(@TypeOf(programSpec), "utility")) { - logs("utility mode - no gui"); - gIsUtility = true; +pub fn start_module(map: *SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void { + staticsInitialized = true; + + if (map.get("utility")) |x| { + if (x.boolean == true) { + logs("utility mode - no gui"); + gIsUtility = true; + } } var fatDump: bool = false; @@ -129,16 +141,22 @@ pub fn start_module(comptime programSpec: anytype, args: anytype, allocator: std gPackerFS = try PackerFS.init(allocator, .{}); // load configs. - const name = if (@hasField(@TypeOf(programSpec), "configName")) programSpec.configName else programSpec.name; + //const name = if (@hasField(@TypeOf(programSpec), "configName")) programSpec.configName else programSpec.name; + var name = map.get("name").?.string; - logging.engine_logs("loading configs with name" ++ name); + if (map.get("configName")) |x| { + name = x.string; + } gEngine = try allocator.create(Engine); gEngine.* = try Engine.init(allocator); - + gModuleLoader = try createObject(ModuleLoader, .{}); try console.start(); - try configVars.setupConfigs(name ++ "Engine.ini"); + const engineName = try std.fmt.allocPrint(allocator, "{s}Engine.ini", .{name}); + defer allocator.free(engineName); + + try configVars.setupConfigs(engineName); if (@hasField(@TypeOf(args), "unitTest") and args.unitTest) {} else { try logging.setupLogging(gEngine); @@ -179,12 +197,14 @@ pub fn dispatchJob(capture: anytype) !void { try gEngine.jobManager.newJob(capture); } -pub var gEngine: *Engine = undefined; - pub fn createObject(comptime T: type, params: engine.NeonObjectParams) !*T { return gEngine.createObject(T, params); } +pub fn createObjectVTable(vtable: *const engineObject.EngineObjectVTable, params: engine.NeonObjectParams) !*anyopaque { + return gEngine.createObjectVTable(vtable, params); +} + pub fn registerRendererSetup(ctx: *anyopaque, setup: engine.SetupFuncFn) void { gEngine.rendererCtx = ctx; gEngine.rendererSetupFunc = setup; @@ -252,3 +272,43 @@ pub const loopDelay = engine.loopDelay; pub const getConfigVar = configVars.getConfigVar; pub const configVar = configVars.configVar; + +pub const SpecVariantMap = std.StringHashMap(SpecVariant); + +pub const SpecVariant = union(enum(u8)) { + boolean: bool, + string: []const u8, +}; + +pub fn createSpecVariant(comptime spec: anytype, allocator: std.mem.Allocator) !SpecVariantMap { + var variantMap = std.StringHashMap(SpecVariant).init(allocator); + + inline for (@typeInfo(@TypeOf(spec)).@"struct".fields) |s| { + switch (@typeInfo(s.type)) { + .pointer => { + try variantMap.put(s.name, .{ .string = @field(spec, s.name) }); + }, + .bool => { + try variantMap.put(s.name, .{ .boolean = @field(spec, s.name) }); + }, + else => {}, + } + } + + return variantMap; +} + +pub fn getEngineObject(comptime T: type) ?*T { + if (T.NeonObjectTable.singletonName) |name| { + if (getEngine().engineObjectsByName.get(name)) |ref| { + return @ptrCast(@alignCast(ref.ptr)); + } + } + return null; +} + +pub fn loadModule(moduleName: []const u8, watch: bool) !void { + if (watch == false) unreachable; // not implemented + + try gModuleLoader.addModule(moduleName); +} diff --git a/engine/core/src/ecs.zig b/engine/core/src/ecs.zig index c8c7782..edf2066 100644 --- a/engine/core/src/ecs.zig +++ b/engine/core/src/ecs.zig @@ -193,7 +193,7 @@ pub const EcsRegistry = struct { containerNames: std.ArrayListUnmanaged(core.Name) = .{}, containersByName: std.AutoHashMapUnmanaged(u32, u32) = .{}, - pub const NeonObjectTable = core.EngineObjectVTable.from(@This()); + pub const NeonObjectTable = core.EngineObjectVTable.from(@This(), "core.EcsRegistry"); pub fn init(allocator: std.mem.Allocator) !*@This() { const self = try allocator.create(@This()); diff --git a/engine/core/src/engine.zig b/engine/core/src/engine.zig index 42efa04..d9a3be0 100644 --- a/engine/core/src/engine.zig +++ b/engine/core/src/engine.zig @@ -42,6 +42,7 @@ pub const Engine = struct { createObjectLock: bool = false, // better name for these engineObject objects is actually 'engine object' + engineObjectLUF: u64 = 0, engineObjects: ArrayListUnmanaged(EngineObjectRef), eventors: ArrayListUnmanaged(EngineObjectRef), exitListeners: ArrayListUnmanaged(EngineObjectRef), @@ -56,6 +57,9 @@ pub const Engine = struct { destroyListSimple: ArrayListUnmanaged(EngineObjectRef) = .{}, destroyListCore: ArrayListUnmanaged(EngineObjectRef) = .{}, + // if an engine object is created with a "singletonName" it will be added here. + engineObjectsByName: std.StringHashMapUnmanaged(EngineObjectRef) = .{}, + prepares: ArrayListUnmanaged(EngineObjectRef) = .{}, lastEngineTime: f64, @@ -93,7 +97,7 @@ pub const Engine = struct { .lastEngineTime = 0.0, .jobManager = try JobManager.create(allocator), .eventors = .{}, - .frameNumber = 0, + .frameNumber = 1, .exitListeners = .{}, .nfdRuntime = try nfd.NFDRuntime.create(allocator, .{}), .delegates = EngineDelegates.init(allocator), @@ -109,6 +113,8 @@ pub const Engine = struct { core.engine_logs("shutting down job Manager"); self.jobManager.destroy(); + self.engineObjectsByName.deinit(self.allocator); + if (self.destroyListCore.items.len > 0) { var i: i32 = @intCast(self.destroyListCore.items.len - 1); while (i >= 0) : (i -= 1) { @@ -140,16 +146,22 @@ pub const Engine = struct { self.allocator.destroy(self); } - // creates an engine object using the engine's allocator. pub fn createObject(self: *@This(), comptime T: type, params: NeonObjectParams) !*T { + const rv = try self.createObjectVTable(&T.NeonObjectTable, params); + + return @ptrCast(@alignCast(rv)); + } + + // creates an engine object using the engine's allocator. + pub fn createObjectVTable(self: *@This(), vtable: *const core.EngineObjectVTable, params: NeonObjectParams) !*anyopaque { if (self.createObjectLock) { core.engine_err("RECURSIVE OBJECT CREATION NOT ALLOWED", .{}); return error.BadInit; } + self.engineObjectLUF = self.frameNumber; // bump this every time an engine object mutation has happened self.createObjectLock = true; defer self.createObjectLock = false; const newIndex = self.engineObjects.items.len; - const vtable = &@field(T, "NeonObjectTable"); const newObjectPtr = try vtable.init_func(self.allocator); const newObjectRef = EngineObjectRef{ @@ -159,6 +171,10 @@ pub const Engine = struct { try self.engineObjects.append(self.allocator, newObjectRef); + if (vtable.singletonName) |singletonName| { + try self.engineObjectsByName.put(self.allocator, singletonName, newObjectRef); + } + if (params.isCore) { try self.destroyListCore.append(self.allocator, newObjectRef); } else { @@ -166,45 +182,48 @@ pub const Engine = struct { } if (params.can_tick) |t| { - if (t and !@hasDecl(T, "tick")) { - return error.RequestedTickNotAvailable; - } - if (t) { - try self.tickables.append(self.allocator, newIndex); + if (vtable.tick_func != null) { + try self.tickables.append(self.allocator, newIndex); + } } } else { - if (@hasDecl(T, "tick")) { + if (vtable.tick_func != null) { try self.tickables.append(self.allocator, newIndex); } } - if (@hasDecl(T, "engineDraw")) { + //if (@hasDecl(T, "engineDraw")) { + if (vtable.engineDraw_func != null) { try self.renderers.append(self.allocator, newObjectRef); } - if (@hasDecl(T, "prepare")) { + if (vtable.prepare_func != null) { try self.prepares.append(self.allocator, newObjectRef); } - if (@hasDecl(T, "preTick")) { + //if (@hasDecl(T, "preTick")) { + if (vtable.preTick_func != null) { try self.preTickables.append(self.allocator, newObjectRef); } - if (@hasDecl(T, "processEvents")) { + //if (@hasDecl(T, "processEvents")) { + if (vtable.processEvents != null) { try self.eventors.append(self.allocator, newObjectRef); // } - if (@hasDecl(T, "onExitSignal")) { - try core.assert(@hasDecl(T, "readyToExit")); + //if (@hasDecl(T, "onExitSignal")) { + if (vtable.exitSignal_func != null) { + try core.assert(vtable.readyToExit_func != null); //@hasDecl(T, "readyToExit")); try self.exitListeners.append(self.allocator, newObjectRef); // } - if (@hasDecl(T, "postInit")) { + //if (@hasDecl(T, "postInit")) { + if (vtable.postInit_func != null) { try vtable.postInit_func.?(newObjectPtr); } - return @as(*T, @ptrCast(@alignCast(newObjectPtr))); + return newObjectPtr; //@as(*T, @ptrCast(@alignCast(newObjectPtr))); } pub fn tick(self: *@This()) !void { diff --git a/engine/core/src/engineObject.zig b/engine/core/src/engineObject.zig index c095a63..5bb8ee2 100644 --- a/engine/core/src/engineObject.zig +++ b/engine/core/src/engineObject.zig @@ -40,6 +40,8 @@ pub const EngineObjectVTable = struct { typeSize: usize, typeAlign: usize, + singletonName: ?[]const u8 = null, + init_func: *const fn (std.mem.Allocator) EngineDataEventError!*anyopaque, tick_func: ?*const fn (*anyopaque, f64) void = null, engineDraw_func: ?*const fn (*anyopaque, f64) void = null, @@ -52,7 +54,7 @@ pub const EngineObjectVTable = struct { prepare_func: ?*const fn (*anyopaque) EngineDataEventError!void = null, - pub fn from(comptime TargetType: type) EngineObjectVTable { + pub fn from(comptime TargetType: type, comptime engineObjectName: ?[]const u8) EngineObjectVTable { var self = EngineObjectVTable{ .typeName = @typeName(TargetType), .typeSize = @sizeOf(TargetType), @@ -60,6 +62,10 @@ pub const EngineObjectVTable = struct { .init_func = undefined, }; + if (engineObjectName) |eon| { + self.singletonName = eon; + } + if (@hasDecl(TargetType, "init")) { const wrappedInit = struct { const funcFind: @TypeOf(@field(TargetType, "init")) = @field(TargetType, "init"); diff --git a/engine/core/src/extern/externModule.zig b/engine/core/src/extern/externModule.zig index 2ca7f54..ecc011d 100644 --- a/engine/core/src/extern/externModule.zig +++ b/engine/core/src/extern/externModule.zig @@ -1,64 +1,146 @@ // modules for managing loading dynamic libraries // -// i want hot swapping -// -// 1. add a folder to the watch list -pub const FileWatchEntry = struct { - path: []const u8, - stamp: i128 = 0, - cbCtx: ?*anyopaque, +const ModuleInterface = struct { + startup: *const fn (*anyopaque, ?*anyopaque) callconv(.C) bool = undefined, + shutdown: *const fn () callconv(.C) void = undefined, +}; - loadCallback: *const fn (*@This(), ?*anyopaque) void, +pub const LoadedModule = struct { + baseModulePath: []const u8, + moduleName: []const u8, + stagedPaths: std.ArrayListUnmanaged([]u8) = .{}, + loaded: std.ArrayListUnmanaged(ModuleInterface) = .{}, + activePath: ?[]const u8 = null, + stagingCount: u32 = 0, + lastLoad: i64 = 0, + lastModification: i64 = 0, - // staging path is under .cache/modules// - pub fn copyToStaging(self: *@This()) !void { - const fileName = p2. - const dir = try std.fs.cwd().makePath(); - std.fs.cwd().copyFile(self.path, dir, "", options: CopyFileOptions) + startOnLoad: bool = true, + started: bool = false, + + pub fn getInterface(self: @This()) ?ModuleInterface { + return self.loaded.getLastOrNull(); } - pub fn checkUpdateTime(self: *@This()) bool { - const stat = std.fs.cwd().statFile(self.path) catch false; - if (stat.mtime != self.stamp) { - self.stamp = stat.mtime; + pub fn stageModule(self: *@This(), allocator: std.mem.Allocator) !void { + //const stagingDirectory = ".modulecache//0/"; + const stagingDirectoryPath = try std.fmt.allocPrint(allocator, ".modulecache/{s}/{d}", .{ + self.moduleName, + self.stagedPaths.items.len, + }); + defer allocator.free(stagingDirectoryPath); + + try std.fs.cwd().makePath(stagingDirectoryPath); + + const stagedPath = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ + stagingDirectoryPath, + try p2.sharedLibNameAlloc(allocator, self.moduleName), + }); + + try std.fs.cwd().copyFile(self.baseModulePath, std.fs.cwd(), stagedPath, .{}); + + self.stagedPaths.append(allocator, stagedPath) catch unreachable; + } + + pub fn loadStagedModule(self: *@This(), allocator: std.mem.Allocator) !void { + const stagedPath = self.stagedPaths.getLast(); + var lib = try std.DynLib.open(stagedPath); + var mod = ModuleInterface{}; + mod.startup = lib.lookup(@TypeOf(mod.startup), "startup") orelse return error.BadModule; + mod.shutdown = lib.lookup(@TypeOf(mod.shutdown), "shutdown") orelse return error.BadModule; + + try self.loaded.append(allocator, mod); + } + + // logic for testing if we should stage and load + // + // 1. modification check time > last load time + // 2. current time > modification check time + debounce + pub fn maybeStageAndLoad(self: *@This(), allocator: std.mem.Allocator) !bool { + core.engine_log("[tick]:", .{}); + if (self.lastModification > self.lastLoad) { + const currentTime = std.time.microTimestamp(); + + // give 100ms for debouncing + if (currentTime > self.lastModification + 50_000) { + self.lastLoad = currentTime; + core.engine_log("[ModuleLoader] loading module: ", .{}); + try self.stageModule(allocator); + try self.loadStagedModule(allocator); + return true; + } } + + return false; } }; pub const ModuleLoader = struct { backingAllocator: std.mem.Allocator, arena: std.heap.ArenaAllocator, - allocator: std.mem.Allocator = undefined, - - files: std.ArrayListUnmanaged(FileWatchEntry) = .{}, + loadedModules: std.ArrayListUnmanaged(LoadedModule) = .{}, + pub const NeonObjectTable = core.EngineObjectVTable.from(@This(), "core.ModuleLoader"); pub fn create(allocator: std.mem.Allocator) !*@This() { const self = try allocator.create(@This()); self.* = .{ .backingAllocator = allocator, - .arena = try std.heap.ArenaAllocator.init(allocator), + .arena = std.heap.ArenaAllocator.init(allocator), }; - self.allocator = self.arena.allocator(); - return self; } - pub fn destroy(self: *@This()) void { - self.arena.deinit(); - self.backingAllocator.destroy(self); + pub fn addModule(self: *@This(), moduleName: []const u8) !void { + // modules are always looked for under zig-out/modules + core.engine_log("[ModuleLoader]: adding module to watch '{s}'", .{moduleName}); + const libFileName = try p2.sharedLibNameAlloc(self.arena.allocator(), moduleName); + const loaded = LoadedModule{ + .baseModulePath = try std.fmt.allocPrint(self.arena.allocator(), "zig-out/modules/{s}", .{libFileName}), + .moduleName = moduleName, + .lastModification = std.time.microTimestamp(), + }; + + try self.loadedModules.append(self.arena.allocator(), loaded); } - pub fn checkForFileUpdates(self: *@This()) void { - for (self.files.items) |*f| { - if (f.checkTime()) { - f.loadCallback(f.cbCtx); + pub fn tick(self: *@This(), dt: f64) void { + _ = dt; + for (self.loadedModules.items) |*loaded| { + const didLoad = loaded.maybeStageAndLoad(self.arena.allocator()) catch |err| { + core.engine_log("unable to load module error: {any}", .{err}); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + continue; + }; + + if (didLoad) { + const i = loaded.getInterface(); + + if (i) |interface| { + if (loaded.startOnLoad) { + if (!loaded.started) { + var a = self.backingAllocator; + if (interface.startup(&a, null)) { + core.engine_log("[ModuleLoader] module startup done", .{}); + } + } + } + } } } } + + pub fn destroy(self: *@This()) void { + // std.fs.cwd().deleteTree(".modulecache") catch {}; + self.arena.deinit(); + self.backingAllocator.destroy(self); + } }; const std = @import("std"); +const core = @import("../core.zig"); const p2 = @import("p2"); diff --git a/engine/core/src/inputs/inputStack.zig b/engine/core/src/inputs/inputStack.zig index 8a977e4..59811e0 100644 --- a/engine/core/src/inputs/inputStack.zig +++ b/engine/core/src/inputs/inputStack.zig @@ -565,7 +565,7 @@ pub const InputStack = struct { keysDown: std.AutoHashMapUnmanaged(Key, bool) = .{}, - pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); + pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.InputStack"); pub fn init(allocator: std.mem.Allocator) !*@This() { const self = try allocator.create(@This()); diff --git a/engine/core/src/logging.zig b/engine/core/src/logging.zig index 5395d95..4d55b86 100644 --- a/engine/core/src/logging.zig +++ b/engine/core/src/logging.zig @@ -157,7 +157,7 @@ pub const FileLog = struct { }; pub const LoggerSys = struct { - pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); + pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.LoggerSys"); writeOutBuffer: std.ArrayList(u8), flushBuffer: std.ArrayList(u8), diff --git a/engine/core/src/modules.zig b/engine/core/src/modules.zig index e779df5..c72e295 100644 --- a/engine/core/src/modules.zig +++ b/engine/core/src/modules.zig @@ -1,6 +1,7 @@ // the module startup system. const std = @import("std"); +const core = @import("core.zig"); // a series of comptime functions for letting you select which features are compiled and brought // into the engine. @@ -10,11 +11,9 @@ pub const ModuleDescription = struct { enabledByDefault: bool, }; -pub fn isModuleEnabled(comptime module: ModuleDescription, comptime buildDescription: anytype) bool { - if (!@hasField(@TypeOf(buildDescription), "enabledModules")) { - return module.enabledByDefault; - } else if (@hasField(@TypeOf(buildDescription.enabledModules), module.name)) { - return @field(buildDescription.enabledModules, module.name); +pub fn isModuleEnabled(comptime module: ModuleDescription, spec: *core.SpecVariantMap) bool { + if (spec.get(module.name)) |x| { + return x.boolean; } else { return module.enabledByDefault; } diff --git a/engine/core/src/scene.zig b/engine/core/src/scene.zig index 451144f..e98463f 100644 --- a/engine/core/src/scene.zig +++ b/engine/core/src/scene.zig @@ -275,7 +275,7 @@ fn childAllocator() std.mem.Allocator { } pub const SceneSystem = struct { - pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); + pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.SceneSystem"); allocator: std.mem.Allocator, dynamicObjects: ArrayListUnmanaged(core.ObjectHandle) = .{}, diff --git a/engine/core/src/script_bindings.zig b/engine/core/src/script_bindings.zig index 7507303..42cf497 100644 --- a/engine/core/src/script_bindings.zig +++ b/engine/core/src/script_bindings.zig @@ -28,7 +28,7 @@ pub fn registerTick(l: lua.LuaState) i32 { pub const ScriptTicks = struct { allocator: std.mem.Allocator, - pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); + pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.ScriptTicks"); pub fn init(allocator: std.mem.Allocator) !*@This() { const self = try allocator.create(@This()); diff --git a/engine/core/tests/externalModule.zig b/engine/core/tests/externalModule.zig new file mode 100644 index 0000000..ca53f5b --- /dev/null +++ b/engine/core/tests/externalModule.zig @@ -0,0 +1,20 @@ +var gAllocator: std.mem.Allocator = undefined; + +pub export fn startup(p_allocator: *anyopaque, args: ?*anyopaque) bool { + _ = args; + + gAllocator = @as(*std.mem.Allocator, @ptrCast(@alignCast(p_allocator))).*; + + const allocator = gAllocator; + + // do some test allocations and let it leak + const t = std.fmt.allocPrint(gAllocator, "Lmao 2 nova {d}", .{2}) catch unreachable; + std.debug.print("external module started allocated string: {s}\n", .{t}); + allocator.free(t); + + return true; +} + +pub export fn shutdown() void {} + +const std = @import("std"); diff --git a/engine/core/tests/tests.zig b/engine/core/tests/tests.zig index 5fd3924..1635a85 100644 --- a/engine/core/tests/tests.zig +++ b/engine/core/tests/tests.zig @@ -15,7 +15,11 @@ test "simple systems setup for core" { std.debug.print("Starting up \n", .{}); engine_logs("systems starting"); - try core.start_module(.{ .name = "test" }, .{ .unitTest = true }, allocator); + + var map = try core.createSpecVariant(.{ .name = "test" }, allocator); + defer map.deinit(); + + try core.start_module(&map, .{ .unitTest = true }, allocator); defer core.shutdown_module(allocator); engine_logs("systems started, shutting down"); @@ -25,11 +29,27 @@ test "simple systems setup for core" { try test_consoleCommands(); try test_gameObjects(std.testing.allocator); + try test_loadModules(); + + try test_objectLoaderRegistry(); // try generateRandomSamples(); try memory.dumpTimeline("test-core-timeline.txt"); } +fn test_objectLoaderRegistry() !void { + const inputStack = core.getEngineObject(core.inputs.InputStack); + try core.assert(inputStack == core.getInputStack()); +} + +pub fn test_loadModules() !void { + _ = try core.loadModule("external", true); + const moduleLoader = core.getEngineObject(core.ModuleLoader).?; + + std.time.sleep(1e9 * 0.1); + moduleLoader.tick(0.1); +} + fn generateRandomSamples() !void { var prng = std.Random.DefaultPrng.init(blk: { var seed: u64 = undefined; diff --git a/engine/imgui/src/imgui.zig b/engine/imgui/src/imgui.zig index a8a0330..ec0633b 100644 --- a/engine/imgui/src/imgui.zig +++ b/engine/imgui/src/imgui.zig @@ -11,10 +11,10 @@ pub const Module: core.ModuleDescription = .{ var gImgui: *Impl = undefined; -pub fn start_module(comptime programSpec: anytype, args: anytype, allocator: std.mem.Allocator) !void { +pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void { _ = allocator; _ = args; - _ = programSpec; + _ = spec; // gImgui = try rend.createRendererObject(Impl); // try gImgui.setup(); diff --git a/engine/physics/src/physics.zig b/engine/physics/src/physics.zig index 6c06421..aa23a9c 100644 --- a/engine/physics/src/physics.zig +++ b/engine/physics/src/physics.zig @@ -74,9 +74,10 @@ pub fn addShape(name: []const u8, settings: ShapeSettings) !void { try gPhysicsRuntime.createShape(&n, settings); } -pub fn start_module(comptime programSpec: anytype, args: anytype, allocator: std.mem.Allocator) !void { +pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void { _ = args; - _ = programSpec; + _ = spec; + try zphysics.init(allocator, .{}); gPhysicsRuntime = try core.createObject(runtime.PhysicsRuntime, .{ .can_tick = true }); } diff --git a/engine/platform/src/platform.zig b/engine/platform/src/platform.zig index 164e413..7ecd4e1 100644 --- a/engine/platform/src/platform.zig +++ b/engine/platform/src/platform.zig @@ -38,9 +38,9 @@ pub fn setImguiVisible(visible: bool) void { gPlatformInstance.imguiVisible = visible; } -pub fn start_module(comptime programSpec: anytype, args: anytype, allocator: std.mem.Allocator) !void { +pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void { _ = args; - _ = programSpec; + _ = spec; if (core.isUtility()) { return; } diff --git a/engine/rend/shaders/postProc.frag.hlsl b/engine/rend/shaders/postProc.frag.hlsl index e8c0680..a0db890 100644 --- a/engine/rend/shaders/postProc.frag.hlsl +++ b/engine/rend/shaders/postProc.frag.hlsl @@ -135,10 +135,10 @@ float4 main(float2 UV : TEXCOORD0) : SV_Target0 float ssao = blurSSAO(uv); c = c * ssao; - // float4 x = SsaoTexture.Sample(Sampler2, uv); - // c = x; + //float4 x = SsaoTexture.Sample(Sampler2, uv); + //c = x; - // c = ssao.xyz; + // c = float3(ssao, ssao, ssao); c.x *= 1.0 + 0.000001 * EmissiveTexture.Sample(Sampler1, uv).x; c.x *= 1.0 + 0.000001 * ColorTexture.Sample(Sampler0, uv).x; diff --git a/engine/rend/src/rend.zig b/engine/rend/src/rend.zig index 21b5d19..0012715 100644 --- a/engine/rend/src/rend.zig +++ b/engine/rend/src/rend.zig @@ -49,9 +49,10 @@ pub const Module: core.ModuleDescription = .{ .enabledByDefault = true, }; -pub fn start_module(comptime programSpec: anytype, args: anytype, allocator: std.mem.Allocator) !void { +pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void { _ = args; - _ = programSpec; + _ = spec; + rendAllocator = allocator; try renderer.createInstance(); try renderer.start(); diff --git a/engine/rend/src/sgpu/mesh-pool.zig b/engine/rend/src/sgpu/mesh-pool.zig index 665abfb..624e8b9 100644 --- a/engine/rend/src/sgpu/mesh-pool.zig +++ b/engine/rend/src/sgpu/mesh-pool.zig @@ -55,8 +55,9 @@ pub const MeshPool = struct { var iter = self.invalidations.iterator(); while (iter.next()) |n| { const invalidate = n.value_ptr; - self.indexSpans.removeSpan(invalidate.index); - self.vertexSpans.removeSpan(invalidate.vertex); + _ = invalidate; + //self.indexSpans.removeSpan(invalidate.index); + //self.vertexSpans.removeSpan(invalidate.vertex); } self.invalidations.clearRetainingCapacity(); diff --git a/engine/rend/src/sgpu/ssao.zig b/engine/rend/src/sgpu/ssao.zig index 0930584..234ebfc 100644 --- a/engine/rend/src/sgpu/ssao.zig +++ b/engine/rend/src/sgpu/ssao.zig @@ -12,7 +12,7 @@ ssaoTexture: *gpu.GPUTexture = undefined, noiseTexture: *gpu.GPUTexture = undefined, noiseSampler: *gpu.GPUSampler = undefined, -radius: f32 = 0.5, +radius: f32 = 0.8, bias: f32 = 0.05, numSamples: i32 = 64, enable: bool = true, diff --git a/engine/ui/src/ui.zig b/engine/ui/src/ui.zig index e9bf207..6c7ebc7 100644 --- a/engine/ui/src/ui.zig +++ b/engine/ui/src/ui.zig @@ -14,14 +14,12 @@ pub const PapyrusIntegration = @import("sgpu/papyrusSgpu.zig"); var gIntegration: *PapyrusIntegration = undefined; -pub fn start_module(comptime programSpec: anytype, args: anytype, allocator: std.mem.Allocator) !void { +pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void { _ = args; - _ = programSpec; + _ = spec; gIntegration = try PapyrusIntegration.create(allocator); try gIntegration.setup(); - // gImgui = try rend.createRendererObject(Impl); - // try gImgui.setup(); } // gets the main context under gIntegration diff --git a/extras/gameExtras/src/EngineTool.zig b/extras/gameExtras/src/EngineTool.zig new file mode 100644 index 0000000..2ee3743 --- /dev/null +++ b/extras/gameExtras/src/EngineTool.zig @@ -0,0 +1,69 @@ +allocator: std.mem.Allocator, +windowOpen: bool = true, + +lastUpdateFrame: u64 = 0, +arena: std.heap.ArenaAllocator, +strings: std.ArrayListUnmanaged([]u8) = .{}, + +pub fn create(allocator: std.mem.Allocator) !*@This() { + const self = try allocator.create(@This()); + + self.* = .{ + .allocator = allocator, + .arena = std.heap.ArenaAllocator.init(allocator), + }; + + 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, + x.vtable.typeName, + @intFromPtr(x.ptr), + x.vtable.typeSize, + }); + + try self.strings.append(alloc, newString); + } + } +} + +pub fn tick(self: *@This()) void { + if (self.windowOpen) { + if (ig.begin("EngineTool", &self.windowOpen, .{})) { + self.maybeUpdate() catch { + ig.textSlice("Unable to update engine tools list"); + return; + }; + for (self.strings.items) |slice| { + ig.textSlice(slice); + } + } + 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; diff --git a/extras/gameExtras/src/FpCamera.zig b/extras/gameExtras/src/FpCamera.zig index ec41d32..3126627 100644 --- a/extras/gameExtras/src/FpCamera.zig +++ b/extras/gameExtras/src/FpCamera.zig @@ -1,6 +1,4 @@ // generic first person camera, -// -// allocator: std.mem.Allocator, camera: core.Entity = undefined, diff --git a/extras/gameExtras/src/gameExtras.zig b/extras/gameExtras/src/gameExtras.zig index 643d113..14ec68b 100644 --- a/extras/gameExtras/src/gameExtras.zig +++ b/extras/gameExtras/src/gameExtras.zig @@ -2,3 +2,4 @@ pub const FpCamera = @import("FpCamera.zig"); pub const inputDebugger = @import("inputDebugger.zig"); pub const ObjectSpawner = @import("objectSpawner.zig"); pub const RendererDebug = @import("RendererDebug.zig"); +pub const EngineTool = @import("EngineTool.zig"); diff --git a/lib/p2/src/p2.zig b/lib/p2/src/p2.zig index 79f187c..e2385bf 100644 --- a/lib/p2/src/p2.zig +++ b/lib/p2/src/p2.zig @@ -73,16 +73,24 @@ pub const Span = spans.Span; pub const shell = @import("utils/shell.zig"); -pub fn sharedLibName(comptime s: []const u8) []const u8 { +pub fn sharedLibNameAlloc(allocator: std.mem.Allocator, s: []const u8) ![]u8 { const os_tag = @import("builtin").os.tag; + + var suffix: []const u8 = "dll"; + var prefix: []const u8 = ""; if (os_tag == .linux) { - return s ++ ".so"; + prefix = "lib"; + suffix = "so"; } else if (os_tag == .macos) { - return s ++ ".dynlib"; - } else { - return s ++ ".dll"; + suffix = "dylib"; + prefix = "lib"; } + + const path = try std.fmt.allocPrint(allocator, "{s}{s}.{s}", .{ prefix, s, suffix }); + + return path; } + comptime { std.testing.refAllDecls(utils); std.testing.refAllDecls(static_structures); diff --git a/projects/content/bsp/testmap.map b/projects/content/bsp/testmap.map index 88babca..1b75b2f 100644 --- a/projects/content/bsp/testmap.map +++ b/projects/content/bsp/testmap.map @@ -509,15 +509,6 @@ } // brush 56 { -( 168 640 16 ) ( 168 641 16 ) ( 168 640 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 -( 168 648 16 ) ( 168 648 17 ) ( 169 648 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 -( 168 640 16 ) ( 169 640 16 ) ( 168 641 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 -( 536 656 272 ) ( 536 657 272 ) ( 537 656 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 -( 536 656 24 ) ( 537 656 24 ) ( 536 656 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 -( 536 656 24 ) ( 536 656 25 ) ( 536 657 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 -} -// brush 57 -{ ( 496 656 176 ) ( 496 657 176 ) ( 496 656 177 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 ( 496 656 176 ) ( 496 656 177 ) ( 497 656 176 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 ( 496 656 16 ) ( 497 656 16 ) ( 496 657 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 @@ -525,7 +516,7 @@ ( 504 728 184 ) ( 505 728 184 ) ( 504 728 185 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 ( 504 664 184 ) ( 504 664 185 ) ( 504 665 184 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 } -// brush 58 +// brush 57 { ( 176 688 128 ) ( 176 689 128 ) ( 176 688 129 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 176 656 128 ) ( 176 656 129 ) ( 177 656 128 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -534,7 +525,7 @@ ( 240 944 136 ) ( 241 944 136 ) ( 240 944 137 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 264 872 136 ) ( 264 872 137 ) ( 264 873 136 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 59 +// brush 58 { ( 260 860 136 ) ( 260 861 136 ) ( 260 860 137 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 260 704 136 ) ( 260 704 137 ) ( 261 704 136 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -543,7 +534,7 @@ ( 264 944 140 ) ( 265 944 140 ) ( 264 944 141 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 264 992 140 ) ( 264 992 141 ) ( 264 993 140 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 60 +// brush 59 { ( 240 1040 192 ) ( 240 1048 184 ) ( 240 1048 312 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 ( 200 1028 204 ) ( 204 1028 332 ) ( 204 1028 204 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 @@ -552,7 +543,7 @@ ( 192 1060 172 ) ( 212 1060 172 ) ( 212 1060 300 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 ( 496 1120 136 ) ( 496 1120 137 ) ( 496 1121 136 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 } -// brush 61 +// brush 60 { ( 176 960 128 ) ( 176 961 128 ) ( 176 960 129 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 ( 192 1060 172 ) ( 212 1060 300 ) ( 212 1060 172 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 @@ -562,7 +553,7 @@ ( 296 1120 136 ) ( 297 1120 136 ) ( 296 1120 137 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 ( 236 1060 172 ) ( 236 1060 176 ) ( 236 1188 176 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 } -// brush 62 +// brush 61 { ( 240 1024 208 ) ( 240 1020 340 ) ( 240 1020 212 ) mapping_defaults/ProtoBrightBlue -223.99994 -48.000015 0 1 1 ( 168 1088 144 ) ( 168 1080 152 ) ( 296 1080 152 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 @@ -570,7 +561,7 @@ ( 200 1028 204 ) ( 204 1028 204 ) ( 204 1028 332 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 ( 496 1120 136 ) ( 496 1120 137 ) ( 496 1121 136 ) mapping_defaults/ProtoBrightBlue -223.99994 -48.000015 0 1 1 } -// brush 63 +// brush 62 { ( 176 960 128 ) ( 176 961 128 ) ( 176 960 129 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 ( 168 1088 144 ) ( 168 1080 152 ) ( 296 1080 152 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 @@ -578,7 +569,7 @@ ( 176 1020 212 ) ( 184 1020 212 ) ( 184 1020 340 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 ( 240 1024 208 ) ( 240 1020 212 ) ( 240 1020 340 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 } -// brush 64 +// brush 63 { ( 236 1060 172 ) ( 236 1188 176 ) ( 236 1060 176 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 ( 192 1060 172 ) ( 212 1060 300 ) ( 212 1060 172 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 @@ -588,7 +579,7 @@ ( 296 1120 136 ) ( 297 1120 136 ) ( 296 1120 137 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 ( 496 1120 136 ) ( 496 1120 137 ) ( 496 1121 136 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 } -// brush 65 +// brush 64 { ( 304 656 16 ) ( 292 656 8 ) ( 292 784 8 ) mapping_defaults/ProtoDark -80 224 0 1 1 ( 88 656 20 ) ( 88 656 21 ) ( 89 656 20 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -597,7 +588,7 @@ ( 160 656 -92 ) ( 172 656 -84 ) ( 172 784 -84 ) mapping_defaults/ProtoDark -80 224 0 1 1 ( 304 704 24 ) ( 304 704 25 ) ( 304 705 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 66 +// brush 65 { ( -108 656 -172 ) ( -108 657 -172 ) ( -108 656 -171 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 108 656 -172 ) ( 108 656 -171 ) ( 109 656 -172 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -606,7 +597,7 @@ ( 120 984 -168 ) ( 121 984 -168 ) ( 120 984 -167 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 320 700 -168 ) ( 320 700 -167 ) ( 320 701 -168 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 67 +// brush 66 { ( -112 984 -96 ) ( -112 985 -96 ) ( -112 984 -95 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( -96 984 -96 ) ( -96 984 -95 ) ( -95 984 -96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -615,7 +606,7 @@ ( -20 988 -92 ) ( -19 988 -92 ) ( -20 988 -91 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 320 988 -92 ) ( 320 988 -91 ) ( 320 989 -92 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 68 +// brush 67 { ( 316 956 -96 ) ( 316 957 -96 ) ( 316 956 -95 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 316 640 -96 ) ( 316 640 -95 ) ( 317 640 -96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -624,7 +615,7 @@ ( 320 992 -92 ) ( 321 992 -92 ) ( 320 992 -91 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 320 972 -92 ) ( 320 972 -91 ) ( 320 973 -92 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 69 +// brush 68 { ( -112 980 -96 ) ( -112 981 -96 ) ( -112 980 -95 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( -112 656 -96 ) ( -112 656 -95 ) ( -111 656 -96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -633,7 +624,7 @@ ( -108 984 -92 ) ( -107 984 -92 ) ( -108 984 -91 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( -108 984 -92 ) ( -108 984 -91 ) ( -108 985 -92 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 70 +// brush 69 { ( -168 700 4 ) ( -168 701 4 ) ( -168 700 5 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 160 656 4 ) ( 160 656 5 ) ( 161 656 4 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -642,7 +633,7 @@ ( 176 704 8 ) ( 177 704 8 ) ( 176 704 9 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 124 704 8 ) ( 124 704 9 ) ( 124 705 8 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 71 +// brush 70 { ( -112 652 -96 ) ( -112 653 -96 ) ( -112 652 -95 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( -112 652 -96 ) ( -112 652 -95 ) ( -111 652 -96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -651,7 +642,7 @@ ( 176 656 -92 ) ( 177 656 -92 ) ( 176 656 -91 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 320 656 -92 ) ( 320 656 -91 ) ( 320 657 -92 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 72 +// brush 71 { ( 264 656 16 ) ( 264 657 16 ) ( 264 656 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 276 704 120 ) ( 288 704 112 ) ( 288 832 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 @@ -660,7 +651,7 @@ ( 488 704 20 ) ( 489 704 20 ) ( 488 704 21 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 264 676 136 ) ( 276 804 128 ) ( 276 676 128 ) mapping_defaults/ProtoDark -80 224 0 1 1 } -// brush 73 +// brush 72 { ( 272 1200 16 ) ( 272 1201 16 ) ( 272 1200 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 272 1200 16 ) ( 272 1200 17 ) ( 273 1200 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -669,7 +660,7 @@ ( 280 1216 24 ) ( 281 1216 24 ) ( 280 1216 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 448 1232 24 ) ( 448 1232 25 ) ( 448 1233 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 74 +// brush 73 { ( 272 1200 16 ) ( 272 1201 16 ) ( 272 1200 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 272 1200 16 ) ( 272 1200 17 ) ( 273 1200 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -678,7 +669,7 @@ ( 280 1232 24 ) ( 281 1232 24 ) ( 280 1232 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 448 1232 24 ) ( 448 1232 25 ) ( 448 1233 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 75 +// brush 74 { ( 272 1216 28 ) ( 272 1217 28 ) ( 272 1216 29 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 272 1216 28 ) ( 272 1216 29 ) ( 273 1216 28 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -687,7 +678,7 @@ ( 448 1232 32 ) ( 449 1232 32 ) ( 448 1232 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 448 1236 32 ) ( 448 1236 33 ) ( 448 1237 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 76 +// brush 75 { ( 236 1172 120 ) ( 236 1173 120 ) ( 236 1172 121 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 228 1120 120 ) ( 228 1120 121 ) ( 229 1120 120 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -696,7 +687,7 @@ ( 240 1288 124 ) ( 241 1288 124 ) ( 240 1288 125 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 240 1284 124 ) ( 240 1284 125 ) ( 240 1285 124 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 77 +// brush 76 { ( 240 1284 128 ) ( 240 1285 128 ) ( 240 1284 129 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 240 1284 128 ) ( 240 1284 129 ) ( 241 1284 128 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -705,7 +696,7 @@ ( 452 1288 132 ) ( 453 1288 132 ) ( 452 1288 133 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 456 1288 132 ) ( 456 1288 133 ) ( 456 1289 132 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 78 +// brush 77 { ( 168 1120 176 ) ( 168 1121 176 ) ( 168 1120 177 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 244 1116 176 ) ( 244 1116 177 ) ( 245 1116 176 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -714,7 +705,7 @@ ( 348 1124 180 ) ( 349 1124 180 ) ( 348 1124 181 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 496 1124 180 ) ( 496 1124 181 ) ( 496 1125 180 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 79 +// brush 78 { ( 688 912 16 ) ( 688 913 16 ) ( 688 912 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 688 912 16 ) ( 688 912 17 ) ( 689 912 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -723,7 +714,7 @@ ( 704 1136 32 ) ( 705 1136 32 ) ( 704 1136 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 704 1136 32 ) ( 704 1136 33 ) ( 704 1137 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 80 +// brush 79 { ( 592 1216 16 ) ( 592 1217 16 ) ( 592 1216 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 592 1216 16 ) ( 592 1216 17 ) ( 593 1216 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -732,7 +723,7 @@ ( 800 1232 32 ) ( 801 1232 32 ) ( 800 1232 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 800 1232 32 ) ( 800 1232 33 ) ( 800 1233 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 81 +// brush 80 { ( 1024 896 176 ) ( 1008 896 160 ) ( 1008 1024 160 ) mapping_defaults/ProtoDark -80 224 0 1 1 ( 832 896 16 ) ( 832 896 17 ) ( 833 896 16 ) mapping_defaults/ProtoDark -80 -47.999992 0 1 1 @@ -740,7 +731,7 @@ ( 1040 976 32 ) ( 1041 976 32 ) ( 1040 976 33 ) mapping_defaults/ProtoDark -80 -47.999992 0 1 1 ( 1072 944 32 ) ( 1072 944 33 ) ( 1072 945 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 82 +// brush 81 { ( 1072 896 48 ) ( 1072 897 48 ) ( 1072 896 49 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 1040 896 48 ) ( 1040 896 49 ) ( 1041 896 48 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -749,7 +740,7 @@ ( 1136 976 64 ) ( 1137 976 64 ) ( 1136 976 65 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 1136 976 64 ) ( 1136 976 65 ) ( 1136 977 64 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 83 +// brush 82 { ( 1056 976 112 ) ( 1056 976 96 ) ( 1056 1104 96 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 864 976 16 ) ( 864 976 17 ) ( 865 976 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -758,7 +749,7 @@ ( 1136 1056 32 ) ( 1137 1056 32 ) ( 1136 1056 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 1136 1056 32 ) ( 1136 1056 33 ) ( 1136 1057 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 84 +// brush 83 { ( 864 976 16 ) ( 864 977 16 ) ( 864 976 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 864 976 16 ) ( 864 976 17 ) ( 865 976 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -767,7 +758,7 @@ ( 1136 1056 32 ) ( 1137 1056 32 ) ( 1136 1056 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 960 976 112 ) ( 960 1104 96 ) ( 960 976 96 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 85 +// brush 84 { ( 864 976 16 ) ( 864 977 16 ) ( 864 976 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 864 976 16 ) ( 864 976 17 ) ( 865 976 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -776,7 +767,7 @@ ( 1136 1056 32 ) ( 1137 1056 32 ) ( 1136 1056 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 1056 976 112 ) ( 1056 1104 96 ) ( 1056 976 96 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 86 +// brush 85 { ( 1136 896 208 ) ( 1136 897 208 ) ( 1136 896 209 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 1136 896 208 ) ( 1136 896 209 ) ( 1137 896 208 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -785,7 +776,7 @@ ( 1152 1136 224 ) ( 1153 1136 224 ) ( 1152 1136 225 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 1200 928 224 ) ( 1200 928 225 ) ( 1200 929 224 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 87 +// brush 86 { ( 880 1056 208 ) ( 880 1057 208 ) ( 880 1056 209 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 1120 1056 208 ) ( 1120 1056 209 ) ( 1121 1056 208 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -794,7 +785,7 @@ ( 1136 1136 224 ) ( 1072 1136 240 ) ( 1072 1264 240 ) mapping_defaults/ProtoDark -80 224 0 1 1 ( 1136 1120 224 ) ( 1136 1120 225 ) ( 1136 1121 224 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 88 +// brush 87 { ( 784 1056 208 ) ( 784 1057 208 ) ( 784 1056 209 ) mapping_defaults/ProtoDark -224 -48 0 1 1 ( 784 1056 208 ) ( 784 1056 209 ) ( 785 1056 208 ) mapping_defaults/ProtoDark -80 -48 0 1 1 @@ -803,7 +794,7 @@ ( 864 1136 224 ) ( 865 1136 224 ) ( 864 1136 225 ) mapping_defaults/ProtoDark -80 -48 0 1 1 ( 880 1136 224 ) ( 880 1136 225 ) ( 880 1137 224 ) mapping_defaults/ProtoDark -224 -48 0 1 1 } -// brush 89 +// brush 88 { ( -32 640 16 ) ( -32 641 16 ) ( -32 640 17 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 ( -32 640 16 ) ( -32 640 17 ) ( -31 640 16 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 @@ -812,7 +803,7 @@ ( 16 784 32 ) ( 17 784 32 ) ( 16 784 33 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 ( 16 784 32 ) ( 16 784 33 ) ( 16 785 32 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 } -// brush 90 +// brush 89 { ( -48 864 16 ) ( -48 865 16 ) ( -48 864 17 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 ( -48 864 16 ) ( -48 864 17 ) ( -47 864 16 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 @@ -821,7 +812,7 @@ ( 16 1008 32 ) ( 17 1008 32 ) ( 16 1008 33 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 ( 16 1008 32 ) ( 16 1008 33 ) ( 16 1009 32 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 } -// brush 91 +// brush 90 { ( -224 496 16 ) ( -224 497 16 ) ( -224 496 17 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 ( -224 496 16 ) ( -224 496 17 ) ( -223 496 16 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 @@ -830,7 +821,7 @@ ( 32 544 32 ) ( 33 544 32 ) ( 32 544 33 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 ( 32 544 32 ) ( 32 544 33 ) ( 32 545 32 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 } -// brush 92 +// brush 91 { ( -160 528 144 ) ( -160 529 144 ) ( -160 528 145 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 ( -160 528 144 ) ( -160 528 145 ) ( -159 528 144 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 @@ -839,7 +830,7 @@ ( -32 992 160 ) ( -31 992 160 ) ( -32 992 161 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 ( -32 544 160 ) ( -32 544 161 ) ( -32 545 160 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 } -// brush 93 +// brush 92 { ( 576 384 16 ) ( 576 385 16 ) ( 576 384 17 ) mapping_defaults/ProtoYellow 0 0 0 0.25 0.25 ( 576 384 16 ) ( 576 384 17 ) ( 577 384 16 ) mapping_defaults/ProtoYellow 0 0 0 0.25 0.25 @@ -848,6 +839,33 @@ ( 704 480 32 ) ( 705 480 32 ) ( 704 480 33 ) mapping_defaults/ProtoYellow 0 0 0 0.25 0.25 ( 704 480 32 ) ( 704 480 33 ) ( 704 481 32 ) mapping_defaults/ProtoYellow 0 0 0 0.25 0.25 } +// brush 93 +{ +( 168 640 16 ) ( 168 641 16 ) ( 168 640 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 648 16 ) ( 168 648 17 ) ( 169 648 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 168 640 16 ) ( 169 640 16 ) ( 168 641 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 536 656 272 ) ( 536 657 272 ) ( 537 656 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 536 656 24 ) ( 537 656 24 ) ( 536 656 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 320 648 64 ) ( 320 648 96 ) ( 320 776 96 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 94 +{ +( 368 648 64 ) ( 368 776 96 ) ( 368 648 96 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 648 16 ) ( 168 648 17 ) ( 169 648 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 168 640 16 ) ( 169 640 16 ) ( 168 641 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 536 656 272 ) ( 536 657 272 ) ( 537 656 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 536 656 24 ) ( 537 656 24 ) ( 536 656 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 536 656 24 ) ( 536 656 25 ) ( 536 657 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 95 +{ +( 320 648 64 ) ( 320 776 96 ) ( 320 648 96 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 648 16 ) ( 168 648 17 ) ( 169 648 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 352 648 112 ) ( 336 776 112 ) ( 336 648 112 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 536 656 272 ) ( 536 657 272 ) ( 537 656 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 536 656 24 ) ( 537 656 24 ) ( 536 656 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 368 648 64 ) ( 368 648 96 ) ( 368 776 96 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} } // entity 1 { diff --git a/projects/sampleGame/externGame/externGame.zig b/projects/sampleGame/externGame/externGame.zig index 9bb240b..9e250e9 100644 --- a/projects/sampleGame/externGame/externGame.zig +++ b/projects/sampleGame/externGame/externGame.zig @@ -1,5 +1,9 @@ pub export fn add(a: i32, b: i32) i32 { - return a + b + 32000; + return a + b; +} + +pub export fn subtract(a: i32, b: i32) i32 { + return a + b; } const std = @import("std"); diff --git a/projects/sampleGame/main.zig b/projects/sampleGame/main.zig index dc0a4a8..4486330 100644 --- a/projects/sampleGame/main.zig +++ b/projects/sampleGame/main.zig @@ -30,6 +30,8 @@ tbMap: ?*bsp.maploader.TBMap = null, addFunc: ?*const fn (i32, i32) callconv(.C) i32 = undefined, +engineTool: *extras.EngineTool = undefined, + modules: std.AutoHashMapUnmanaged(u32, []const u8) = .{}, pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); @@ -190,6 +192,8 @@ pub fn prepare(self: *@This()) !void { try script.loadTypes("scripts"); try script.runScriptFile("scripts/prepare.lua"); + self.engineTool = try extras.EngineTool.create(self.allocator); + core.fs().watchPath("zig-out/modules"); try core.fs().addFileChangedCallback(core.sharedLibName("externGame"), moduleChangedCallback, self); @@ -382,13 +386,16 @@ pub fn tryLoadExtern(self: *@This(), gameName: []const u8) !void { const os_tag = @import("builtin").os.tag; var suffix: []const u8 = "dll"; + var prefix: []const u8 = ""; if (os_tag == .linux) { + prefix = "lib"; suffix = "so"; } else if (os_tag == .macos) { - suffix = "dynlib"; + suffix = "dylib"; + prefix = "lib"; } - const path = try std.fmt.bufPrint(&buf, "zig-out/bin/{s}.{s}", .{ gameName, suffix }); + const path = try std.fmt.bufPrint(&buf, "zig-out/modules/{s}{s}.{s}", .{ prefix, gameName, suffix }); var lib = try std.DynLib.open(path); // std.debug.print("path: {s}", .{path}); @@ -411,14 +418,9 @@ pub fn tick(self: *@This(), dt: f64) void { }, .{ .s = self }); const z1 = tracy.ZoneN(@src(), "inputDebugger"); - if (!self.mouseLook) { - extras.inputDebugger.tick(); - } z1.End(); const z2 = tracy.ZoneN(@src(), "inputDebugger"); - self.objectSpawner.windowOpen = !self.mouseLook; - self.objectSpawner.tick(dt); z2.End(); const z3 = tracy.ZoneN(@src(), "VideoPlayer"); @@ -461,6 +463,11 @@ pub fn tick(self: *@This(), dt: f64) void { // show a window with the current camera's position if (!self.mouseLook) { + ig.showDemoWindow(null); + self.engineTool.tick(); + self.objectSpawner.windowOpen = !self.mouseLook; + self.objectSpawner.tick(dt); + extras.inputDebugger.tick(); self.rendererDebugger.tick(dt); if (ig.begin("meh", null, .{})) { ig.textFmt("x:{d:.03} y:{d:.03} z:{d:.03}", .{ pos.x, pos.y, pos.z }) catch return; @@ -529,14 +536,23 @@ pub fn deinit(self: *@This()) void { } pub fn main() anyerror!void { - try backlog.initializeAndRunStandardProgram(@This(), .{ - .name = "SampleGame", - .enabledModules = .{ - .imgui = true, - .physics = true, - .audio = true, - }, - }); + var spec = try backlog.createSpecVariant(.{ + .name = "sampleGame", + .imgui = true, + .physics = true, + .audio = true, + }, std.heap.c_allocator); + + _ = backlog.initAndRun(&NeonObjectTable, &spec); + + // try backlog.initializeAndRunStandardProgram(@This(), .{ + // .name = "sampleGame", + // .enabledModules = .{ + // .imgui = true, + // .physics = true, + // .audio = true, + // }, + //}); } const DoomPlayer = @import("doomplayer");