// main public facing root file for core const std = @import("std"); pub const gameObjectList = @import("utils/gameObjectList.zig"); pub const GameObjectList = gameObjectList.GameObjectList; pub const GameObjectInterface = gameObjectList.GameObjectInterface; pub const GameObjectData = gameObjectList.GameObjectData; pub const inputs = @import("inputs/inputStack.zig"); pub const getInputStack = inputs.getInputStack; pub const ActionEvent = inputs.ActionEvent; pub const Axis1dBinding = inputs.Axis1dBinding; pub const Axis2dBinding = inputs.Axis2dBinding; pub const ActionBinding = inputs.ActionBinding; pub const IOEvent = inputs.IOEvent; pub const debug_draw = @import("debug_draw.zig"); pub const debugTextLog = debug_draw.debugTextLog; pub const DebugDrawParams = debug_draw.DebugDrawParams; pub const DebugDrawInterface = debug_draw.DebugDrawInterface; pub const installDebugDrawInterface = debug_draw.installDebugDrawInterface; pub const debugSphere = debug_draw.debugSphere; pub const debugSphereTransform = debug_draw.debugSphereTransform; 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"); pub usingnamespace @import("engineObject.zig"); pub usingnamespace @import("jobs.zig"); pub usingnamespace @import("file_utils.zig"); pub usingnamespace @import("string_utils.zig"); pub usingnamespace @import("type_utils.zig"); pub const engine = @import("engine.zig"); pub const tracy = @import("tracy"); pub const png = @import("png.zig"); pub const colors = @import("colors.zig"); pub const zgltf = @import("zgltf"); pub const zm = @import("zmath"); pub usingnamespace @import("p2"); pub const algorithm = @import("p2"); pub const nfd = @import("nfd"); pub usingnamespace @import("math.zig"); pub usingnamespace @import("args.zig"); pub usingnamespace @import("file_dialogue.zig"); pub const panickers = @import("panickers.zig"); pub const scene = @import("scene.zig"); pub const ScenePosRot = scene.ScenePosRot; pub const SceneSystem = scene.SceneSystem; pub const Engine = engine.Engine; const Name = algorithm.Name; pub const spng = @import("spng"); pub const MemoryTracker = @import("MemoryTracker.zig"); pub const DefaultSavePath = "Saved"; const logging = @import("logging.zig"); const c = @This(); const logs = logging.engine_logs; const log = logging.engine_log; pub const packer = @import("packer"); pub const FileSystem = packer.PackerFS; pub const PackerFS = packer.PackerFS; pub const StackCompactor = stacks.StackCompactor; var staticsInitialized = false; var gEngine: *Engine = undefined; var gPackerFS: *PackerFS = undefined; var fsInitialized: bool = false; pub fn EngineObject(comptime T: type) type { return struct { pub var gInstance: ?*T = null; pub fn get() *T { if (gInstance == null) { gInstance = getEngineObject(T); } return gInstance.?; } }; } pub fn getModuleLoader() *ModuleLoader { return EngineObject(ModuleLoader).get(); } var gIsUtility: bool = false; pub const Scene = scene.Scene; pub const externModule = @import("extern/externModule.zig"); pub const ModuleLoader = externModule.ModuleLoader; pub const ModuleLoaderArgs = externModule.ModuleLoaderArgs; pub const ecs = @import("ecs.zig"); pub usingnamespace ecs; pub const script = @import("script.zig"); pub const stacks = @import("stacks.zig"); pub const walkAndPrintStack = stacks.walkAndPrintStack; pub const gameObject = @import("gameObject.zig"); pub const SpawnParameters = gameObject.SpawnParameters; pub const GameObject = gameObject.GameObject; pub const GameObjectSystem = gameObject.GameObjectSystem; pub const MessageInfo = gameObject.MessageInfo; pub fn registerObject(comptime T: type, name: []const u8) !void { try get(GameObjectSystem).registerObject(name, T); } pub fn registerObjectAdvanced(comptime T: type, name: []const u8, comptime funcName: []const u8) !void { try get(GameObjectSystem).registerObjectAdvanced(name, T, funcName); } pub fn fs() *PackerFS { return gPackerFS; } pub const Module = ModuleDescription{ .name = "core", .enabledByDefault = true, }; pub fn isUtility() bool { return gIsUtility; } pub fn checkArgBool(args: anytype, comptime field: []const u8) bool { if (@hasField(@TypeOf(args), "fatDump")) { return @field(args, field); } return false; } pub fn getSessionStamp() i64 { return gEngine.sessionStamp; } // a struct can be used like a list of types in this way pub const ComponentList = struct { pub const Scene = scene.Scene; pub const GameObject = gameObject.GameObject; }; pub const ModuleStartupError = error{StartupFailed}; pub fn start_module(map: *SpecVariantMap, args: anytype, allocator: std.mem.Allocator) ModuleStartupError!void { start_module_(map, args, allocator) catch return error.StartupFailed; } pub fn maybeInitPackerFs(allocator: std.mem.Allocator) !void { if (fsInitialized == false) { gPackerFS = try PackerFS.init(allocator, .{}); fsInitialized = 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; if (checkArgBool(args, "fatDump")) { fatDump = true; } script.lua.setupMiniDump(fatDump); _ = try algorithm.createNameRegistry(allocator); // LUA BEGIN -- what if i want to make the scripting integration optional? try script.start_lua(allocator); // LUA END try maybeInitPackerFs(allocator); // load configs. //const name = if (@hasField(@TypeOf(programSpec), "configName")) programSpec.configName else programSpec.name; var name = map.get("name").?.string; if (map.get("configName")) |x| { name = x.string; } gEngine = try allocator.create(Engine); gEngine.* = try Engine.init(allocator); _ = try createObject(ModuleLoader, .{}); try console.start(); 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); } try ecs.setup(allocator); _ = try gEngine.createObject(scene.SceneSystem, .{ .can_tick = true }); try algorithm.string_pool.setup(allocator); _ = try gEngine.createObject(script_bindings.ScriptTicks, .{ .can_tick = true }); _ = try createObject(GameObjectSystem, .{ .can_tick = true }); _ = try inputs.initInputStack(); // components define try ecs.defineComponentList(ComponentList, allocator); return; } pub fn setupFromModule(__args: ModuleLoaderArgs) !void { gEngine = __args.engine; gPackerFS = __args.packerFS; script.setupLuaFromModule(__args.luaState, __args.luaAllocator); algorithm.names.gRegistry = __args.nameRegistry; logging.setupLoggingFromModule(); staticsInitialized = true; // walk through and patch all ecs containers ecs.patchComponentList(ComponentList); debug_draw.gDebugDrawInterface = __args.debugDrawInterface; if (getEngineObject(SceneSystem)) |system| { scene.Scene.SceneObjectContainer = system.sceneObjectContainer; } } pub fn shutdown_module(_: std.mem.Allocator) void { MemoryTracker.MTPrintStatsDelta(); ecs.undefineComponentList(ComponentList); logging.shutdownLogging(); debug_draw.shutdownDrawInterface(); ecs.shutdown(); algorithm.destroyNameRegistry(); gEngine.deinit(); gPackerFS.destroy(); // LUA BEGIN script.shutdown_lua(); // LUA END console.shutdown(); algorithm.string_pool.shutdown(); return; } pub fn dispatchJob(capture: anytype) !void { try gEngine.jobManager.newJob(capture); } pub fn createObject(comptime T: type, params: engine.NeonObjectParams) !*T { return gEngine.createObject(T, params); } pub fn createObjectVTable(vtable: *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; } pub fn setupEnginePlatform(ctx: *anyopaque, poll: engine.PollFuncFn, proc: engine.ProcEventsFn) void { gEngine.platformCtx = ctx; gEngine.platformPollFunc = poll; gEngine.platformProcEventsFunc = proc; } pub fn exitNow() void { signalShutdown(); } pub fn signalShutdown() void { gEngine.exit(); } pub fn getEngine() *Engine { return gEngine; } pub fn BuildOption(comptime option: []const u8) bool { if (@hasDecl(@import("root"), "options")) { const r = @import("root").options; if (@hasDecl(r, option)) { return @field(r, option); } else { return false; } } return false; } const EngineDelegates = @import("EngineDelegates.zig"); // binds a function + a context to pub fn addEngineDelegateBinding(comptime event: []const u8, func: anytype, ctx: *anyopaque) !usize { if (!@hasField(EngineDelegates, event)) { @compileError("Engine does not have delegate " ++ event); } const handle = @field(gEngine.delegates, event).items.len; try @field(gEngine.delegates, event).append(gEngine.delegates.allocator, .{ .func = func, .ctx = ctx }); return handle; } const getEngineTime = @import("engineTime.zig").getEngineTime; pub fn getEngineUptime() f64 { return getEngineTime() - gEngine.engineStartTime; } pub const modules = @import("modules.zig"); pub const isModuleEnabled = modules.isModuleEnabled; pub const ModuleDescription = modules.ModuleDescription; pub const console = @import("console.zig"); pub const configVars = @import("configVars.zig"); 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 const EngineObjectRef = engineObject.EngineObjectRef; pub fn getEngineObjectRef(comptime T: type) ?engineObject.EngineObjectRef { if (T.NeonObjectTable.singletonName) |name| { if (getEngine().engineObjectsByName.get(name)) |ref| { return ref; } } return null; } 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 get(comptime T: type) *T { return EngineObject(T).get(); } pub fn loadModule(moduleName: []const u8, watch: bool) !void { if (watch == false) unreachable; // not implemented try getModuleLoader().addModule(moduleName); } pub fn startup_getAllocator(p_allocator: *anyopaque) std.mem.Allocator { return @as(*std.mem.Allocator, @ptrCast(@alignCast(p_allocator))).*; } pub fn startup_getArgs(p_allocator: *anyopaque) ModuleLoaderArgs { return @as(*ModuleLoaderArgs, @ptrCast(@alignCast(p_allocator))).*; } pub fn modulePreamble(p_allocator: *anyopaque, p_a: ?*anyopaque) !std.mem.Allocator { const args = startup_getArgs(p_a.?); const allocator = startup_getAllocator(p_allocator); try setupFromModule(args); return allocator; } // a wrapper around a struct // which adds slack up to a specific size // // engine objects must be allocated with this if they support hot patching // // if pub const Slack is a decl in the struct- EngineObjectVTable will generate with a // fields remapping list. pub fn SlackStruct(comptime T: type, comptime SlackSize: usize) type { return struct { inner: T, slack: [SlackSize - @sizeOf(T)]u8 = undefined, pub fn create(allocator: std.mem.Allocator) !*T { return (try allocator.create(@This())).getInner(); } pub fn getInner(self: *@This()) *T { return &self.inner; } pub fn fromPtr(inner: *T) *@This() { const p: *anyopaque = inner; return @as(*@This(), @ptrCast(@alignCast(p))); } }; } pub fn cast(comptime T: type, p: *anyopaque) T { return @alignCast(@ptrCast(p)); } pub fn MakeNameFmt(comptime fmt: []const u8, args: anytype) Name { var makeNameBuf: [256]u8 = undefined; return algorithm.MakeName(std.fmt.bufPrint(&makeNameBuf, fmt, args) catch unreachable); } pub fn PatchOrCreateObject(comptime T: type, args: engine.NeonObjectParams) void { if (getEngineObject(T) != null) { engineObject.updateEngineVTable(T); return; } logging.engine_log("spawning object {s}", .{T.NeonObjectTable.typeName}); _ = createObject(T, args) catch { logging.engine_err("Unable to create object", .{}); }; }