618 lines
18 KiB
Zig
618 lines
18 KiB
Zig
// main public facing root file for core
|
|
const std = @import("std");
|
|
|
|
pub const machinery = @import("machinery/machinery.zig");
|
|
|
|
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 engineTime = @import("engineTime.zig");
|
|
pub const engineObject = @import("engineObject.zig");
|
|
pub const EngineObjectVTable = engineObject.EngineObjectVTable;
|
|
pub const MakeTypeName = engineObject.MakeTypeName;
|
|
pub const PatchStruct = engineObject.PatchStruct;
|
|
pub const InterfaceRef = engineObject.InterfaceRef;
|
|
pub const updateEngineVTable = engineObject.updateEngineVTable;
|
|
pub const EngineDataEventError = engineObject.EngineDataEventError;
|
|
pub const EngineObjectDelegate = engineObject.EngineObjectDelegate;
|
|
pub const FieldInfo = engineObject.FieldInfo;
|
|
|
|
pub const jobs = @import("jobs.zig");
|
|
pub const JobContext = jobs.ThreadContext;
|
|
pub const ThreadContext = jobs.ThreadContext;
|
|
pub const JobManager = jobs.JobManager;
|
|
pub const JobWorker = jobs.JobWorker;
|
|
|
|
pub const engine = @import("engine.zig");
|
|
pub const tracy = @import("tracy").t;
|
|
|
|
pub const colors = @import("colors.zig");
|
|
|
|
pub const zgltf = @import("zgltf");
|
|
|
|
pub const zm = @import("zmath");
|
|
|
|
pub const p2 = @import("p2");
|
|
pub const assert = p2.assert;
|
|
pub const asserts = p2.asserts;
|
|
pub const assertf = p2.assertf;
|
|
pub const stringStrip = p2.stringStrip;
|
|
|
|
pub const MakeInterface = p2.MakeInterface;
|
|
|
|
pub const Reference = p2.Reference;
|
|
|
|
pub const names = p2.names;
|
|
pub const BumpArena = p2.BumpArena;
|
|
pub const ObjectHandle = p2.ObjectHandle;
|
|
pub const RingQueue = p2.RingQueue;
|
|
pub const RingQueueU = p2.RingQueueU;
|
|
pub const ConcurrentQueueU = p2.ConcurrentQueueU;
|
|
pub const Name = p2.Name;
|
|
pub const StaticVector = p2.StaticVector;
|
|
|
|
pub const SparseSet = p2.SparseSet;
|
|
pub const SparseMap = p2.SparseMap;
|
|
pub const SparseMultiSet = p2.SparseMultiSet;
|
|
pub const SparseSetAdvanced = p2.SparseSetAdvanced;
|
|
pub const SparseMultiSetAdvanced = p2.SparseMultiSetAdvanced;
|
|
pub const SetHandle = p2.SetHandle;
|
|
|
|
pub const EcsContainerInterface = p2.EcsContainerInterface;
|
|
|
|
pub const IndexPoolHandle = p2.IndexPoolHandle;
|
|
pub const PagedVector = p2.PagedVector;
|
|
pub const IndexPool = p2.IndexPool;
|
|
pub const MakeName = p2.MakeName;
|
|
pub const DefineName = p2.DefineName;
|
|
pub const createNameRegistry = p2.createNameRegistry;
|
|
pub const destroyNameRegistry = p2.destroyNameRegistry;
|
|
pub const setNameRegistry = p2.setNameRegistry;
|
|
pub const NameRegistry = p2.NameRegistry;
|
|
pub const NameInvalid = p2.NameInvalid;
|
|
|
|
pub const getFileExtension = p2.getFileExtension;
|
|
pub const getBasePath = p2.getBasePath;
|
|
pub const getDir = p2.getDir;
|
|
pub const getFolder = p2.getFolder;
|
|
|
|
pub const MergedSpans = p2.MergedSpans;
|
|
pub const Span = p2.Span;
|
|
pub const shell = p2.shell;
|
|
|
|
pub const algorithm = @import("p2");
|
|
pub const math = @import("math.zig");
|
|
|
|
pub const Rayf = math.Rayf;
|
|
pub const f32x4 = math.f32x4; // __m128_int
|
|
pub const f32x8 = math.f32x8; // __m256_int
|
|
pub const f32x16 = math.f32x16; // __m512_int
|
|
pub const f32x4_zero = math.f32x4_zero;
|
|
pub const f32x8_zero = math.f32x8_zero;
|
|
pub const f32x16_zero = math.f32x16_zero;
|
|
|
|
//
|
|
pub const radians = math.radians;
|
|
pub const Mat = math.Mat;
|
|
pub const Transform = math.Transform;
|
|
pub const Quat = math.Quat;
|
|
pub const Vector2i = math.Vector2i;
|
|
pub const Vectorf = math.Vectorf;
|
|
pub const Vector = math.Vector;
|
|
pub const Vector4 = math.Vector4;
|
|
pub const Vector4f = math.Vector4f;
|
|
pub const Vector2 = math.Vector2;
|
|
pub const Vector2c = math.Vector2c;
|
|
pub const Vector2u = math.Vector2u;
|
|
pub const Vector2f = math.Vector2f;
|
|
pub const Rotation = math.Rotation;
|
|
|
|
pub const launchArgs = @import("args.zig");
|
|
pub const ParseArgs = launchArgs.ParseArgs;
|
|
|
|
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;
|
|
|
|
pub const MemoryTracker = @import("MemoryTracker.zig");
|
|
|
|
pub const DefaultSavePath = "Saved";
|
|
|
|
pub const logging = @import("logging.zig");
|
|
pub const logDisplay = logging.logDisplay;
|
|
pub const LoggerSys = logging.LoggerSys;
|
|
|
|
const c = @This();
|
|
pub const getLogger = logging.getLogger;
|
|
|
|
pub const console_log = logging.console_log;
|
|
pub const console_logs = logging.console_logs;
|
|
|
|
pub const engine_logs = logging.engine_logs;
|
|
pub const engine_log = logging.engine_log;
|
|
|
|
pub const graphics_logs = logging.graphics_logs;
|
|
pub const graphics_log = logging.graphics_log;
|
|
|
|
pub const engine_err = logging.engine_err;
|
|
pub const engine_errs = logging.engine_errs;
|
|
|
|
pub const printInner = logging.printInner;
|
|
|
|
pub const errorHighlight = logging.errorHighlight;
|
|
pub const defaultHighlight = logging.defaultHighlight;
|
|
|
|
pub const packer = @import("packer");
|
|
|
|
pub const StackCompactor = stacks.StackCompactor;
|
|
|
|
var staticsInitialized = false;
|
|
var gEngine: *Engine = undefined;
|
|
pub const PackerFS = packer.PackerFS;
|
|
var gPackerFS: *PackerFS = undefined;
|
|
|
|
pub fn fs() *PackerFS {
|
|
return gPackerFS;
|
|
}
|
|
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 const defineComponentList = ecs.defineComponentList;
|
|
pub const undefineComponentList = ecs.undefineComponentList;
|
|
|
|
pub const Entity = ecs.Entity;
|
|
pub const createEntity = ecs.createEntity;
|
|
|
|
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 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) {
|
|
engine_logs("utility mode - no gui");
|
|
gIsUtility = true;
|
|
}
|
|
}
|
|
|
|
var fatDump: bool = false;
|
|
if (checkArgBool(args, "fatDump")) {
|
|
fatDump = true;
|
|
}
|
|
|
|
_ = try algorithm.createNameRegistry(allocator);
|
|
try maybeInitPackerFs(allocator);
|
|
|
|
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);
|
|
gEngine.stringContext = algorithm.string_pool.gStringContext;
|
|
|
|
_ = 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;
|
|
algorithm.names.gRegistry = __args.nameRegistry;
|
|
algorithm.string_pool.gStringContext = gEngine.stringContext;
|
|
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();
|
|
gPackerFS.destroy();
|
|
console.shutdown();
|
|
algorithm.string_pool.shutdown();
|
|
|
|
gEngine.deinit();
|
|
return;
|
|
}
|
|
|
|
pub fn parallelJob(capture: anytype, async: bool, maxWorkerCount: ?u32) !void {
|
|
const z = tracy.ZoneNC(@src(), "parallel Job", 0xCF8774);
|
|
defer z.End();
|
|
|
|
const jobManager = getEngine().jobManager;
|
|
const requestedWorkers = if (maxWorkerCount) |m| m else jobManager.numWorkers;
|
|
const baseWorkerCount = @min(requestedWorkers, @max(getEngine().jobManager.numWorkers - 2, 1));
|
|
|
|
const workerStart: u32 = if (async) 0 else 1;
|
|
|
|
for (workerStart..baseWorkerCount) |workerId| {
|
|
try jobManager.newJob(capture, .{ .threadId = @intCast(workerId), .threadCount = baseWorkerCount });
|
|
}
|
|
|
|
// start working on the job locally
|
|
if (!async) {
|
|
try jobManager.runLocally(capture, .{ .threadId = 0, .threadCount = baseWorkerCount });
|
|
}
|
|
}
|
|
|
|
pub fn dispatchJob(capture: anytype) !void {
|
|
try gEngine.jobManager.newJob(capture, .{ .threadId = 0, .threadCount = 1 }); //0, 1, null);
|
|
}
|
|
|
|
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 {
|
|
// destroy all ecs entities first
|
|
ecs.destroyAllEntities();
|
|
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;
|
|
}
|
|
|
|
pub 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 @ptrCast(@alignCast(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", .{});
|
|
};
|
|
}
|
|
|
|
pub const u32a = std.atomic.Value(u32);
|
|
pub const i32a = std.atomic.Value(u32);
|
|
|
|
var gBarrierCount: u32a = u32a.init(0);
|
|
|
|
pub fn setBarrierCount(count: u32) void {
|
|
gBarrierCount.store(count, .seq_cst);
|
|
}
|
|
|
|
pub fn getBarrierCount() u32 {
|
|
return gBarrierCount.load(.acquire);
|
|
}
|
|
|
|
pub fn jobCount() u32 {
|
|
return getEngine().jobManager.numWorkers;
|
|
}
|
|
|
|
pub fn waitSeconds(wait: f64) void {
|
|
const start = getEngineTime();
|
|
|
|
while (getEngineTime() - start < wait) {
|
|
std.Thread.sleep(10_000_000);
|
|
}
|
|
}
|
|
|
|
pub fn itof32(i: anytype) f32 {
|
|
return @as(f32, @floatFromInt(i));
|
|
}
|
|
|
|
pub fn itof64(i: anytype) f32 {
|
|
return @as(f32, @floatFromInt(i));
|
|
}
|
|
|
|
pub fn setShutdownModule(shutdownFunction: *const fn () callconv(.c) void) void {
|
|
getEngine().shutdownModuleFunction = shutdownFunction;
|
|
}
|