//pub const core = @import("core"); //pub const platform = @import("platform"); //pub const assets = @import("assets"); //pub const rend = @import("rend"); //pub const audio = @import("audio"); //pub const ui = @import("ui"); //pub const papyrus = @import("papyrus"); //pub const physics = @import("physics"); //pub const imgui = @import("imgui"); pub const core = @import("core").module; pub const platform = @import("platform").module; pub const assets = @import("assets").module; pub const rend = @import("rend").module; pub const audio = @import("audio").module; pub const net = @import("net").module; pub const ui = @import("ui").module; pub const papyrus = @import("papyrus").module; pub const physics = @import("physics").module; pub const imgui = @import("imgui").module; pub const sys = @import("sys").module; const modulelist = @import("modulelist.zig").list; const std = @import("std"); pub const NwArgs = struct { useGPA: bool = false, // slower zig based memory allocator, provides detailed tracking of leaks and memory violations vulkanValidation: bool = true, fastTest: bool = false, dmt: bool = false, // detailed memory tracking, implements a timeline for tracking all memory allocations fatDump: bool = false, // takes a full fat minidump on crash, very large files are produced }; pub fn getArgs() !NwArgs { const a = try core.ParseArgs(NwArgs); return a; } // entry function for a backlog program // when this function is called it will use the settings specified by the program spec // to conditionally start up feature modules within the engine var shutdownList: std.ArrayListUnmanaged(*const fn (std.mem.Allocator) void) = .{}; var shutdownModuleNames: std.ArrayListUnmanaged([]const u8) = .{}; 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"); defer z.End(); inline for (modulelist) |feature| { if (@hasDecl(Backlog, feature)) { const Struct = @field(Backlog, feature); 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(spec, args, allocator); } else { try Struct.start_module(spec, NwArgs{}, allocator); } try shutdownList.append(allocator, Struct.shutdown_module); try shutdownModuleNames.append(allocator, feature); core.engine_logs("module started >>>> " ++ feature ++ " <<<<"); } } } } pub const ModuleStartup = struct { name: []const u8, startupFunc: *const fn (map: *core.SpecVariantMap, args: anytype, allocator: std.mem.Allocator) core.ModuleStartupError!void, shutdownFunc: *const fn (*const fn (std.mem.Allocator) void) void, }; // read moduleList from root pub fn start_modules_list(list: []const ModuleStartup, spec: *core.SpecVariantMap, maybeArgs: ?NwArgs, allocator: std.mem.Allocator) !void { var z = core.tracy.ZoneN(@src(), "Starting all Modules"); defer z.End(); for (list) |feature| { //if (@hasDecl(Backlog, feature)) { core.engine_logs("starting module >> {s}", .{feature.name}); try feature.startupFunc(spec, maybeArgs orelse NwArgs{}, allocator); try shutdownList.append(allocator, feature.shutdownFunc); try shutdownModuleNames.append(allocator, feature.name); core.engine_logs("module started {s}! ", .{feature.name}); } //} } pub fn shutdown_modules(allocator: std.mem.Allocator) void { var i: isize = @intCast(shutdownList.items.len - 1); while (i >= 0) : (i -= 1) { core.engine_log("module shutting down >>>> {s} <<<<", .{shutdownModuleNames.items[@intCast(i)]}); shutdownList.items[@intCast(i)](allocator); } shutdownList.deinit(allocator); shutdownModuleNames.deinit(allocator); } pub fn start_everything(spec: *core.SpecVariantMap, allocator: std.mem.Allocator, maybeArgs: ?NwArgs) !void { //if (maybeArgs) |args| { // //if (args.vulkanValidation) // // graphics.setStartupSettings("vulkanValidation", true); //} try start_modules(spec, maybeArgs, allocator); } pub fn shutdown_everything(allocator: std.mem.Allocator) void { shutdown_modules(allocator); } pub fn run_everything_vtable(gameVtable: *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.getEngine().run(); while (!core.getEngine().exitFinished()) { const z = core.tracy.ZoneN(@src(), "shutdown poll"); z.End(); } } 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.getEngine().run(); while (!core.getEngine().exitFinished()) { const z = core.tracy.ZoneN(@src(), "shutdown poll"); z.End(); } } pub const createSpecVariant = core.createSpecVariant; pub export fn initAndRun(vtable: *core.EngineObjectVTable, spec: *core.SpecVariantMap) bool { const args = getArgs() catch return false; var backingAllocator: std.mem.Allocator = std.heap.smp_allocator; var gpa: std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = 20, }) = .{}; defer { const cleanupStatus = gpa.deinit(); if (cleanupStatus == .leak) { std.debug.print("gpa cleanup leaked memory\n", .{}); } } if (spec.get("useGPA")) |arg| { if (arg.boolean == true) { backingAllocator = gpa.allocator(); } } const memory = core.MemoryTracker; memory.MTSetup(backingAllocator, .{ .timeline = args.dmt }); defer memory.MTShutdown(); var tracker = memory.MTGet().?; const allocator = tracker.allocator(); start_everything(spec, allocator, args) catch return false; defer shutdown_everything(allocator); run_everything_vtable(vtable) catch return false; return true; }