From 792f1b480a8cad2eaa50fe06a4b1b2231cd08a5c Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Mon, 2 Oct 2023 23:10:28 +0530 Subject: [PATCH] rewind fixes --- src/DtsObject.hx | 8 +- src/modes/GameMode.hx | 1 + src/modes/HuntMode.hx | 78 ++++++++++++--- src/modes/NullMode.hx | 4 + src/rewind/RewindFrame.hx | 182 +++++++++++++++++++++++----------- src/rewind/RewindManager.hx | 9 +- src/rewind/RewindableState.hx | 3 + 7 files changed, 208 insertions(+), 77 deletions(-) diff --git a/src/DtsObject.hx b/src/DtsObject.hx index 4cd6bf8c..6c42a0eb 100644 --- a/src/DtsObject.hx +++ b/src/DtsObject.hx @@ -616,11 +616,11 @@ class DtsObject extends GameObject { for (index in [i1, i2, i3]) { var vertex = vertices[index]; - hs.points.push(new Vector(vertex.x, vertex.y, vertex.z)); + hs.addPoint(vertex.x, vertex.y, vertex.z); hs.transformKeys.push(0); var normal = vertexNormals[index]; - hs.normals.push(new Vector(normal.x, normal.y, normal.z)); + hs.addNormal(normal.x, normal.y, normal.z); } hs.indices.push(hs.indices.length); @@ -667,11 +667,11 @@ class DtsObject extends GameObject { for (index in [i1, i2, i3]) { var vertex = vertices[index]; - hs.points.push(new Vector(vertex.x, vertex.y, vertex.z)); + hs.addPoint(vertex.x, vertex.y, vertex.z); hs.transformKeys.push(0); var normal = vertexNormals[index]; - hs.normals.push(new Vector(normal.x, normal.y, normal.z)); + hs.addNormal(normal.x, normal.y, normal.z); } hs.indices.push(hs.indices.length); diff --git a/src/modes/GameMode.hx b/src/modes/GameMode.hx index c1f3415a..a83a36e6 100644 --- a/src/modes/GameMode.hx +++ b/src/modes/GameMode.hx @@ -28,6 +28,7 @@ interface GameMode { public function onGemPickup(gem:Gem):Void; public function getPreloadFiles():Array; + public function constructRewindState():RewindableState; } class GameModeFactory { diff --git a/src/modes/HuntMode.hx b/src/modes/HuntMode.hx index 251b1df1..ed838fcf 100644 --- a/src/modes/HuntMode.hx +++ b/src/modes/HuntMode.hx @@ -1,5 +1,6 @@ package modes; +import rewind.RewindManager; import hxd.Rand; import rewind.RewindableState; import gui.AchievementsGui; @@ -55,14 +56,16 @@ class GemSpawnSphere { class GemOctreeElem implements IOctreeObject { public var boundingBox:Bounds; public var spawn:GemSpawnSphere; + public var spawnIndex:Int; var priority:Int; - public function new(vec:Vector, spawn:GemSpawnSphere) { + public function new(vec:Vector, spawn:GemSpawnSphere, spawnIndex:Int) { boundingBox = new Bounds(); boundingBox.addPoint(vec.add(new Vector(-0.5, -0.5, -0.5)).toPoint()); boundingBox.addPoint(vec.add(new Vector(0.5, 0.5, 0.5)).toPoint()); this.spawn = spawn; + this.spawnIndex = spawnIndex; } public function getElementType() { @@ -80,7 +83,7 @@ class GemOctreeElem implements IOctreeObject { @:publicFields class HuntState implements RewindableState { - var activeGemSpawnGroup:Array; + var activeGemSpawnGroup:Array; var activeGems:Array; var points:Int; var rngState:Int; @@ -102,6 +105,47 @@ class HuntState implements RewindableState { c.rngState2 = rngState2; return c; } + + public function getSize():Int { + var size = 2; + size += 2 + activeGemSpawnGroup.length * 2; + size += 2 + activeGems.length * 2; + size += 4; + size += 4; + size += 4; + return size; + } + + public function serialize(rm:RewindManager, bw:haxe.io.BytesOutput) { + bw.writeUInt16(points); + bw.writeUInt16(activeGemSpawnGroup.length); + for (elem in activeGemSpawnGroup) { + bw.writeUInt16(elem); + } + bw.writeUInt16(activeGems.length); + for (elem in activeGems) { + bw.writeUInt16(rm.allocGO(elem)); + } + bw.writeInt32(rngState); + bw.writeInt32(rngState2); + } + + public function deserialize(rm:RewindManager, br:haxe.io.BytesInput) { + points = br.readUInt16(); + activeGemSpawnGroup = []; + var len = br.readUInt16(); + for (i in 0...len) { + activeGemSpawnGroup.push(br.readUInt16()); + } + activeGems = []; + var len = br.readUInt16(); + for (i in 0...len) { + var uid = br.readUInt16(); + activeGems.push(cast rm.getGO(uid)); + } + rngState = br.readInt32(); + rngState2 = br.readInt32(); + } } class HuntMode extends NullMode { @@ -111,7 +155,7 @@ class HuntMode extends NullMode { var gemOctree:Octree; var gemGroupRadius:Float; var maxGemsPerGroup:Int; - var activeGemSpawnGroup:Array; + var activeGemSpawnGroup:Array; var activeGems:Array = []; var gemBeams:Array = []; var gemToBeamMap:Map = []; @@ -191,7 +235,8 @@ class HuntMode extends NullMode { override function onRespawn() { if (activeGemSpawnGroup.length != 0) { var gemAvg = new Vector(); - for (g in activeGemSpawnGroup) { + for (gi in activeGemSpawnGroup) { + var g = gemSpawnPoints[gi]; gemAvg = gemAvg.add(g.position); } gemAvg.scale(1 / activeGemSpawnGroup.length); @@ -258,9 +303,10 @@ class HuntMode extends NullMode { maxGemsPerGroup = Std.parseInt(level.mission.missionInfo.maxgemspergroup); gemOctree = new Octree(); - for (gemSpawn in gemSpawnPoints) { + for (gi in 0...gemSpawnPoints.length) { + var gemSpawn = gemSpawnPoints[gi]; var vec = gemSpawn.position; - gemOctree.insert(new GemOctreeElem(vec, gemSpawn)); + gemOctree.insert(new GemOctreeElem(vec, gemSpawn, gi)); if (gemSpawn.gem != null) { gemSpawn.gem.setHide(true); gemSpawn.gem.pickedUp = true; @@ -269,7 +315,8 @@ class HuntMode extends NullMode { } if (activeGemSpawnGroup != null) { - for (gemSpawn in activeGemSpawnGroup) { + for (gemSpawnIndex in activeGemSpawnGroup) { + var gemSpawn = gemSpawnPoints[gemSpawnIndex]; if (gemSpawn.gem != null) { gemSpawn.gem.pickedUp = true; gemSpawn.gem.setHide(true); @@ -283,7 +330,8 @@ class HuntMode extends NullMode { refillGemGroups(); var gemAvg = new Vector(); - for (g in activeGemSpawnGroup) { + for (gi in activeGemSpawnGroup) { + var g = gemSpawnPoints[gi]; gemAvg = gemAvg.add(g.position); } gemAvg.scale(1 / activeGemSpawnGroup.length); @@ -308,8 +356,9 @@ class HuntMode extends NullMode { } } - function fillGemGroup(group:Array) { - for (gemSpawn in group) { + function fillGemGroup(group:Array) { + for (gi in group) { + var gemSpawn = gemSpawnPoints[gi]; if (gemSpawn.gem != null) { gemSpawn.gem.pickedUp = false; gemSpawn.gem.setHide(false); @@ -354,7 +403,8 @@ class HuntMode extends NullMode { var ok = true; if (activeGemSpawnGroup != null) { - for (gemSpawn in activeGemSpawnGroup) { + for (gi in activeGemSpawnGroup) { + var gemSpawn = gemSpawnPoints[gi]; if (gemSpawn.position.distance(groupMainPt) < searchRadius) { ok = false; break; @@ -384,7 +434,7 @@ class HuntMode extends NullMode { var search = gemOctree.radiusSearch(pos, gemGroupRadius); for (elem in search) { var gemElem:GemOctreeElem = cast elem; - results.push(gemElem.spawn); + results.push(gemElem.spawnIndex); if (results.length >= maxGemsPerGroup) break; } @@ -481,4 +531,8 @@ class HuntMode extends NullMode { rng2.setSeed(s.rngState2); } } + + override function constructRewindState():RewindableState { + return new HuntState(); + }; } diff --git a/src/modes/NullMode.hx b/src/modes/NullMode.hx index 490796b9..5d2d78e1 100644 --- a/src/modes/NullMode.hx +++ b/src/modes/NullMode.hx @@ -103,4 +103,8 @@ class NullMode implements GameMode { } public function applyRewindState(state:RewindableState) {} + + public function constructRewindState() { + return null; + } } diff --git a/src/rewind/RewindFrame.hx b/src/rewind/RewindFrame.hx index 2b511d42..180a1c43 100644 --- a/src/rewind/RewindFrame.hx +++ b/src/rewind/RewindFrame.hx @@ -128,8 +128,13 @@ class RewindFrame { var bb = new BytesOutput(); var framesize = 0; framesize += 32; // timeState - framesize += 24; // marblePosition + framesize += 8; // rewindAcculumulator + framesize += 128; // marbleColliderTransform + framesize += 24; // marblePrevPosition + framesize += 24; // marbleNextPosition + framesize += 8; // marblePhysicsAccumulator framesize += 32; // marbleOrientation + framesize += 32; // marblePrevOrientation framesize += 24; // marbleVelocity framesize += 24; // marbleAngularVelocity framesize += 2; // marblePowerup @@ -138,16 +143,19 @@ class RewindFrame { framesize += 2 + gemStates.length * 1; // gemStates framesize += 2 + powerupStates.length * 8; // powerupStates framesize += 2 + landMineStates.length * 8; // landMineStates - framesize += 32; // activePowerupStates + framesize += 16; // activePowerupStates framesize += 24; // currentUp framesize += 24; // lastContactNormal framesize += 2; // mpStates.length for (s in mpStates) { - framesize += 8; // s.curState.currentTime - framesize += 8; // s.curState.targetTime - framesize += 24; // s.curState.velocity - framesize += 1; // s.stopped + framesize += 8; // s.currentTime + framesize += 8; // s.targetTime + framesize += 1; // Null + if (s.stoppedPosition != null) + framesize += 24; // s.stoppedPosition + framesize += 24; // s.prevPosition framesize += 24; // s.position + framesize += 24; // s.velocity } framesize += 2; // trapdoorStates.length for (s in trapdoorStates) { @@ -161,7 +169,7 @@ class RewindFrame { framesize += 32; // oobState.timeState framesize += 1; // Null if (checkpointState != null) { - framesize += 4; // checkpointState.currentCheckpoint + framesize += 2; // checkpointState.currentCheckpoint } framesize += 2; // checkpointState.currentCheckpointTrigger framesize += 2; // checkpointState.checkpointCollectedGems.length @@ -170,23 +178,48 @@ class RewindFrame { framesize += 1; // checkpointState.checkpointCollectedGems[gem] } framesize += 2; // checkpointState.checkpointHeldPowerup - framesize += 1; // Null - if (checkpointState.checkpointUp != null) - framesize += 24; // checkpointState.checkpointUp framesize += 8; // checkpointState.checkpointBlast + framesize += 1; // Null + if (modeState != null) + framesize += modeState.getSize(); bb.prepare(framesize); // Now actually write bb.writeDouble(timeState.currentAttemptTime); bb.writeDouble(timeState.timeSinceLoad); bb.writeDouble(timeState.gameplayClock); bb.writeDouble(timeState.dt); - bb.writeDouble(marblePosition.x); - bb.writeDouble(marblePosition.y); - bb.writeDouble(marblePosition.z); + bb.writeDouble(rewindAccumulator); + bb.writeDouble(marbleColliderTransform._11); + bb.writeDouble(marbleColliderTransform._12); + bb.writeDouble(marbleColliderTransform._13); + bb.writeDouble(marbleColliderTransform._14); + bb.writeDouble(marbleColliderTransform._21); + bb.writeDouble(marbleColliderTransform._22); + bb.writeDouble(marbleColliderTransform._23); + bb.writeDouble(marbleColliderTransform._24); + bb.writeDouble(marbleColliderTransform._31); + bb.writeDouble(marbleColliderTransform._32); + bb.writeDouble(marbleColliderTransform._33); + bb.writeDouble(marbleColliderTransform._34); + bb.writeDouble(marbleColliderTransform._41); + bb.writeDouble(marbleColliderTransform._42); + bb.writeDouble(marbleColliderTransform._43); + bb.writeDouble(marbleColliderTransform._44); + bb.writeDouble(marblePrevPosition.x); + bb.writeDouble(marblePrevPosition.y); + bb.writeDouble(marblePrevPosition.z); + bb.writeDouble(marbleNextPosition.x); + bb.writeDouble(marbleNextPosition.y); + bb.writeDouble(marbleNextPosition.z); + bb.writeDouble(marblePhysicsAccmulator); bb.writeDouble(marbleOrientation.x); bb.writeDouble(marbleOrientation.y); bb.writeDouble(marbleOrientation.z); bb.writeDouble(marbleOrientation.w); + bb.writeDouble(marblePrevOrientation.x); + bb.writeDouble(marblePrevOrientation.y); + bb.writeDouble(marblePrevOrientation.z); + bb.writeDouble(marblePrevOrientation.w); bb.writeDouble(marbleVelocity.x); bb.writeDouble(marbleVelocity.y); bb.writeDouble(marbleVelocity.z); @@ -210,8 +243,6 @@ class RewindFrame { } bb.writeDouble(activePowerupStates[0]); bb.writeDouble(activePowerupStates[1]); - bb.writeDouble(activePowerupStates[2]); - bb.writeDouble(activePowerupStates[3]); bb.writeDouble(currentUp.x); bb.writeDouble(currentUp.y); bb.writeDouble(currentUp.z); @@ -220,15 +251,23 @@ class RewindFrame { bb.writeDouble(lastContactNormal.z); bb.writeInt16(mpStates.length); for (s in mpStates) { - bb.writeDouble(s.curState.currentTime); - bb.writeDouble(s.curState.targetTime); - bb.writeDouble(s.curState.velocity.x); - bb.writeDouble(s.curState.velocity.y); - bb.writeDouble(s.curState.velocity.z); - bb.writeByte(s.stopped ? 1 : 0); + bb.writeDouble(s.currentTime); + bb.writeDouble(s.targetTime); + bb.writeByte(s.stoppedPosition == null ? 0 : 1); + if (s.stoppedPosition != null) { + bb.writeDouble(s.stoppedPosition.x); + bb.writeDouble(s.stoppedPosition.y); + bb.writeDouble(s.stoppedPosition.z); + } + bb.writeDouble(s.prevPosition.x); + bb.writeDouble(s.prevPosition.y); + bb.writeDouble(s.prevPosition.z); bb.writeDouble(s.position.x); bb.writeDouble(s.position.y); bb.writeDouble(s.position.z); + bb.writeDouble(s.velocity.x); + bb.writeDouble(s.velocity.y); + bb.writeDouble(s.velocity.z); } bb.writeInt16(trapdoorStates.length); for (s in trapdoorStates) { @@ -246,8 +285,7 @@ class RewindFrame { } bb.writeByte(checkpointState.currentCheckpoint == null ? 0 : 1); if (checkpointState.currentCheckpoint != null) { - bb.writeInt16(rm.allocGO(checkpointState.currentCheckpoint.obj)); - bb.writeInt16(rm.allocME(checkpointState.currentCheckpoint.elem)); + bb.writeInt16(rm.allocGO(checkpointState.currentCheckpoint)); } bb.writeInt16(rm.allocGO(checkpointState.currentCheckpointTrigger)); var chkgemcount = 0; @@ -260,18 +298,18 @@ class RewindFrame { bb.writeByte(checkpointState.checkpointCollectedGems[gem] ? 1 : 0); } bb.writeInt16(rm.allocGO(checkpointState.checkpointHeldPowerup)); - bb.writeByte(checkpointState.checkpointUp == null ? 0 : 1); - if (checkpointState.checkpointUp != null) { - bb.writeDouble(checkpointState.checkpointUp.x); - bb.writeDouble(checkpointState.checkpointUp.y); - bb.writeDouble(checkpointState.checkpointUp.z); - } bb.writeDouble(checkpointState.checkpointBlast); + bb.writeByte(modeState == null ? 0 : 1); + if (modeState != null) + modeState.serialize(rm, bb); return bb.getBytes(); } public inline function deserialize(rm:RewindManager, br:haxe.io.BytesInput) { - marblePosition = new Vector(); + marbleColliderTransform = new Matrix(); + marblePrevPosition = new Vector(); + marbleNextPosition = new Vector(); + marblePrevOrientation = new Quat(); marbleOrientation = new Quat(); marbleVelocity = new Vector(); marbleAngularVelocity = new Vector(); @@ -282,13 +320,38 @@ class RewindFrame { timeState.timeSinceLoad = br.readDouble(); timeState.gameplayClock = br.readDouble(); timeState.dt = br.readDouble(); - marblePosition.x = br.readDouble(); - marblePosition.y = br.readDouble(); - marblePosition.z = br.readDouble(); + rewindAccumulator = br.readDouble(); + marbleColliderTransform._11 = br.readDouble(); + marbleColliderTransform._12 = br.readDouble(); + marbleColliderTransform._13 = br.readDouble(); + marbleColliderTransform._14 = br.readDouble(); + marbleColliderTransform._21 = br.readDouble(); + marbleColliderTransform._22 = br.readDouble(); + marbleColliderTransform._23 = br.readDouble(); + marbleColliderTransform._24 = br.readDouble(); + marbleColliderTransform._31 = br.readDouble(); + marbleColliderTransform._32 = br.readDouble(); + marbleColliderTransform._33 = br.readDouble(); + marbleColliderTransform._34 = br.readDouble(); + marbleColliderTransform._41 = br.readDouble(); + marbleColliderTransform._42 = br.readDouble(); + marbleColliderTransform._43 = br.readDouble(); + marbleColliderTransform._44 = br.readDouble(); + marblePrevPosition.x = br.readDouble(); + marblePrevPosition.y = br.readDouble(); + marblePrevPosition.z = br.readDouble(); + marbleNextPosition.x = br.readDouble(); + marbleNextPosition.y = br.readDouble(); + marbleNextPosition.z = br.readDouble(); + marblePhysicsAccmulator = br.readDouble(); marbleOrientation.x = br.readDouble(); marbleOrientation.y = br.readDouble(); marbleOrientation.z = br.readDouble(); marbleOrientation.w = br.readDouble(); + marblePrevOrientation.x = br.readDouble(); + marblePrevOrientation.y = br.readDouble(); + marblePrevOrientation.z = br.readDouble(); + marblePrevOrientation.w = br.readDouble(); marbleVelocity.x = br.readDouble(); marbleVelocity.y = br.readDouble(); marbleVelocity.z = br.readDouble(); @@ -316,8 +379,6 @@ class RewindFrame { activePowerupStates = []; activePowerupStates.push(br.readDouble()); activePowerupStates.push(br.readDouble()); - activePowerupStates.push(br.readDouble()); - activePowerupStates.push(br.readDouble()); currentUp.x = br.readDouble(); currentUp.y = br.readDouble(); currentUp.z = br.readDouble(); @@ -327,24 +388,29 @@ class RewindFrame { mpStates = []; var mpStates_len = br.readInt16(); for (i in 0...mpStates_len) { - var mpStates_item = { - curState: { - currentTime: 0.0, - targetTime: 0.0, - velocity: new Vector(), - }, - stopped: false, - position: new Vector() - }; - mpStates_item.curState.currentTime = br.readDouble(); - mpStates_item.curState.targetTime = br.readDouble(); - mpStates_item.curState.velocity.x = br.readDouble(); - mpStates_item.curState.velocity.y = br.readDouble(); - mpStates_item.curState.velocity.z = br.readDouble(); - mpStates_item.stopped = br.readByte() != 0; + var mpStates_item = new RewindMPState(); + mpStates_item.currentTime = br.readDouble(); + mpStates_item.targetTime = br.readDouble(); + mpStates_item.stoppedPosition = new Vector(); + mpStates_item.prevPosition = new Vector(); + mpStates_item.position = new Vector(); + mpStates_item.velocity = new Vector(); + if (br.readByte() != 0) { + mpStates_item.stoppedPosition.x = br.readDouble(); + mpStates_item.stoppedPosition.y = br.readDouble(); + mpStates_item.stoppedPosition.z = br.readDouble(); + } else { + mpStates_item.stoppedPosition = null; + } + mpStates_item.prevPosition.x = br.readDouble(); + mpStates_item.prevPosition.y = br.readDouble(); + mpStates_item.prevPosition.z = br.readDouble(); mpStates_item.position.x = br.readDouble(); mpStates_item.position.y = br.readDouble(); mpStates_item.position.z = br.readDouble(); + mpStates_item.velocity.x = br.readDouble(); + mpStates_item.velocity.y = br.readDouble(); + mpStates_item.velocity.z = br.readDouble(); mpStates.push(mpStates_item); } trapdoorStates = []; @@ -378,13 +444,11 @@ class RewindFrame { currentCheckpointTrigger: null, checkpointCollectedGems: new Map(), checkpointHeldPowerup: null, - checkpointUp: null, checkpointBlast: 0.0, }; if (hasCheckpoint) { var co = rm.getGO(br.readInt16()); - var ce = rm.getME(br.readInt16()); - checkpointState.currentCheckpoint = {obj: cast co, elem: ce}; + checkpointState.currentCheckpoint = cast co; } checkpointState.currentCheckpointTrigger = cast rm.getGO(br.readInt16()); var checkpointState_checkpointCollectedGems_len = br.readInt16(); @@ -394,13 +458,11 @@ class RewindFrame { checkpointState.checkpointCollectedGems.set(cast gem, c); } checkpointState.checkpointHeldPowerup = cast rm.getGO(br.readInt16()); - var checkpointState_checkpointUp_has = br.readByte() != 0; - if (checkpointState_checkpointUp_has) { - checkpointState.checkpointUp = new Vector(); - checkpointState.checkpointUp.x = br.readDouble(); - checkpointState.checkpointUp.y = br.readDouble(); - checkpointState.checkpointUp.z = br.readDouble(); - } checkpointState.checkpointBlast = br.readDouble(); + var hasModeState = br.readByte() != 0; + if (hasModeState) { + modeState = rm.level.gameMode.constructRewindState(); + modeState.deserialize(rm, br); + } } } diff --git a/src/rewind/RewindManager.hx b/src/rewind/RewindManager.hx index 3e55a9b2..3dfa605c 100644 --- a/src/rewind/RewindManager.hx +++ b/src/rewind/RewindManager.hx @@ -20,7 +20,9 @@ class RewindManager { var allocObjs:Array = []; var allocMeMap:Map = []; var allocMes:Array = []; - var level:MarbleWorld; + + public var level:MarbleWorld; + var allocId = 0; var allocMeId = 0; @@ -39,6 +41,7 @@ class RewindManager { while (timeAccumulator >= saveResolution) { timeAccumulator -= saveResolution; var rf = new RewindFrame(); + rf.rewindAccumulator = timeAccumulator; rf.timeState = level.timeState.clone(); rf.marbleColliderTransform = level.marble.collider.transform.clone(); rf.marblePrevPosition = @:privateAccess level.marble.oldPos.clone(); @@ -275,6 +278,8 @@ class RewindManager { } public function getGO(id:Int):GameObject { + if (id == -1) + return null; return allocObjs[id]; } @@ -290,6 +295,8 @@ class RewindManager { } public function getME(id:Int):MissionElementBase { + if (id == -1) + return null; return allocMes[id]; } diff --git a/src/rewind/RewindableState.hx b/src/rewind/RewindableState.hx index a919db70..21afc53a 100644 --- a/src/rewind/RewindableState.hx +++ b/src/rewind/RewindableState.hx @@ -5,4 +5,7 @@ import src.MarbleWorld; interface RewindableState { function apply(level:MarbleWorld):Void; function clone():RewindableState; + function getSize():Int; + function serialize(rm:RewindManager, bw:haxe.io.BytesOutput):Void; + function deserialize(rm:RewindManager, br:haxe.io.BytesInput):Void; }