networking module created

This commit is contained in:
peterino2 2025-09-28 14:59:39 -07:00
parent 89fbe381e8
commit 9cadb88e7f
20 changed files with 616 additions and 82 deletions

View File

@ -27,6 +27,7 @@ const engineDepList = [_][]const u8{
"assets", "assets",
"audio", "audio",
"core", "core",
"net",
"papyrus", "papyrus",
"platform", "platform",
"rend", "rend",

View File

@ -5,6 +5,7 @@
.assets = .{ .path = "engine/assets" }, .assets = .{ .path = "engine/assets" },
.audio = .{ .path = "engine/audio" }, .audio = .{ .path = "engine/audio" },
.core = .{ .path = "engine/core" }, .core = .{ .path = "engine/core" },
.net = .{ .path = "engine/net" },
.papyrus = .{ .path = "engine/papyrus" }, .papyrus = .{ .path = "engine/papyrus" },
.physics = .{ .path = "engine/physics" }, .physics = .{ .path = "engine/physics" },
.platform = .{ .path = "engine/platform" }, .platform = .{ .path = "engine/platform" },

View File

@ -13,6 +13,7 @@ pub const platform = @import("platform").module;
pub const assets = @import("assets").module; pub const assets = @import("assets").module;
pub const rend = @import("rend").module; pub const rend = @import("rend").module;
pub const audio = @import("audio").module; pub const audio = @import("audio").module;
pub const net = @import("net").module;
pub const ui = @import("ui").module; pub const ui = @import("ui").module;
pub const papyrus = @import("papyrus").module; pub const papyrus = @import("papyrus").module;
pub const physics = @import("physics").module; pub const physics = @import("physics").module;

View File

@ -53,6 +53,7 @@ pub usingnamespace @import("file_dialogue.zig");
pub const panickers = @import("panickers.zig"); pub const panickers = @import("panickers.zig");
pub const scene = @import("scene.zig"); pub const scene = @import("scene.zig");
pub const ScenePosRot = scene.ScenePosRot;
pub const SceneSystem = scene.SceneSystem; pub const SceneSystem = scene.SceneSystem;
pub const Engine = engine.Engine; pub const Engine = engine.Engine;
@ -118,8 +119,18 @@ pub const walkAndPrintStack = stacks.walkAndPrintStack;
pub const gameObject = @import("gameObject.zig"); pub const gameObject = @import("gameObject.zig");
pub const SpawnParameters = gameObject.SpawnParameters;
pub const GameObject = gameObject.GameObject; pub const GameObject = gameObject.GameObject;
pub const GameObjectSystem = gameObject.GameObjectSystem; 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 { pub fn fs() *PackerFS {
return gPackerFS; return gPackerFS;
@ -215,6 +226,8 @@ pub fn start_module_(map: *SpecVariantMap, args: anytype, allocator: std.mem.All
try algorithm.string_pool.setup(allocator); try algorithm.string_pool.setup(allocator);
_ = try gEngine.createObject(script_bindings.ScriptTicks, .{ .can_tick = true }); _ = try gEngine.createObject(script_bindings.ScriptTicks, .{ .can_tick = true });
_ = try createObject(GameObjectSystem, .{ .can_tick = true });
_ = try inputs.initInputStack(); _ = try inputs.initInputStack();
// components define // components define
@ -384,6 +397,10 @@ pub fn getEngineObject(comptime T: type) ?*T {
return null; return null;
} }
pub fn get(comptime T: type) *T {
return EngineObject(T).get();
}
pub fn loadModule(moduleName: []const u8, watch: bool) !void { pub fn loadModule(moduleName: []const u8, watch: bool) !void {
if (watch == false) unreachable; // not implemented if (watch == false) unreachable; // not implemented

View File

@ -125,7 +125,7 @@ pub fn destroyEntity(e: Entity) void {
entityEntry.containers.deinit(registry.allocator); entityEntry.containers.deinit(registry.allocator);
registry.baseSet.destroyObject(e.handle); registry.baseSet.destroyObject(e.handle);
} else { } else {
core.engine_log("UNABLE TO DESTROY ENTITY {d}", .{e.handle.index}); // core.engine_log("UNABLE TO DESTROY ENTITY {d}", .{e.handle.index});
} }
} }
@ -147,7 +147,7 @@ pub fn CreateEntity_Lua(state: lua.LuaState) i32 {
pub fn setup(allocator: std.mem.Allocator) !void { pub fn setup(allocator: std.mem.Allocator) !void {
try ComponentRef.setupFormatBuffer(allocator); try ComponentRef.setupFormatBuffer(allocator);
_ = try core.createObject(EcsRegistry, .{ .can_tick = true }); _ = try core.createObject(EcsRegistry, .{ .can_tick = true, .isCore = true });
} }
pub fn shutdown() void { pub fn shutdown() void {
@ -349,8 +349,10 @@ pub const Entity = struct {
}, },
}; };
pub fn destroy(self: *@This()) void { pub fn destroy(self: @This()) void {
destroyEntity(self.*); //if (core.getEngineObject(EcsRegistry) != null) {
destroyEntity(self);
// }
} }
pub fn fromHandle(handle: core.ObjectHandle) @This() { pub fn fromHandle(handle: core.ObjectHandle) @This() {

View File

@ -2,17 +2,29 @@
// //
// lets really cook a good API here // lets really cook a good API here
pub const GameObjectInterfaceVTable = struct { pub const SpawnObjectResult = struct { ptr: *anyopaque, entity: core.Entity };
destroy: *const fn (*anyopaque) void,
tick: ?*const fn (*anyopaque, f64) void,
getEntity: ?*const fn (*anyopaque) core.Entity,
objectBaseName: core.Name = core.DefineName("UnknownObject"),
create: *const fn (allocator: std.mem.Allocator, entity: core.Entity) *@This(),
pub const ObjectCreateFn = *const fn (allocator: std.mem.Allocator, entity: core.Entity, parameters: SpawnParameters) ObjectError!*anyopaque;
pub const MessageHandlerFunc = *const fn (*anyopaque, *const MessageInfo, *anyopaque) void;
pub const GameObjectInterfaceVTable = struct {
destroy: *const fn (*anyopaque, std.mem.Allocator) void,
tick: ?*const fn (*anyopaque, f64) void,
objectTypeName: core.Name = core.DefineName("UnknownType"),
objectBaseName: core.Name = core.DefineName("UnknownObject"),
create: ObjectCreateFn,
messageHandlers: std.AutoHashMapUnmanaged(u32, MessageHandlerFunc) = .{}, messageHandlers: std.AutoHashMapUnmanaged(u32, MessageHandlerFunc) = .{},
pub const MessageHandlerFunc = *const fn (*anyopaque, *const MessageInfo, *anyopaque) void; pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
// fn onCustomMessage(self, meta: core.MessageInfo, m: *const MyCustomMessage) void self.messageHandlers.deinit(allocator);
}
};
pub const ObjectError = error{
OutOfMemory,
BadInit,
UnknownState,
UnknownObject,
}; };
pub const MessageInfo = struct { pub const MessageInfo = struct {
@ -29,53 +41,149 @@ pub const GameObjectRef = struct {
pub const GameObject = struct { pub const GameObject = struct {
pub var BaseContainer: *core.SparseSet(GameObject) = undefined; pub var BaseContainer: *core.SparseSet(GameObject) = undefined;
pub const ComponentName = "core.GameObject"; pub const ComponentName = "GameObjectComponent";
pub const ScriptExports: []const []const u8 = &.{}; pub const ScriptExports: []const []const u8 = &.{};
// set by GameObjectSystem when it calls Entity // set by GameObjectSystem when it calls Entity
objectRef: GameObjectRef = undefined, objectRef: GameObjectRef = undefined,
destroyed: bool = false,
pub fn setObjectReference(self: *@This(), table: *GameObjectInterfaceVTable, object: *anyopaque) void { pub fn deinitECS(self: *@This(), handle: core.ObjectHandle) void {
self.objectRef.table = table; _ = handle;
self.objectRef.ptr = object; if (!self.destroyed) {
self.destroyed = true;
self.objectRef.table.destroy(self.objectRef.ptr, core.get(GameObjectSystem).allocator);
}
} }
}; };
pub const SpawnParameters = struct {
posRot: core.ScenePosRot = .{},
scale: core.Vectorf = .{ .z = 1.0, .y = 1.0, .x = 1.0 },
};
pub const SpawnEvent = struct {
interface: GameObjectInterfaceVTable,
};
pub const GameObjectSystem = struct { pub const GameObjectSystem = struct {
// this is the new one, GameObjectList should be deleted after this passes initial usability // this is the new one, GameObjectList should be deleted after this passes initial usability
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "core.GameObjectSystem"); pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "core.GameObjectSystem");
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
objectDefinitions: *core.SparseMap(GameObjectInterfaceVTable), objectDefinitions: std.AutoHashMapUnmanaged(u32, GameObjectInterfaceVTable) = .{},
typesArena: std.heap.ArenaAllocator,
objectSpawnEvents: std.ArrayListUnmanaged(SpawnEvent) = .{},
pub fn create(allocator: std.mem.Allocator) !*@This() { pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(*@This()); const self = try allocator.create(@This());
self.* = .{ self.* = .{
.allocator = allocator, .allocator = allocator,
.sparseMap = try core.SparseMap(GameObjectInterfaceVTable).create(allocator), .typesArena = std.heap.ArenaAllocator.init(self.allocator),
}; };
return self; return self;
} }
pub fn spawnObjectByType(self: *@This(), comptime T: type) !*T { pub fn spawnObject(
_ = self; self: *@This(),
comptime T: type,
objectName: []const u8,
parameters: SpawnParameters,
) !*T {
var n = core.MakeName(objectName);
return self.spawnObjectByName(T, &n, parameters);
}
pub fn spawnObjectByName(self: *@This(), comptime T: type, objectName: *core.Name, parameters: SpawnParameters) !*T {
return @ptrCast(@alignCast((try self.spawnObjectFromTableByName(objectName, parameters)).ptr));
}
pub fn spawnObjectFromTableByName(self: *@This(), objectName: *core.Name, parameters: SpawnParameters) !SpawnObjectResult {
const interface: *GameObjectInterfaceVTable = self.objectDefinitions.getPtr(objectName.handle()) orelse {
return ObjectError.UnknownObject;
};
const entity = try core.createEntity();
const objectComponent = entity.addComponent(GameObject).?;
const rv = SpawnObjectResult{ .ptr = try interface.create(self.allocator, entity, parameters), .entity = entity };
objectComponent.objectRef = .{
.table = interface,
.ptr = rv.ptr,
};
return rv;
}
// registers an object for spawning with the object name
pub fn registerObject(self: *@This(), objectName: []const u8, comptime T: type) !void {
try self.registerObjectAdvanced(objectName, T, "create");
}
pub fn registerObjectAdvanced(self: *@This(), name: []const u8, comptime T: type, comptime createFunctionName: []const u8) !void {
var n = core.MakeName(name);
const Wrap = struct {
pub fn create(allocator: std.mem.Allocator, entity: core.Entity, parameters: SpawnParameters) ObjectError!*anyopaque {
return @field(T, createFunctionName)(allocator, entity, parameters) catch {
return ObjectError.BadInit;
};
}
pub fn destroy(p: *anyopaque, alloc: std.mem.Allocator) void {
T.destroy(@ptrCast(@alignCast(p)), alloc);
}
pub fn tick(p: *anyopaque, dt: f64) void {
T.tick(@ptrCast(@alignCast(p)), dt);
}
};
var interface = GameObjectInterfaceVTable{
.create = Wrap.create,
.tick = if (@hasDecl(T, "tick")) Wrap.tick else null,
.destroy = Wrap.destroy,
.objectTypeName = core.MakeTypeName(T),
.objectBaseName = n,
.messageHandlers = .{},
};
if (@hasDecl(T, "MessageHandlers")) {
inline for (T.MessageHandlers) |handlerName| {
var messageHandlerName = core.MakeName(handlerName);
// const handlerFunc = @field(T, handlerName);
// const handlerTypeInfo = @typeInfo(@TypeOf(handlerFunc));
// const M = @typeInfo(handlerTypeInfo.@"fn".params[3].type.?).pointer.child;
const HandlerWrap = struct {
pub fn messageHandler(p: *anyopaque, info: *const MessageInfo, message: *anyopaque) void {
@field(T, handlerName)(@ptrCast(@alignCast(p)), info, @ptrCast(@alignCast(message)));
}
};
try interface.messageHandlers.put(self.typesArena.allocator(), messageHandlerName.handle(), HandlerWrap.messageHandler);
}
}
try self.objectDefinitions.put(self.typesArena.allocator(), n.handle(), interface);
} }
pub fn tick(self: *@This(), dt: f64) void { pub fn tick(self: *@This(), dt: f64) void {
// for (self.objects.items) |object| { // for (self.objects.items) |object| {
//if (object.vtable.tick) |tick_fn| { // if (object.vtable.tick) |tick_fn| {
//tick_fn(object.ptr, dt); // tick_fn(object.ptr, dt);
//} // }
//} // }
_ = self; _ = self;
_ = dt; _ = dt;
} }
pub fn destroy(self: *@This()) void { pub fn destroy(self: *@This()) void {
self.objects.deinit(); self.typesArena.deinit();
self.allocator.destroy(self); self.allocator.destroy(self);
} }
}; };

View File

@ -23,7 +23,7 @@ pub const SceneMobilityMode = enum {
moveable, // sceneobject is moveable and has it's final transform updated moveable, // sceneobject is moveable and has it's final transform updated
}; };
pub const SceneObjectPosRot = struct { pub const ScenePosRot = struct {
position: core.Vectorf = .{ .x = 0, .y = 0, .z = 0 }, position: core.Vectorf = .{ .x = 0, .y = 0, .z = 0 },
rotation: core.Rotation = core.Rotation.init(), rotation: core.Rotation = core.Rotation.init(),
scale: core.Vectorf = core.Vectorf.new(1.0, 1.0, 1.0), scale: core.Vectorf = core.Vectorf.new(1.0, 1.0, 1.0),
@ -60,7 +60,7 @@ pub const SceneObjectRepr = struct {
pub const SceneObject = struct { pub const SceneObject = struct {
_repr: SceneObjectRepr = .{}, // not public _repr: SceneObjectRepr = .{}, // not public
posRot: SceneObjectPosRot = .{}, // position and rotation posRot: ScenePosRot = .{}, // position and rotation
settings: SceneObjectSettings = .{}, // settings: SceneObjectSettings = .{}, //
children: ArrayListUnmanaged(core.ObjectHandle) = .{}, children: ArrayListUnmanaged(core.ObjectHandle) = .{},
@ -137,6 +137,14 @@ pub const Scene = struct {
core.engine_log("handle.index = 0x{x} generation = {d} alive={any}", .{ self.handle.index, self.handle.generation, self.handle.alive }); core.engine_log("handle.index = 0x{x} generation = {d} alive={any}", .{ self.handle.index, self.handle.generation, self.handle.alive });
} }
pub fn setPosRot(self: @This(), newPosRot: ScenePosRot) void {
if (SceneObjectContainer.get(self.handle, .posRot)) |posRot| {
posRot.* = newPosRot;
} else {
core.engine_log("setposRot failed handle.index = 0x{x} generation = {d} alive={any}", .{ self.handle.index, self.handle.generation, self.handle.alive });
}
}
pub fn setPosition(self: @This(), position: core.Vectorf) void { pub fn setPosition(self: @This(), position: core.Vectorf) void {
if (SceneObjectContainer.get(self.handle, .posRot)) |posRot| { if (SceneObjectContainer.get(self.handle, .posRot)) |posRot| {
posRot.*.position = position; posRot.*.position = position;
@ -145,7 +153,7 @@ pub const Scene = struct {
} }
} }
pub fn getPosRot(self: *@This()) *SceneObjectPosRot { pub fn getPosRot(self: *@This()) *ScenePosRot {
return SceneObjectContainer.get(self.handle, .posRot).?; return SceneObjectContainer.get(self.handle, .posRot).?;
} }
@ -214,6 +222,8 @@ pub const Scene = struct {
} }
} }
pub fn getTickCount() u32 {}
pub fn getAndResolveTransform(self: @This()) core.Transform { pub fn getAndResolveTransform(self: @This()) core.Transform {
const repr: *SceneObjectRepr = SceneObjectContainer.get(self.handle, ._repr).?; const repr: *SceneObjectRepr = SceneObjectContainer.get(self.handle, ._repr).?;
if (repr.lastUpdate != getSceneSystem().tickCount) { if (repr.lastUpdate != getSceneSystem().tickCount) {
@ -227,6 +237,12 @@ pub const Scene = struct {
return SceneObjectContainer.get(self.handle, ._repr).?.transform; return SceneObjectContainer.get(self.handle, ._repr).?.transform;
} }
pub fn updateTransform(self: @This()) void {
const repr = SceneObjectContainer.get(self.handle, ._repr).?;
const posRot = SceneObjectContainer.get(self.handle, .posRot).?;
getSceneSystem().updateTransform(repr, posRot);
}
// you MUST clearTransfomRefUnsafe() before destroying this transform // you MUST clearTransfomRefUnsafe() before destroying this transform
pub fn setTransformRefUnsafe(self: @This(), ref: *core.Transform) void { pub fn setTransformRefUnsafe(self: @This(), ref: *core.Transform) void {
SceneObjectContainer.get(self.handle, ._repr).?.transformOverride = ref; SceneObjectContainer.get(self.handle, ._repr).?.transformOverride = ref;
@ -288,7 +304,7 @@ pub const SceneSystem = struct {
pub const FieldType = SceneObjectSet.FieldType; pub const FieldType = SceneObjectSet.FieldType;
// internal update transform function // internal update transform function
fn updateTransform(self: *@This(), repr: *SceneObjectRepr, posRot: *const SceneObjectPosRot) void { fn updateTransform(self: *@This(), repr: *SceneObjectRepr, posRot: *const ScenePosRot) void {
if (repr.lastUpdate == self.tickCount) { if (repr.lastUpdate == self.tickCount) {
return; return;
} }
@ -385,6 +401,7 @@ pub const SceneSystem = struct {
pub fn tick(self: *@This(), deltaTime: f64) void { pub fn tick(self: *@This(), deltaTime: f64) void {
var z = tracy.ZoneNC(@src(), "Scene System Tick", 0xAABBDD); var z = tracy.ZoneNC(@src(), "Scene System Tick", 0xAABBDD);
defer z.End(); defer z.End();
self.updateTransforms(); self.updateTransforms();
_ = deltaTime; _ = deltaTime;
} }
@ -392,7 +409,6 @@ pub const SceneSystem = struct {
pub fn deinit(self: *@This()) void { pub fn deinit(self: *@This()) void {
self.dynamicObjects.deinit(self.allocator); self.dynamicObjects.deinit(self.allocator);
self.childrenArena.deinit(); self.childrenArena.deinit();
// core.undefineComponent(Scene);
Scene.SceneObjectContainer.destroy(); Scene.SceneObjectContainer.destroy();
self.allocator.destroy(self); self.allocator.destroy(self);
} }

View File

@ -3,6 +3,7 @@ pub const list = [_][]const u8{
"platform", "platform",
"assets", "assets",
"audio", "audio",
"net",
"physics", "physics",
"rend", "rend",

35
engine/net/build.zig Normal file
View File

@ -0,0 +1,35 @@
const std = @import("std");
const depList = [_][]const u8{
"core",
};
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
const mod = b.addModule("net", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("src/net.zig"),
});
for (depList) |depName| {
const dep = b.dependency(depName, .{ .target = target, .optimize = optimize, .static_build = static_build });
mod.addImport(depName, dep.module(depName));
}
const test_step = b.step("test", "run unit tests for net");
const tests = b.addTest(.{
.target = target,
.optimize = optimize,
.root_source_file = b.path("tests/tests.zig"),
});
tests.root_module.addImport("net", mod);
const runArtifact = b.addRunArtifact(tests);
test_step.dependOn(&runArtifact.step);
b.installArtifact(tests);
}

10
engine/net/build.zig.zon Normal file
View File

@ -0,0 +1,10 @@
.{
.name = .net,
.version = "0.0.0",
.dependencies = .{
.core = .{ .path = "../core" },
},
.paths = .{
"",
},
}

33
engine/net/src/net.zig Normal file
View File

@ -0,0 +1,33 @@
const core = @import("core");
const std = @import("std");
const netEngine = @import("netEngine.zig");
pub const NetEngine = netEngine.NetEngine;
pub const net_err = netEngine.net_err;
pub const net_errs = netEngine.net_errs;
pub const net_log = netEngine.net_log;
pub const net_logs = netEngine.net_logs;
pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void {
_ = args;
_ = spec;
_ = allocator;
if (core.isUtility()) {
return;
}
_ = core.createObject(NetEngine, .{ .can_tick = true }) catch unreachable;
}
pub fn shutdown_module(allocator: std.mem.Allocator) void {
core.get(NetEngine).shutdown();
_ = allocator;
}
pub const context = core.EngineObject(NetEngine).get;
pub const Module = core.ModuleDescription{
.name = "net",
.enabledByDefault = false,
};

View File

@ -0,0 +1,49 @@
const core = @import("core");
const std = @import("std");
pub fn net_log(comptime fmt: []const u8, args: anytype) void {
core.printInner("[NET ]: " ++ fmt ++ "\n", args);
}
pub fn net_logs(comptime fmt: []const u8) void {
core.printInner("[NET ]: " ++ fmt ++ "\n", .{});
}
pub fn net_err(comptime fmt: []const u8, args: anytype) void {
core.printInner("[NET ]: ERROR!! " ++ fmt ++ "\n", args);
}
pub fn net_errs(comptime fmt: []const u8) void {
core.printInner("[NET ]: ERROR!! " ++ fmt ++ "\n", .{});
}
pub const NetEngine = struct {
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "net.NetEngine");
allocator: std.mem.Allocator,
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
self.* = @This(){
.allocator = allocator,
};
net_logs("NetEngine initialized");
return self;
}
pub fn shutdown(self: *@This()) void {
net_logs("NetEngine shutting down");
_ = self;
}
pub fn deinit(self: *@This()) void {
self.allocator.destroy(self);
}
pub fn tick(self: *@This(), deltaTime: f64) void {
_ = self;
_ = deltaTime;
// Network tick logic will go here
}
};

View File

@ -119,7 +119,7 @@ pub fn resolve(self: *@This()) void {
base = mul(core.zm.rotationX(self.pitch), base); base = mul(core.zm.rotationX(self.pitch), base);
base = mul(core.zm.rotationZ(self.roll), base); base = mul(core.zm.rotationZ(self.roll), base);
var posRot: core.scene.SceneObjectPosRot = .{ var posRot: core.scene.ScenePosRot = .{
.rotation = scene.getRotation(), .rotation = scene.getRotation(),
.position = scene.getPosition(), .position = scene.getPosition(),
}; };

View File

@ -0,0 +1,84 @@
allocator: std.mem.Allocator,
selectedObjectToSpawn: ?core.Name = null,
spawnedObjects: std.ArrayListUnmanaged(core.Entity) = .{},
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "extras.ObjectSystemSpawner");
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
self.* = .{ .allocator = allocator };
if (core.getEngineObject(igu.TopBar)) |topbar| {
topbar.addMenuObject(self, "New Object Spawner") catch {};
}
return self;
}
// spawns an arbitrary object, no type acquisition here
pub fn spawnObjectAt(self: *@This(), spawnPosRot: core.ScenePosRot) ?core.Entity {
if (self.selectedObjectToSpawn == null)
return null;
const objectSystem: *core.GameObjectSystem = core.get(core.GameObjectSystem);
const r = objectSystem.spawnObjectFromTableByName(&self.selectedObjectToSpawn.?, .{ .posRot = spawnPosRot }) catch return null;
self.spawnedObjects.append(self.allocator, r.entity) catch return null;
return r.entity;
}
pub fn windowOpen(entry: *igu.MenuEntry, dt: f64) void {
const self: *@This() = @ptrCast(@alignCast(entry.ctx));
_ = dt;
const object = core.getEngineObject(core.GameObjectSystem).?;
if (ig.begin("ObjectSystemSpawner", null, .{})) {
if (self.selectedObjectToSpawn) |*selected| {
ig.textf("now spawning : {s}", .{selected.utf8()});
} else {
ig.textf("click an object to spawn", .{});
}
var buf: [256]u8 = undefined;
var i = object.objectDefinitions.iterator();
while (i.next()) |v| {
const x = std.fmt.bufPrintZ(&buf, "spawn##{d}", .{v.value_ptr.objectBaseName.handle()}) catch unreachable;
ig.textf("{s}", .{v.value_ptr.objectBaseName.utf8()});
ig.sameLine(0, 10);
if (ig.smallButton(x)) {
self.selectedObjectToSpawn = v.value_ptr.objectBaseName;
}
}
ig.separator();
var destroyed: ?usize = null;
for (self.spawnedObjects.items, 0..) |entity, j| {
const x = std.fmt.bufPrintZ(&buf, "delete {d}", .{entity.handle.index}) catch unreachable;
if (ig.smallButton(x)) {
entity.destroy();
destroyed = j;
}
}
if (destroyed) |destroyedIndex| {
_ = self.spawnedObjects.orderedRemove(destroyedIndex);
}
}
ig.end();
}
pub fn destroy(self: *@This()) void {
self.spawnedObjects.deinit(self.allocator);
self.allocator.destroy(self);
}
const backlog = @import("Backlog");
const core = backlog.core;
const rend = backlog.rend;
const ig = backlog.imgui.api;
const igu = backlog.imgui.utils;
const std = @import("std");

View File

@ -3,6 +3,7 @@ pub const games = @import("gameplay/games.zig");
pub const inputDebugger = @import("debuggers/inputDebugger.zig"); pub const inputDebugger = @import("debuggers/inputDebugger.zig");
pub const ObjectSpawner = @import("debuggers/objectSpawner.zig"); pub const ObjectSpawner = @import("debuggers/objectSpawner.zig");
pub const ObjectSystemSpawner = @import("debuggers/objectSystemSpawner.zig");
pub const RendererDebug = @import("debuggers/RendererDebug.zig"); pub const RendererDebug = @import("debuggers/RendererDebug.zig");
pub const EngineTool = @import("debuggers/EngineTool.zig"); pub const EngineTool = @import("debuggers/EngineTool.zig");
pub const PhysicsObjectList = @import("debuggers/PhysicsObjectList.zig"); pub const PhysicsObjectList = @import("debuggers/PhysicsObjectList.zig");
@ -14,8 +15,9 @@ pub fn setup() !void {
_ = try core.createObject(games.GameList, .{}); _ = try core.createObject(games.GameList, .{});
} }
pub const GameModeMessage = games.GameModeMessage;
pub const GameModeState = games.GameModeState;
pub const getGame = games.getGame; pub const getGame = games.getGame;
pub const beginGame = games.beginGame; pub const beginGame = games.beginGame;
pub const endGame = games.endGame; pub const endGame = games.endGame;
pub const unloadGame = games.unloadGame; pub const unloadGame = games.unloadGame;

View File

@ -0,0 +1,121 @@
// games are a
pub const GameInterface = struct {
ptr: *anyopaque,
beginPlayFn: *const fn (*anyopaque) void,
endPlayFn: *const fn (*anyopaque) void,
gameName: core.Name,
tags: std.ArrayListUnmanaged(core.Name) = .{},
pub fn beginPlay(self: @This()) void {
self.beginPlayFn(self.ptr);
}
pub fn endPlay(self: @This()) void {
self.endPlayFn(self.ptr);
}
};
pub const GameList = struct {
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "extras.GameList");
allocator: std.mem.Allocator,
games: std.StringHashMapUnmanaged(*GameInterface) = .{},
gamesByTag: std.AutoHashMapUnmanaged(u32, GameInterfaceList) = .{},
gamesLinear: GameInterfaceList = .{},
const GameInterfaceList = std.ArrayListUnmanaged(*GameInterface);
pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
self.* = .{
.allocator = allocator,
};
return self;
}
pub fn registerGame(self: *@This(), gameName: []const u8, p: *anyopaque, comptime InnerType: type) !void {
const interface = try self.allocator.create(GameInterface);
interface.* = .{
.ptr = p,
.beginPlayFn = InnerType.beginPlay,
.endPlayFn = InnerType.endPlay,
.gameName = core.MakeName(gameName),
};
try self.games.put(self.allocator, gameName, interface);
try self.gamesLinear.append(self.allocator, interface);
}
pub fn setGameTag(self: *@This(), gameName: []const u8, name: []const u8) void {
var n = core.MakeName(name);
(self.gamesByTag.getOrPut(gameName) catch unreachable).append(n.handle()) catch unreachable;
}
pub fn removeTag(self: *@This(), game: []const u8, tag: []const u8) void {
var tagName = core.MakeName(tag);
var gameName = core.MakeName(game);
if (self.gamesByTag.getPtr(tagName.handle())) |list| {
for (list.items) |i| {
if (i.gameName.eql(&gameName)) {
list.swapRemove(i);
return;
}
}
}
}
pub fn destroy(self: *@This()) void {
var iter = self.games.valueIterator();
while (iter.next()) |i| {
self.allocator.destroy(i.*);
}
self.gamesLinear.deinit(self.allocator);
self.gamesByTag.deinit(self.allocator);
self.games.deinit(self.allocator);
self.allocator.destroy(self);
}
};
pub fn beginGame(name: []const u8) void {
getGame(name).beginPlay();
}
pub fn endGame(name: []const u8) void {
getGame(name).endPlay();
}
pub fn getGame(name: []const u8) *GameInterface {
core.engine_log("getting Game {s}", .{name});
return core.EngineObject(GameList).get().games.get(name).?;
}
pub fn addGame(name: []const u8, p: *anyopaque, comptime T: type) !void {
core.engine_log("setting Game {s}", .{name});
try core.EngineObject(GameList).get().registerGame(name, p, T);
}
pub const GameModeState = enum {
dead,
prepare,
playing,
paused,
};
pub const GameModeMessage = struct {
gameModeName: []const u8,
gameModeRef: ?*anyopaque = null,
gameModeStatus: GameModeState = .dead,
};
const std = @import("std");
const backlog = @import("Backlog");
const core = backlog.core;

View File

@ -116,7 +116,6 @@ pub const BumpArena = struct {
self.large.reset(.free_all); self.large.reset(.free_all);
self.small.reset(self.backing); self.small.reset(self.backing);
self.smallBumpOffset = 0; self.smallBumpOffset = 0;
self.latestPageFree = PageSize;
self.pageIndex = 0; self.pageIndex = 0;
} }
}; };

View File

@ -22,6 +22,7 @@ pub fn build(b: *std.Build) void {
sampleGame.setModuleEnabled("physics", true); sampleGame.setModuleEnabled("physics", true);
sampleGame.setModuleEnabled("ui", true); sampleGame.setModuleEnabled("ui", true);
sampleGame.setModuleEnabled("sys", true); sampleGame.setModuleEnabled("sys", true);
sampleGame.setModuleEnabled("net", true);
sampleGame.addExtraModule("gameExtras"); sampleGame.addExtraModule("gameExtras");
sampleGame.addExtraModule("videoplayer"); sampleGame.addExtraModule("videoplayer");
sampleGame.addExtraModule("doomplayer"); sampleGame.addExtraModule("doomplayer");
@ -32,14 +33,9 @@ pub fn build(b: *std.Build) void {
_ = externGame.compileInstall(); _ = externGame.compileInstall();
} }
sampleGame.setIconPath("icons/icon.ico");
const sampleGameExe = sampleGame.compileInstall(); const sampleGameExe = sampleGame.compileInstall();
_ = sampleGameExe;
if (target.result.os.tag == .windows) {
sampleGameExe.addWin32ResourceFile(.{
.file = b.path("sampleGame/sampleGame.rc"),
.flags = &.{},
});
}
// tools // tools

View File

@ -42,6 +42,54 @@ pub fn start_module(args: core.ModuleLoaderArgs) !void {
core.PatchStruct(ExternGameObject, @ptrCast(@alignCast(ref.ptr)), ref.vtable.fieldList.?); core.PatchStruct(ExternGameObject, @ptrCast(@alignCast(ref.ptr)), ref.vtable.fieldList.?);
} }
pub const BoxObject = struct {
playing: bool = false,
pub fn create(allocator: std.mem.Allocator, entity: core.Entity, params: core.SpawnParameters) !*@This() {
const position = params.posRot.position;
const box2 = entity;
const scene = box2.addComponent(core.Scene).?;
const mesh = box2.addComponent(rend.MeshComponent).?;
mesh.setMesh("m_crate");
mesh.setTexture("t_crate");
scene.setPosition(position);
scene.setScaleV(params.posRot.scale);
scene.setMobility(.moveable);
const collider = box2.addComponent(physics.PhysicsCollider).?;
try collider.setupByShapeName(core.MakeName("ph_small_box"), .{
.motion_type = .dynamic,
.object_layer = physics.ObjectLayers.moving,
.friction = 0.8,
.mass_properties_override = .{ .mass = 12 },
.override_mass_properties = .calc_inertia,
});
return try allocator.create(@This());
}
pub fn createSmoky(allocator: std.mem.Allocator, entity: core.Entity, params: core.SpawnParameters) !*@This() {
const rv = try create(allocator, entity, params);
const particle = entity.addComponent(rend.ParticleEmitter).?;
particle.start();
particle.gravity = .{ .y = 1.0 };
particle.particleVelocity = .{ .min = 0.6, .max = 1.2 };
particle.particleLife = .{ .min = 5, .max = 6 };
var name = core.MakeName("t_pixelSmoke");
particle.texture = rend.getTexture(&name).?;
return rv;
}
pub fn destroy(self: *@This(), alloc: std.mem.Allocator) void {
alloc.destroy(self);
}
};
pub const ExternGameObject = struct { pub const ExternGameObject = struct {
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "game.ExternGameObject"); pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "game.ExternGameObject");
pub const Slack = core.SlackStruct(@This(), 512); pub const Slack = core.SlackStruct(@This(), 512);
@ -58,6 +106,8 @@ pub const ExternGameObject = struct {
//lmao2: bool = true, //lmao2: bool = true,
// lib: bool = false, // lib: bool = false,
//s: u32 = 0x42, //s: u32 = 0x42,
//
firstTick: bool = true,
fireInput: ?*core.ActionBinding = null, fireInput: ?*core.ActionBinding = null,
altFireInput: ?*core.ActionBinding = null, altFireInput: ?*core.ActionBinding = null,
@ -68,6 +118,8 @@ pub const ExternGameObject = struct {
Anormal: core.Vector2f = .{ .x = -1, .y = 3 }, Anormal: core.Vector2f = .{ .x = -1, .y = 3 },
Bnormal: core.Vector2f = .{ .x = -1, .y = -3 }, Bnormal: core.Vector2f = .{ .x = -1, .y = -3 },
spawnedEntities: std.ArrayListUnmanaged(core.Entity) = .{},
displayVectorsTest: bool = false, displayVectorsTest: bool = false,
pub fn beginPlay(p: *anyopaque) void { pub fn beginPlay(p: *anyopaque) void {
@ -126,6 +178,9 @@ pub const ExternGameObject = struct {
self.physicsObjectsWindow = try extras.PhysicsObjectList.create(self.allocator); self.physicsObjectsWindow = try extras.PhysicsObjectList.create(self.allocator);
self.consoleWindow.setup(); self.consoleWindow.setup();
try core.registerObject(BoxObject, "Box");
try core.registerObjectAdvanced(BoxObject, "BoxSmoky", "createSmoky");
const settings: physics.ShapeSettings = .{ .box = try physics.BoxShapeSettings.create(.{ 1.0, 1.0, 1.0 }) }; const settings: physics.ShapeSettings = .{ .box = try physics.BoxShapeSettings.create(.{ 1.0, 1.0, 1.0 }) };
defer settings.release(); defer settings.release();
try physics.addShape("ph_small_box", settings); try physics.addShape("ph_small_box", settings);
@ -238,36 +293,6 @@ pub const ExternGameObject = struct {
core.debugSphere(v2ToV3(vp), 0.1, .{ .color = .{ .y = 1.0, .z = 1.0, .x = 1.0 } }); core.debugSphere(v2ToV3(vp), 0.1, .{ .color = .{ .y = 1.0, .z = 1.0, .x = 1.0 } });
} }
pub fn addBox(position: core.Vectorf) !void {
const box2 = try core.createEntity();
const scene = box2.addComponent(core.Scene).?;
const mesh = box2.addComponent(rend.MeshComponent).?;
mesh.setMesh("m_crate");
mesh.setTexture("t_crate");
scene.setPosition(position);
scene.setScaleV(core.Vectorf.fromInt(1.0));
scene.setMobility(.moveable);
const collider = box2.addComponent(physics.PhysicsCollider).?;
try collider.setupByShapeName(core.MakeName("ph_small_box"), .{
.motion_type = .dynamic,
.object_layer = physics.ObjectLayers.moving,
.friction = 0.8,
.mass_properties_override = .{ .mass = 12 },
.override_mass_properties = .calc_inertia,
});
const particle = box2.addComponent(rend.ParticleEmitter).?;
particle.start();
particle.gravity = .{ .y = 1.0 };
particle.particleVelocity = .{ .min = 0.6, .max = 1.2 };
particle.particleLife = .{ .min = 5, .max = 6 };
var name = core.MakeName("t_pixelSmoke");
particle.texture = rend.getTexture(&name).?;
}
fn onAltFire(ctx: ?*anyopaque, _: core.ActionEvent) void { fn onAltFire(ctx: ?*anyopaque, _: core.ActionEvent) void {
const self: *@This() = @ptrCast(@alignCast(ctx)); const self: *@This() = @ptrCast(@alignCast(ctx));
@ -295,9 +320,14 @@ pub const ExternGameObject = struct {
const ray = rend.context().activeCamera.?.getNormalRayFromScreen(platform.getCursorPosition()); const ray = rend.context().activeCamera.?.getNormalRayFromScreen(platform.getCursorPosition());
if (physics.traceLine(ray.start, ray.dir.fmul(10000), .{ .bodyFilter = &self.fireTraceFilter, .getNormalsSlow = true })) |r| { if (physics.traceLine(ray.start, ray.dir.fmul(10000), .{ .bodyFilter = &self.fireTraceFilter, .getNormalsSlow = true })) |r| {
if (r.normal) |n| { if (r.normal) |n| {
const p = r.point.add(n.fmul(0.2)); const p: core.Vectorf = r.point.add(n.fmul(0.2));
addBox(p.add(n.fmul(1.0))) catch unreachable; const posRot = core.ScenePosRot{
.position = p,
};
self.spawnedEntities.append(self.allocator, core.get(extras.ObjectSystemSpawner).spawnObjectAt(posRot) orelse return) catch unreachable;
// addBox(p.add(n.fmul(1.0))) catch unreachable;
} }
} }
} }
@ -316,6 +346,11 @@ pub const ExternGameObject = struct {
self.drawVector2Test(); self.drawVector2Test();
} }
if (self.firstTick) {
self.loadMap2() catch unreachable;
self.firstTick = false;
}
if (platform.context().isCursorEnabled()) { if (platform.context().isCursorEnabled()) {
if (ig.begin("meh", null, .{})) { if (ig.begin("meh", null, .{})) {
// if (ig.checkbox("move lights ", null)) {} // if (ig.checkbox("move lights ", null)) {}
@ -372,6 +407,11 @@ pub const ExternGameObject = struct {
if (self.tbMap) |map| { if (self.tbMap) |map| {
map.destroy(); map.destroy();
} }
for (self.spawnedEntities.items) |*entity| {
entity.destroy();
}
self.spawnedEntities.deinit(self.allocator);
self.consoleWindow.deinit(); self.consoleWindow.deinit();
self.physicsObjectsWindow.destroy(); self.physicsObjectsWindow.destroy();
self.allocator.destroy(Slack.fromPtr(self)); self.allocator.destroy(Slack.fromPtr(self));

View File

@ -154,15 +154,23 @@ pub const ParticleObject = struct {
}; };
pub const FoxObject = struct { pub const FoxObject = struct {
data: core.GameObjectData = undefined,
entity: core.Entity, entity: core.Entity,
pub fn create(alloc: std.mem.Allocator) !*@This() { pub const MessageHandlers: []const []const u8 = &.{
"onGameModeMessage",
};
pub fn create(alloc: std.mem.Allocator, entity: core.Entity, p: core.SpawnParameters) !*@This() {
const self = try alloc.create(@This()); const self = try alloc.create(@This());
const fox = try core.createEntity(); //const fox = try core.createEntity();
const fox = entity;
const scene = fox.addComponent(core.Scene).?; const scene = fox.addComponent(core.Scene).?;
scene.setScale(0.01, 0.01, 0.01); var pr = p.posRot;
pr.scale = pr.scale.fmul(0.01);
scene.setPosRot(pr);
scene.updateTransform();
const mesh = fox.addComponent(rend.MeshComponent).?; const mesh = fox.addComponent(rend.MeshComponent).?;
mesh.setMesh("m_fox"); mesh.setMesh("m_fox");
mesh.setTexture("t_fox"); mesh.setTexture("t_fox");
@ -176,13 +184,19 @@ pub const FoxObject = struct {
return self; return self;
} }
pub fn onGameModeMessage(self: *@This(), messageInfo: *const core.MessageInfo, gameModeMessage: *extras.GameModeMessage) void {
_ = self;
_ = messageInfo;
_ = gameModeMessage;
}
pub fn getEntity(self: *@This()) core.Entity { pub fn getEntity(self: *@This()) core.Entity {
return self.entity; return self.entity;
} }
pub fn destroy(self: *@This()) void { pub fn destroy(self: *@This(), allocator: std.mem.Allocator) void {
self.entity.destroy(); allocator.destroy(self);
self.data.release(self); core.engine_logs("destroying fox");
} }
}; };
@ -249,19 +263,23 @@ pub fn prepare(self: *@This()) !void {
// core.fs().watchPath("zig-out/modules"); // core.fs().watchPath("zig-out/modules");
// try core.fs().addFileChangedCallback(core.sharedLibName("externGame"), moduleChangedCallback, self); // try core.fs().addFileChangedCallback(core.sharedLibName("externGame"), moduleChangedCallback, self);
// self.rendererDebugger = try extras.RendererDebug.create(self.allocator); //try core.createObject(extras.RendererDebug, .{});
const rendererDebug = try core.createObject(extras.RendererDebug, .{}); const rendererDebug = try core.createObject(extras.RendererDebug, .{});
try rendererDebug.skyboxes.append(rendererDebug.allocator, core.MakeName("t_skybox")); try rendererDebug.skyboxes.append(rendererDebug.allocator, core.MakeName("t_skybox"));
try rendererDebug.skyboxes.append(rendererDebug.allocator, core.MakeName("t_dark_skybox")); try rendererDebug.skyboxes.append(rendererDebug.allocator, core.MakeName("t_dark_skybox"));
const objectSpawner2 = try core.createObject(extras.ObjectSystemSpawner, .{});
_ = objectSpawner2;
//self.objectSpawner = try extras.ObjectSpawner.create(self.allocator); //self.objectSpawner = try extras.ObjectSpawner.create(self.allocator);
self.objectSpawner = try core.createObject(extras.ObjectSpawner, .{}); self.objectSpawner = try core.createObject(extras.ObjectSpawner, .{});
try self.objectSpawner.addSpawnFunction("fox", FoxObject); // try self.objectSpawner.addSpawnFunction("fox", FoxObject);
try self.objectSpawner.addSpawnFunction("particle", ParticleObject); try self.objectSpawner.addSpawnFunction("particle", ParticleObject);
try self.objectSpawner.addSpawnFunction("doomplayer", DoomPlayer.DoomCanvas); try self.objectSpawner.addSpawnFunction("doomplayer", DoomPlayer.DoomCanvas);
try self.objectSpawner.addSpawnFunction("empire", @import("empire.zig")); try self.objectSpawner.addSpawnFunction("empire", @import("empire.zig"));
try self.objectSpawner.addSpawnFunction("DamagedHelmet", DamagedHelmet); try self.objectSpawner.addSpawnFunction("DamagedHelmet", DamagedHelmet);
try core.getEngineObject(core.GameObjectSystem).?.registerObject("foxObject", FoxObject);
try assets.loadList(assetReferences); try assets.loadList(assetReferences);
// self.videoplayer = try VideoPlayer.create(self.allocator); // self.videoplayer = try VideoPlayer.create(self.allocator);
// try self.videoplayer.startPlayback("LAPWING2.ogv"); // try self.videoplayer.startPlayback("LAPWING2.ogv");