From 3eb5c336607197ef80df3cd4a5bc787ef4244957 Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Sun, 1 Oct 2023 14:06:36 +0530 Subject: [PATCH] fix memory leaks caused by world not being properly disposed --- src/DtsObject.hx | 1 + src/InstanceManager.hx | 27 ++++++++++++++++++--------- src/MarbleGame.hx | 14 +++++++++++--- src/MarbleWorld.hx | 16 ++++++++++++++++ 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/DtsObject.hx b/src/DtsObject.hx index f300af95..d51100cd 100644 --- a/src/DtsObject.hx +++ b/src/DtsObject.hx @@ -1544,6 +1544,7 @@ class DtsObject extends GameObject { public override function dispose() { super.dispose(); + this.level = null; this.dtsResource.release(); } } diff --git a/src/InstanceManager.hx b/src/InstanceManager.hx index c68669ad..9f87447d 100644 --- a/src/InstanceManager.hx +++ b/src/InstanceManager.hx @@ -20,16 +20,25 @@ import h3d.scene.MeshBatch; import src.MarbleGame; import src.ProfilerUI; -typedef MeshBatchInfo = { +@:publicFields +class MeshBatchInfo { var instances:Array; var meshbatch:MeshBatch; - var ?transparencymeshbatch:MeshBatch; + var transparencymeshbatch:MeshBatch; var mesh:Mesh; + + public function new() {} } -typedef MeshInstance = { +@:publicFields +class MeshInstance { var emptyObj:Object; var gameObject:GameObject; + + public function new(eo, go) { + this.emptyObj = eo; + this.gameObject = go; + } } class InstanceManager { @@ -152,7 +161,7 @@ class InstanceManager { var objs = getAllChildren(object); var minfos = objects[objectMap.get(object.identifier)]; // objects.get(object.identifier); for (i in 0...objs.length) { - minfos[i].instances.push({emptyObj: objs[i], gameObject: object}); + minfos[i].instances.push(new MeshInstance(objs[i], object)); } } else { // First time appending the thing so bruh @@ -161,11 +170,11 @@ class InstanceManager { var minfos = []; for (obj in objs) { var isMesh = obj is Mesh; - var minfo:MeshBatchInfo = { - instances: [{emptyObj: obj, gameObject: object}], - meshbatch: isMesh ? new MeshBatch(cast(cast(obj, Mesh).primitive), cast(cast(obj, Mesh)).material.clone(), scene) : null, - mesh: isMesh ? cast obj : null - } + var minfo:MeshBatchInfo = new MeshBatchInfo(); + minfo.instances = [new MeshInstance(obj, object)]; + minfo.meshbatch = isMesh ? new MeshBatch(cast(cast(obj, Mesh).primitive), cast(cast(obj, Mesh)).material.clone(), scene) : null; + minfo.mesh = isMesh ? cast obj : null; + if (isMesh) { var mat = cast(obj, Mesh).material; var minfoshaders = []; diff --git a/src/MarbleGame.hx b/src/MarbleGame.hx index fa17ebd9..95fe000c 100644 --- a/src/MarbleGame.hx +++ b/src/MarbleGame.hx @@ -229,7 +229,8 @@ class MarbleGame { public function showPauseUI() { exitGameDlg = new ExitGameDlg((sender) -> { canvas.popDialog(exitGameDlg); - if (world.isRecording) { + var w = getWorld(); + if (w.isRecording) { MarbleGame.canvas.pushDialog(new ReplayNameDlg(() -> { quitMission(); })); @@ -240,11 +241,13 @@ class MarbleGame { @:privateAccess world.playGui.setGuiVisibility(true); canvas.popDialog(exitGameDlg); paused = !paused; - world.setCursorLock(true); + var w = getWorld(); + w.setCursorLock(true); }, (sender) -> { @:privateAccess world.playGui.setGuiVisibility(true); canvas.popDialog(exitGameDlg); - world.restart(true); + var w = getWorld(); + w.restart(true); // world.setCursorLock(true); paused = !paused; }); @@ -273,6 +276,11 @@ class MarbleGame { } } + public function getWorld() { + // So that we don't actually store this somewhere in any closure stack + return world; + } + public function quitMission() { Console.log("Quitting mission"); var watching = world.isWatching; diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index c07a8059..8f564c7a 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -1815,28 +1815,44 @@ class MarbleWorld extends Scheduler { for (interior in this.interiors) { interior.dispose(); } + interiors = null; for (pathedInteriors in this.pathedInteriors) { pathedInteriors.dispose(); } + pathedInteriors = null; for (marble in this.marbles) { marble.dispose(); } + marbles = null; for (dtsObject in this.dtsObjects) { dtsObject.dispose(); } + dtsObjects = null; for (trigger in this.triggers) { trigger.dispose(); } + triggers = null; for (soundResource in this.soundResources) { soundResource.release(); } for (textureResource in this.textureResources) { textureResource.release(); } + gems = null; if (sky != null) sky.dispose(); + instanceManager = null; + collisionWorld = null; + particleManager = null; + namedObjects = null; + shapeOrTriggerInside = null; + shapeImmunity = null; + currentCheckpoint = null; + checkpointCollectedGems = null; + marble = null; + this._disposed = true; AudioManager.stopAllSounds(); // AudioManager.playShell();