replay support

This commit is contained in:
RandomityGuy 2022-11-27 23:42:58 +05:30
parent 0c1e121a8b
commit f820a3e41b
8 changed files with 257 additions and 93 deletions

View file

@ -1265,6 +1265,9 @@ class Marble extends GameObject {
} }
} }
var stoppedPaths = false;
var tempState = timeState.clone();
var intersectData = testMove(velocity, this.getAbsPos().getPosition(), timeStep, _radius, true); // this.getIntersectionTime(timeStep, velocity); var intersectData = testMove(velocity, this.getAbsPos().getPosition(), timeStep, _radius, true); // this.getIntersectionTime(timeStep, velocity);
var intersectT = intersectData.t; var intersectT = intersectData.t;
@ -1279,7 +1282,6 @@ class Marble extends GameObject {
// this.setPosition(intersectData.position.x, intersectData.position.y, intersectData.position.z); // this.setPosition(intersectData.position.x, intersectData.position.y, intersectData.position.z);
} }
var tempState = timeState.clone();
tempState.dt = timeStep; tempState.dt = timeStep;
it++; it++;
@ -1289,7 +1291,7 @@ class Marble extends GameObject {
var isCentered:Bool = cmf.result; var isCentered:Bool = cmf.result;
var aControl = cmf.aControl; var aControl = cmf.aControl;
var desiredOmega = cmf.desiredOmega; var desiredOmega = cmf.desiredOmega;
var stoppedPaths = false;
stoppedPaths = this.velocityCancel(timeState.currentAttemptTime, timeStep, isCentered, false, stoppedPaths, pathedInteriors); stoppedPaths = this.velocityCancel(timeState.currentAttemptTime, timeStep, isCentered, false, stoppedPaths, pathedInteriors);
var A = this.getExternalForces(timeState.currentAttemptTime, m, timeStep); var A = this.getExternalForces(timeState.currentAttemptTime, m, timeStep);
var retf = this.applyContactForces(timeStep, m, isCentered, aControl, desiredOmega, A); var retf = this.applyContactForces(timeStep, m, isCentered, aControl, desiredOmega, A);
@ -1362,6 +1364,9 @@ class Marble extends GameObject {
pTime.currentAttemptTime = piTime; pTime.currentAttemptTime = piTime;
this.heldPowerup.use(pTime); this.heldPowerup.use(pTime);
this.heldPowerup = null; this.heldPowerup = null;
if (this.level.isRecording) {
this.level.replay.recordPowerupPickup(null);
}
} }
if (this.controllable && this.prevPos != null) { if (this.controllable && this.prevPos != null) {
@ -1434,7 +1439,10 @@ class Marble extends GameObject {
var expectedVel = this.level.replay.currentPlaybackFrame.marbleVelocity.clone(); var expectedVel = this.level.replay.currentPlaybackFrame.marbleVelocity.clone();
var expectedOmega = this.level.replay.currentPlaybackFrame.marbleAngularVelocity.clone(); var expectedOmega = this.level.replay.currentPlaybackFrame.marbleAngularVelocity.clone();
this.getAbsPos().setPosition(expectedPos); this.setPosition(expectedPos.x, expectedPos.y, expectedPos.z);
var tform = this.collider.transform;
tform.setPosition(new Vector(expectedPos.x, expectedPos.y, expectedPos.z));
this.collider.setTransform(tform);
this.velocity = expectedVel; this.velocity = expectedVel;
this.setRotationQuat(this.level.replay.currentPlaybackFrame.marbleOrientation.clone()); this.setRotationQuat(this.level.replay.currentPlaybackFrame.marbleOrientation.clone());
this.omega = expectedOmega; this.omega = expectedOmega;

View file

@ -353,16 +353,16 @@ class MarbleWorld extends Scheduler {
} }
public function restart(full:Bool = false) { public function restart(full:Bool = false) {
if (!this.isWatching) {
this.replay.clear();
} else
this.replay.rewind();
if (!full && this.currentCheckpoint != null) { if (!full && this.currentCheckpoint != null) {
this.loadCheckpointState(); this.loadCheckpointState();
return 0; // Load checkpoint return 0; // Load checkpoint
} }
if (!this.isWatching) {
this.replay.clear();
} else
this.replay.rewind();
this.timeState.currentAttemptTime = 0; this.timeState.currentAttemptTime = 0;
this.timeState.gameplayClock = 0; this.timeState.gameplayClock = 0;
this.bonusTime = 0; this.bonusTime = 0;
@ -390,13 +390,15 @@ class MarbleWorld extends Scheduler {
} }
// Record/Playback trapdoor and landmine states // Record/Playback trapdoor and landmine states
if (full) {
var tidx = 0; var tidx = 0;
var lidx = 0; var lidx = 0;
for (dtss in this.dtsObjects) { for (dtss in this.dtsObjects) {
if (dtss is Trapdoor) { if (dtss is Trapdoor) {
var trapdoor:Trapdoor = cast dtss; var trapdoor:Trapdoor = cast dtss;
if (!this.isWatching) { if (!this.isWatching) {
this.replay.recordTrapdoorState(trapdoor.lastContactTime - this.timeState.timeSinceLoad, trapdoor.lastDirection, trapdoor.lastCompletion); this.replay.recordTrapdoorState(trapdoor.lastContactTime - this.timeState.timeSinceLoad, trapdoor.lastDirection,
trapdoor.lastCompletion);
} else { } else {
var state = this.replay.getTrapdoorState(tidx); var state = this.replay.getTrapdoorState(tidx);
trapdoor.lastContactTime = state.lastContactTime + this.timeState.timeSinceLoad; trapdoor.lastContactTime = state.lastContactTime + this.timeState.timeSinceLoad;
@ -415,6 +417,7 @@ class MarbleWorld extends Scheduler {
lidx++; lidx++;
} }
} }
}
var startquat = this.getStartPositionAndOrientation(); var startquat = this.getStartPositionAndOrientation();
@ -988,7 +991,9 @@ class MarbleWorld extends Scheduler {
if (Key.isPressed(Settings.controlsSettings.respawn)) { if (Key.isPressed(Settings.controlsSettings.respawn)) {
this.respawnPressedTime = timeState.timeSinceLoad; this.respawnPressedTime = timeState.timeSinceLoad;
this.restart(); this.restart();
if (!this.isWatching) {
Settings.playStatistics.respawns++; Settings.playStatistics.respawns++;
if (!Settings.levelStatistics.exists(mission.path)) { if (!Settings.levelStatistics.exists(mission.path)) {
Settings.levelStatistics.set(mission.path, { Settings.levelStatistics.set(mission.path, {
oobs: 0, oobs: 0,
@ -998,10 +1003,15 @@ class MarbleWorld extends Scheduler {
} else { } else {
Settings.levelStatistics[mission.path].respawns++; Settings.levelStatistics[mission.path].respawns++;
} }
if (this.isRecording) {
this.replay.endFrame();
}
}
return; return;
} }
if (Key.isDown(Settings.controlsSettings.respawn)) { if (Key.isDown(Settings.controlsSettings.respawn) && !this.isWatching) {
if (timeState.timeSinceLoad - this.respawnPressedTime > 1.5) { if (timeState.timeSinceLoad - this.respawnPressedTime > 1.5) {
this.restart(true); this.restart(true);
this.respawnPressedTime = Math.POSITIVE_INFINITY; this.respawnPressedTime = Math.POSITIVE_INFINITY;
@ -1010,6 +1020,17 @@ class MarbleWorld extends Scheduler {
} }
this.tickSchedule(timeState.currentAttemptTime); this.tickSchedule(timeState.currentAttemptTime);
// Replay gravity
if (this.isWatching) {
if (this.replay.currentPlaybackFrame.gravityChange) {
this.setUp(this.replay.currentPlaybackFrame.gravity, timeState, this.replay.currentPlaybackFrame.gravityInstant);
}
if (this.replay.currentPlaybackFrame.powerupPickup != null) {
this.pickUpPowerUpReplay(this.replay.currentPlaybackFrame.powerupPickup);
}
}
this.updateGameState(); this.updateGameState();
ProfilerUI.measure("updateDTS"); ProfilerUI.measure("updateDTS");
for (obj in dtsObjects) { for (obj in dtsObjects) {
@ -1031,17 +1052,17 @@ class MarbleWorld extends Scheduler {
ProfilerUI.measure("updateAudio"); ProfilerUI.measure("updateAudio");
AudioManager.update(this.scene); AudioManager.update(this.scene);
if (this.outOfBounds && this.finishTime == null && Key.isDown(Settings.controlsSettings.powerup) && !this.isWatching) {
this.restart();
return;
}
if (!this.isWatching) { if (!this.isWatching) {
if (this.isRecording) { if (this.isRecording) {
this.replay.endFrame(); this.replay.endFrame();
} }
} }
if (this.outOfBounds && this.finishTime == null && Key.isDown(Settings.controlsSettings.powerup)) {
this.restart();
return;
}
this.updateTexts(); this.updateTexts();
} }
@ -1412,6 +1433,18 @@ class MarbleWorld extends Scheduler {
return 0; return 0;
} }
public function pickUpPowerUpReplay(powerupIdent:String) {
if (powerupIdent == null)
return false;
if (this.marble.heldPowerup != null)
if (this.marble.heldPowerup.identifier == powerupIdent)
return false;
this.playGui.setPowerupImage(powerupIdent);
return true;
}
public function pickUpPowerUp(powerUp:PowerUp) { public function pickUpPowerUp(powerUp:PowerUp) {
if (powerUp == null) if (powerUp == null)
return false; return false;
@ -1421,6 +1454,9 @@ class MarbleWorld extends Scheduler {
this.marble.heldPowerup = powerUp; this.marble.heldPowerup = powerUp;
this.playGui.setPowerupImage(powerUp.identifier); this.playGui.setPowerupImage(powerUp.identifier);
MarbleGame.instance.touchInput.powerupButton.setEnabled(true); MarbleGame.instance.touchInput.powerupButton.setEnabled(true);
if (this.isRecording) {
this.replay.recordPowerupPickup(powerUp);
}
return true; return true;
} }
@ -1479,6 +1515,10 @@ class MarbleWorld extends Scheduler {
// quatChange.initMoveTo(oldUp, vec); // quatChange.initMoveTo(oldUp, vec);
quatChange.multiply(quatChange, currentQuat); quatChange.multiply(quatChange, currentQuat);
if (this.isRecording) {
this.replay.recordGravity(vec, instant);
}
this.newOrientationQuat = quatChange; this.newOrientationQuat = quatChange;
this.oldOrientationQuat = currentQuat; this.oldOrientationQuat = currentQuat;
this.orientationChangeTime = instant ? -1e8 : timeState.currentAttemptTime; this.orientationChangeTime = instant ? -1e8 : timeState.currentAttemptTime;
@ -1491,6 +1531,7 @@ class MarbleWorld extends Scheduler {
this.outOfBounds = true; this.outOfBounds = true;
this.outOfBoundsTime = this.timeState.clone(); this.outOfBoundsTime = this.timeState.clone();
this.marble.camera.oob = true; this.marble.camera.oob = true;
if (!this.isWatching) {
Settings.playStatistics.oobs++; Settings.playStatistics.oobs++;
if (!Settings.levelStatistics.exists(mission.path)) { if (!Settings.levelStatistics.exists(mission.path)) {
Settings.levelStatistics.set(mission.path, { Settings.levelStatistics.set(mission.path, {
@ -1503,6 +1544,7 @@ class MarbleWorld extends Scheduler {
} }
if (Settings.optionsSettings.oobInsults) if (Settings.optionsSettings.oobInsults)
OOBInsultGui.OOBCheck(); OOBInsultGui.OOBCheck();
}
// sky.follow = null; // sky.follow = null;
// this.oobCameraPosition = camera.position.clone(); // this.oobCameraPosition = camera.position.clone();
playGui.setCenterText('outofbounds'); playGui.setCenterText('outofbounds');
@ -1571,13 +1613,19 @@ class MarbleWorld extends Scheduler {
this.marble.setPosition(mpos.x, mpos.y, mpos.z); this.marble.setPosition(mpos.x, mpos.y, mpos.z);
marble.velocity.load(new Vector(0, 0, 0)); marble.velocity.load(new Vector(0, 0, 0));
marble.omega.load(new Vector(0, 0, 0)); marble.omega.load(new Vector(0, 0, 0));
// Set camera orienation // Set camera orientation
var euler = this.currentCheckpoint.obj.getRotationQuat().toEuler(); var euler = this.currentCheckpoint.obj.getRotationQuat().toEuler();
this.marble.camera.CameraYaw = euler.z + Math.PI / 2; this.marble.camera.CameraYaw = euler.z + Math.PI / 2;
this.marble.camera.CameraPitch = 0.45; this.marble.camera.CameraPitch = 0.45;
this.marble.camera.nextCameraYaw = this.marble.camera.CameraYaw; this.marble.camera.nextCameraYaw = this.marble.camera.CameraYaw;
this.marble.camera.nextCameraPitch = this.marble.camera.CameraPitch; this.marble.camera.nextCameraPitch = this.marble.camera.CameraPitch;
this.marble.camera.oob = false; this.marble.camera.oob = false;
if (this.isRecording) {
this.replay.recordCameraState(this.marble.camera.CameraYaw, this.marble.camera.CameraPitch);
this.replay.recordMarbleInput(0, 0);
this.replay.recordMarbleState(mpos, marble.velocity, marble.getRotationQuat(), marble.omega);
this.replay.recordMarbleStateFlags(false, false, true);
}
var gravityField = ""; // (this.currentCheckpoint.srcElement as any) ?.gravity || this.currentCheckpointTrigger?.element.gravity; var gravityField = ""; // (this.currentCheckpoint.srcElement as any) ?.gravity || this.currentCheckpointTrigger?.element.gravity;
if (this.currentCheckpoint.elem.fields.exists('gravity')) { if (this.currentCheckpoint.elem.fields.exists('gravity')) {
gravityField = this.currentCheckpoint.elem.fields.get('gravity')[0]; gravityField = this.currentCheckpoint.elem.fields.get('gravity')[0];
@ -1661,7 +1709,9 @@ class MarbleWorld extends Scheduler {
public function dispose() { public function dispose() {
// Gotta add the timesinceload to our stats // Gotta add the timesinceload to our stats
if (!this.isWatching) {
Settings.playStatistics.totalTime += this.timeState.timeSinceLoad; Settings.playStatistics.totalTime += this.timeState.timeSinceLoad;
if (!Settings.levelStatistics.exists(mission.path)) { if (!Settings.levelStatistics.exists(mission.path)) {
Settings.levelStatistics.set(mission.path, { Settings.levelStatistics.set(mission.path, {
oobs: 0, oobs: 0,
@ -1671,6 +1721,7 @@ class MarbleWorld extends Scheduler {
} else { } else {
Settings.levelStatistics[mission.path].totalTime += this.timeState.timeSinceLoad; Settings.levelStatistics[mission.path].totalTime += this.timeState.timeSinceLoad;
} }
}
this.playGui.dispose(); this.playGui.dispose();
scene.removeChildren(); scene.removeChildren();

View file

@ -136,6 +136,7 @@ class Mission {
var ret = ResourceLoader.getResource(basename + ".png", ResourceLoader.getImage, this.imageResources).toTile(); var ret = ResourceLoader.getResource(basename + ".png", ResourceLoader.getImage, this.imageResources).toTile();
onLoaded(ret); onLoaded(ret);
}); });
return imgFileEntry.path;
} }
if (ResourceLoader.fileSystem.exists(basename + ".jpg")) { if (ResourceLoader.fileSystem.exists(basename + ".jpg")) {
imgFileEntry = ResourceLoader.fileSystem.get(basename + ".jpg"); imgFileEntry = ResourceLoader.fileSystem.get(basename + ".jpg");
@ -143,14 +144,17 @@ class Mission {
var ret = ResourceLoader.getResource(basename + ".jpg", ResourceLoader.getImage, this.imageResources).toTile(); var ret = ResourceLoader.getResource(basename + ".jpg", ResourceLoader.getImage, this.imageResources).toTile();
onLoaded(ret); onLoaded(ret);
}); });
return imgFileEntry.path;
} }
var img = new BitmapData(1, 1); var img = new BitmapData(1, 1);
img.setPixel(0, 0, 0); img.setPixel(0, 0, 0);
onLoaded(Tile.fromBitmap(img)); onLoaded(Tile.fromBitmap(img));
return null;
} else { } else {
var img = new BitmapData(1, 1); var img = new BitmapData(1, 1);
img.setPixel(0, 0, 0); img.setPixel(0, 0, 0);
onLoaded(Tile.fromBitmap(img)); onLoaded(Tile.fromBitmap(img));
return null;
} }
} }

View file

@ -1,5 +1,6 @@
package src; package src;
import shapes.PowerUp;
import haxe.io.BytesInput; import haxe.io.BytesInput;
import haxe.zip.Huffman; import haxe.zip.Huffman;
import haxe.io.Bytes; import haxe.io.Bytes;
@ -29,12 +30,17 @@ class ReplayFrame {
var marbleOrientation:Quat; var marbleOrientation:Quat;
var marbleAngularVelocity:Vector; var marbleAngularVelocity:Vector;
var marbleStateFlags:EnumFlags<ReplayMarbleState>; var marbleStateFlags:EnumFlags<ReplayMarbleState>;
var powerupPickup:String;
// Camera // Camera
var cameraPitch:Float; var cameraPitch:Float;
var cameraYaw:Float; var cameraYaw:Float;
// Input // Input
var marbleX:Float; var marbleX:Float;
var marbleY:Float; var marbleY:Float;
// Gravity
var gravity:Vector;
var gravityInstant:Bool;
var gravityChange:Bool;
public function new() {} public function new() {}
@ -98,6 +104,22 @@ class ReplayFrame {
interpFrame.marbleX = this.marbleX; interpFrame.marbleX = this.marbleX;
interpFrame.marbleY = this.marbleY; interpFrame.marbleY = this.marbleY;
// Gravity
if (this.gravityChange) {
interpFrame.gravity = this.gravity.clone();
interpFrame.gravityInstant = this.gravityInstant;
interpFrame.gravityChange = true;
}
if (next.gravityChange) {
interpFrame.gravity = next.gravity.clone();
interpFrame.gravityInstant = next.gravityInstant;
interpFrame.gravityChange = true;
}
if (this.powerupPickup != null) {
interpFrame.powerupPickup = this.powerupPickup;
}
return interpFrame; return interpFrame;
} }
@ -123,6 +145,21 @@ class ReplayFrame {
bw.writeFloat(this.cameraYaw); bw.writeFloat(this.cameraYaw);
bw.writeFloat(this.marbleX); bw.writeFloat(this.marbleX);
bw.writeFloat(this.marbleY); bw.writeFloat(this.marbleY);
if (this.gravityChange) {
bw.writeByte(1);
bw.writeFloat(this.gravity.x);
bw.writeFloat(this.gravity.y);
bw.writeFloat(this.gravity.z);
bw.writeByte(this.gravityInstant ? 1 : 0);
} else {
bw.writeByte(0);
}
if (this.powerupPickup != null) {
bw.writeByte(1);
bw.writeStr(this.powerupPickup);
} else {
bw.writeByte(0);
}
} }
public function read(br:BytesReader) { public function read(br:BytesReader) {
@ -138,6 +175,18 @@ class ReplayFrame {
this.cameraYaw = br.readFloat(); this.cameraYaw = br.readFloat();
this.marbleX = br.readFloat(); this.marbleX = br.readFloat();
this.marbleY = br.readFloat(); this.marbleY = br.readFloat();
if (br.readByte() == 1) {
this.gravity = new Vector(br.readFloat(), br.readFloat(), br.readFloat());
this.gravityInstant = br.readByte() == 1;
this.gravityChange = true;
} else {
this.gravityChange = false;
}
if (br.readByte() == 1) {
this.powerupPickup = br.readStr();
} else {
this.powerupPickup = null;
}
} }
} }
@ -197,7 +246,7 @@ class Replay {
var currentPlaybackFrameIdx:Int; var currentPlaybackFrameIdx:Int;
var currentPlaybackTime:Float; var currentPlaybackTime:Float;
var version:Int = 1; var version:Int = 3;
public function new(mission:String) { public function new(mission:String) {
this.mission = mission; this.mission = mission;
@ -235,6 +284,13 @@ class Replay {
currentRecordFrame.marbleStateFlags.set(InstantTeleport); currentRecordFrame.marbleStateFlags.set(InstantTeleport);
} }
public function recordPowerupPickup(powerup:PowerUp) {
if (powerup == null)
currentRecordFrame.powerupPickup = ""; // Use powerup
else
currentRecordFrame.powerupPickup = powerup.identifier;
}
public function recordMarbleInput(x:Float, y:Float) { public function recordMarbleInput(x:Float, y:Float) {
currentRecordFrame.marbleX = x; currentRecordFrame.marbleX = x;
currentRecordFrame.marbleY = y; currentRecordFrame.marbleY = y;
@ -245,6 +301,13 @@ class Replay {
currentRecordFrame.cameraYaw = yaw; currentRecordFrame.cameraYaw = yaw;
} }
public function recordGravity(gravity:Vector, instant:Bool) {
currentRecordFrame.gravityChange = true;
currentRecordFrame.gravity = gravity.clone();
if (instant)
currentRecordFrame.gravityInstant = instant;
}
public function recordTrapdoorState(lastContactTime:Float, lastDirection:Int, lastCompletion:Float) { public function recordTrapdoorState(lastContactTime:Float, lastDirection:Int, lastCompletion:Float) {
initialState.trapdoorLastContactTimes.push(lastContactTime); initialState.trapdoorLastContactTimes.push(lastContactTime);
initialState.trapdoorLastDirections.push(lastDirection); initialState.trapdoorLastDirections.push(lastDirection);
@ -283,15 +346,42 @@ class Replay {
return false; return false;
} }
var nextFrame = this.frames[this.currentPlaybackFrameIdx + 1]; var nextFrame = this.frames[this.currentPlaybackFrameIdx + 1];
var stateFlags = 0;
var nextGravityChange:Bool = false;
var nextGravityState:{
instant:Bool,
gravity:Vector
} = null;
var powerup:String = null;
while (nextFrame.time <= nextT) { while (nextFrame.time <= nextT) {
this.currentPlaybackFrameIdx++; this.currentPlaybackFrameIdx++;
if (this.currentPlaybackFrameIdx + 1 >= this.frames.length) { if (this.currentPlaybackFrameIdx + 1 >= this.frames.length) {
return false; return false;
} }
var testNextFrame = this.frames[this.currentPlaybackFrameIdx + 1]; var testNextFrame = this.frames[this.currentPlaybackFrameIdx + 1];
stateFlags |= testNextFrame.marbleStateFlags.toInt();
if (testNextFrame.gravityChange) {
nextGravityChange = true;
nextGravityState = {
instant: testNextFrame.gravityInstant,
gravity: testNextFrame.gravity.clone()
};
}
if (testNextFrame.powerupPickup != null) {
powerup = testNextFrame.powerupPickup;
}
startFrame = nextFrame; startFrame = nextFrame;
nextFrame = testNextFrame; nextFrame = testNextFrame;
} }
nextFrame.marbleStateFlags = EnumFlags.ofInt(stateFlags);
if (nextGravityChange) {
nextFrame.gravityChange = true;
nextFrame.gravityInstant = nextGravityState.instant;
nextFrame.gravity = nextGravityState.gravity.clone();
}
if (powerup != null) {
nextFrame.powerupPickup = powerup;
}
this.currentPlaybackFrame = startFrame.interpolate(nextFrame, nextT); this.currentPlaybackFrame = startFrame.interpolate(nextFrame, nextT);
this.currentPlaybackTime += dt; this.currentPlaybackTime += dt;
return true; return true;

View file

@ -205,7 +205,8 @@ class Util {
'\\f' => '\x0C', '\\f' => '\x0C',
'\\n' => '\n', '\\n' => '\n',
'\\r' => '\r', '\\r' => '\r',
"\\'" => "'" "\\'" => "'",
"\\\"" => "\"",
]; ];
for (obj => esc in specialCases) { for (obj => esc in specialCases) {

View file

@ -99,6 +99,8 @@ class MainMenuGui extends GuiImage {
#if js #if js
repmis = StringTools.replace(repmis, "data/", ""); repmis = StringTools.replace(repmis, "data/", "");
#end #end
if (MissionList.missions == null)
MissionList.buildMissionList();
var playMis = MissionList.missions.get(repmis); var playMis = MissionList.missions.get(repmis);
if (playMis != null) { if (playMis != null) {
cast(this.parent, Canvas).marbleGame.watchMissionReplay(playMis, replay); cast(this.parent, Canvas).marbleGame.watchMissionReplay(playMis, replay);

View file

@ -782,8 +782,6 @@ class PlayMissionGui extends GuiImage {
index = 0; index = 0;
} }
var selectionChanged = currentSelection != index;
currentSelection = index; currentSelection = index;
currentSelectionStatic = currentSelection; currentSelectionStatic = currentSelection;
@ -899,31 +897,38 @@ class PlayMissionGui extends GuiImage {
setScoreHover(scoreButtonHover); setScoreHover(scoreButtonHover);
if (selectionChanged) { // pmPreview.bmp.tile = tmpprevtile;
pmPreview.bmp.tile = tmpprevtile;
#if js #if js
switch (previewTimeoutHandle) { switch (previewTimeoutHandle) {
case None: case None:
previewTimeoutHandle = Some(js.Browser.window.setTimeout(() -> { previewTimeoutHandle = Some(js.Browser.window.setTimeout(() -> {
currentMission.getPreviewImage(prevImg -> { var prevpath = currentMission.getPreviewImage(prevImg -> {
pmPreview.bmp.tile = prevImg; pmPreview.bmp.tile = prevImg;
}); });
if (prevpath != pmPreview.bmp.tile.getTexture().name) {
pmPreview.bmp.tile = tmpprevtile;
}
}, 75)); }, 75));
case Some(previewTimeoutHandle_id): case Some(previewTimeoutHandle_id):
js.Browser.window.clearTimeout(previewTimeoutHandle_id); js.Browser.window.clearTimeout(previewTimeoutHandle_id);
previewTimeoutHandle = Some(js.Browser.window.setTimeout(() -> { previewTimeoutHandle = Some(js.Browser.window.setTimeout(() -> {
currentMission.getPreviewImage(prevImg -> { var prevpath = currentMission.getPreviewImage(prevImg -> {
pmPreview.bmp.tile = prevImg; pmPreview.bmp.tile = prevImg;
}); });
if (prevpath != pmPreview.bmp.tile.getTexture().name) {
pmPreview.bmp.tile = tmpprevtile;
}
}, 75)); }, 75));
} }
#end #end
#if hl #if hl
currentMission.getPreviewImage(prevImg -> { var prevpath = currentMission.getPreviewImage(prevImg -> {
pmPreview.bmp.tile = prevImg; pmPreview.bmp.tile = prevImg;
}); // Shit be sync }); // Shit be sync
#end if (prevpath != pmPreview.bmp.tile.getTexture().name) {
pmPreview.bmp.tile = tmpprevtile;
} }
#end
} }
setCategoryFunc(currentGame, currentCategoryStatic, false); setCategoryFunc(currentGame, currentCategoryStatic, false);

View file

@ -88,6 +88,9 @@ class TeleportTrigger extends Trigger {
} }
this.level.marble.prevPos.load(position); this.level.marble.prevPos.load(position);
this.level.marble.setPosition(position.x, position.y, position.z); this.level.marble.setPosition(position.x, position.y, position.z);
if (this.level.isRecording) {
this.level.replay.recordMarbleStateFlags(false, false, true);
}
if (!MisParser.parseBoolean(chooseNonNull(this.element.keepvelocity, destination.element.keepvelocity))) if (!MisParser.parseBoolean(chooseNonNull(this.element.keepvelocity, destination.element.keepvelocity)))
this.level.marble.velocity.set(0, 0, 0); this.level.marble.velocity.set(0, 0, 0);