hotreload hardening

This commit is contained in:
peterino2 2025-10-02 13:42:47 -07:00
parent 5975ac0585
commit 402704bf4f
7 changed files with 139 additions and 4 deletions

View File

@ -74,7 +74,20 @@ pub fn PatchStruct(comptime T: type, p: *T, old: []const FieldInfo) void {
dest.ptr = @ptrCast(&@field(new, field.name));
dest.len = @sizeOf(@TypeOf(@field(new, field.name)));
std.debug.print(
"patching field {s} {d} bytes {d} -> {d} {s}\n",
.{
field.name,
src.len,
of.offset,
@offsetOf(T, field.name),
if (of.offset == @offsetOf(T, field.name)) "" else "change!",
},
);
std.mem.copyForwards(u8, dest, src);
} else {
std.debug.print("new field added {s}", .{field.name});
}
}

View File

@ -545,8 +545,16 @@ pub const BindingLayer = struct {
pub fn removeBindingByName(self: *@This(), _name: core.Name) void {
var name = _name;
_ = self.bindingStack.orderedRemove(self.bindingsByName.get(name.handle()).?);
const index = self.bindingsByName.get(name.handle()).?;
_ = self.bindingStack.orderedRemove(index);
_ = self.bindingsByName.remove(name.handle());
var iter = self.bindingsByName.valueIterator();
while (iter.next()) |next| {
if (next.* > index) {
next.* -= 1;
}
}
}
pub fn destroy(self: *@This()) void {

View File

@ -23,6 +23,7 @@ pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.me
pub fn setupFromModule() void {
const impl = core.getEngineObject(Impl).?;
api.setCurrentContext(impl.context);
api.setBeginCount(&impl.beginCount);
}
pub fn shutdown_module(allocator: std.mem.Allocator) void {

View File

@ -6,6 +6,8 @@ pub const Impl = struct {
rendererDebug: bool = true,
context: *ig.Context = undefined,
beginCount: u32 = 0,
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "imgui.BackendImpl");
pub const Settings = struct {
@ -32,6 +34,11 @@ pub const Impl = struct {
try platform.getInstance().addSDLProcessFunction(processSDLEvents);
self.context = ig.getCurrentContext().?;
self.setupBeginCount();
}
pub fn setupBeginCount(self: *@This()) void {
ig.setBeginCount(&self.beginCount);
}
pub fn processSDLEvents(event: *sdl3.Event) void {
@ -44,6 +51,16 @@ pub const Impl = struct {
const self: *@This() = @ptrCast(@alignCast(p));
platform.context().imguiMouseConsumed = ig.isWindowHovered(.{ .any_window = true });
const count = self.beginCount;
while (self.beginCount > 0) {
ig.end();
}
if (count > 0) {
_ = ig.begin("error", null, .{});
ig.textf("IMGUI ERORR", .{});
core.engine_logs("error");
ig.end();
}
ig.render();
if (platform.getInstance().imguiVisible) {
@ -76,11 +93,12 @@ pub const Impl = struct {
}
pub fn preTick(self: *@This(), dt: f64) core.EngineDataEventError!void {
_ = self;
c.Imgui_SDL3_NewFrame();
c.igNewFrame();
_ = ig.dockSpaceOverViewport(ig.getMainViewport(), .{ .passthru_central_node = true }, null);
_ = self;
_ = dt;
}

View File

@ -2388,12 +2388,28 @@ pub inline fn styleColorsLight(dst: [*c]Style) void { //igStyleColorsLight
pub inline fn styleColorsClassic(dst: [*c]Style) void { //igStyleColorsClassic
c.igStyleColorsClassic(dst);
}
pub var gBeginCount: *u32 = undefined;
pub fn setBeginCount(beginCount: *u32) void {
gBeginCount = beginCount;
}
pub inline fn begin(name: [*c]const u8, p_open: [*c]bool, flags: WindowFlags) bool { //igBegin
gBeginCount.* += 1;
return c.igBegin(name, p_open, @bitCast(flags));
}
pub inline fn end() void { //igEnd
gBeginCount.* -= 1;
c.igEnd();
}
pub fn checkIgEnd() void {
while (gBeginCount.* > 0) {
end();
}
}
pub inline fn beginChild_Str(str_id: [*c]const u8, size: Vec2, border: bool, flags: WindowFlags) bool { //igBeginChild_Str
return c.igBeginChild_Str(str_id, @bitCast(size), border, @bitCast(flags));
}

View File

@ -38,9 +38,11 @@ pub fn start_module(args: core.ModuleLoaderArgs) !void {
//log("gonna try something dumb- lets patch the vtable of that old object with my vtable's values", .{});
const ref = core.getEngineObjectRef(ExternGameObject).?;
const vtable: *core.EngineObjectVTable = @constCast(ref.vtable);
vtable.* = ExternGameObject.NeonObjectTable;
core.PatchStruct(ExternGameObject, @ptrCast(@alignCast(ref.ptr)), ref.vtable.fieldList.?);
vtable.* = ExternGameObject.NeonObjectTable;
core.get(ExternGameObject).onHotReload();
}
pub const BoxObject = struct {
@ -93,7 +95,7 @@ pub const BoxObject = struct {
pub const ExternGameObject = struct {
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "game.ExternGameObject");
pub const Slack = core.SlackStruct(@This(), 512);
pub const Slack = core.SlackStruct(@This(), 1024);
allocator: std.mem.Allocator = undefined,
consoleWindow: imgui.utils.ConsoleWindow = undefined,
@ -105,7 +107,12 @@ pub const ExternGameObject = struct {
session: ?*net.Session = null,
clientLink: ?*net.Link = null,
recompiling: bool = false,
volume: f32 = 100,
volume2: f64 = 100,
volume4: f64 = 100,
newBool: bool = true,
new2Bool: bool = true,
//lmao: bool = false,
//lmao2: bool = true,
// lib: bool = false,
@ -113,8 +120,11 @@ pub const ExternGameObject = struct {
//
firstTick: bool = true,
frameCount: u32 = 0,
fireInput: ?*core.ActionBinding = null,
altFireInput: ?*core.ActionBinding = null,
reloadInput: ?*core.ActionBinding = null,
a: core.Vector2f = .{ .x = 1, .y = 4 },
b: core.Vector2f = .{ .x = 4, .y = 1 },
@ -134,6 +144,28 @@ pub const ExternGameObject = struct {
}
pub fn _beginPlay(self: *@This()) !void {
try self.setupInputs();
}
pub fn setupInputs(self: *@This()) !void {
if (self.fireInput) |fireInput| {
fireInput.deactivate();
}
if (self.altFireInput) |altFireInput| {
altFireInput.deactivate();
}
if (self.reloadInput) |input| {
input.deactivate();
}
if (self.reloadInput == null) {
self.reloadInput = try core.ActionBinding.create(core.MakeName("input"));
self.reloadInput.?.addKey(.@"9", .keyDown);
_ = self.reloadInput.?.data.addListener(self, onRequestReload);
}
self.reloadInput.?.activate();
if (self.fireInput == null) {
self.fireInput = try core.ActionBinding.create(core.MakeName("fire"));
self.fireInput.?.addKey(.Mouse1, .keyDown);
@ -149,6 +181,12 @@ pub const ExternGameObject = struct {
self.altFireInput.?.activate();
}
pub fn onHotReload(self: *@This()) void {
self.setupInputs() catch {
core.engine_errs("Unable to setup inputs");
};
}
pub fn endPlay(p: *anyopaque) void {
const self = core.cast(*@This(), p);
self.fireInput.?.deactivate();
@ -297,6 +335,37 @@ pub const ExternGameObject = struct {
core.debugSphere(v2ToV3(vp), 0.1, .{ .color = .{ .y = 1.0, .z = 1.0, .x = 1.0 } });
}
pub fn recompileComplete(ctx: ?*anyopaque) void {
const self = core.cast(*@This(), ctx.?);
self.recompiling = false;
}
fn onRequestReload(ctx: ?*anyopaque, _: core.ActionEvent) void {
const self = core.cast(*@This(), ctx.?);
if (!self.recompiling) {
self.recompiling = true;
const x = core.EngineObject(sys.SystemRunner).get();
x.commandQueue.pushLocked(.{
.subprocess = .{
.context = self,
.onComplete = recompileComplete,
.task = sys.SubprocessTask.runCommand(
x.allocator,
&.{ "zig", "build", "install" },
".",
) catch {
self.recompiling = false;
return;
},
},
}) catch {
self.recompiling = false;
return;
};
}
}
fn onAltFire(ctx: ?*anyopaque, _: core.ActionEvent) void {
const self: *@This() = @ptrCast(@alignCast(ctx));
@ -355,6 +424,15 @@ pub const ExternGameObject = struct {
self.firstTick = false;
}
imgui.utils.structDebugWindow(self);
if (self.recompiling) {
if (ig.begin("recompiling", null, .{})) {
ig.textf("recompiling...", .{});
}
ig.end();
}
if (platform.context().isCursorEnabled()) {
if (ig.begin("meh", null, .{})) {
// if (ig.checkbox("move lights ", null)) {}

View File

@ -170,6 +170,7 @@ pub const FoxObject = struct {
pr.scale = pr.scale.fmul(0.01);
scene.setPosRot(pr);
scene.updateTransform();
scene.setMobility(.moveable);
const mesh = fox.addComponent(rend.MeshComponent).?;
mesh.setMesh("m_fox");