mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2026-05-11 03:51:39 +00:00
kind of do powerups and use our own bitstream
This commit is contained in:
parent
15fb7c5cb9
commit
66c7061600
14 changed files with 180 additions and 69 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
package src;
|
package src;
|
||||||
|
|
||||||
|
import net.BitStream.OutputBitStream;
|
||||||
import net.ClientConnection;
|
import net.ClientConnection;
|
||||||
import net.ClientConnection.GameConnection;
|
import net.ClientConnection.GameConnection;
|
||||||
import net.NetPacket.MarbleUpdatePacket;
|
import net.NetPacket.MarbleUpdatePacket;
|
||||||
|
|
@ -577,7 +578,7 @@ class Marble extends GameObject {
|
||||||
A = A.add(force.multiply(1 / mass));
|
A = A.add(force.multiply(1 / mass));
|
||||||
}
|
}
|
||||||
for (marble in level.marbles) {
|
for (marble in level.marbles) {
|
||||||
if (marble != this) {
|
if (marble != cast this) {
|
||||||
var force = marble.getForce(this.collider.transform.getPosition(), tick);
|
var force = marble.getForce(this.collider.transform.getPosition(), tick);
|
||||||
A = A.add(force.multiply(1 / mass));
|
A = A.add(force.multiply(1 / mass));
|
||||||
}
|
}
|
||||||
|
|
@ -1608,7 +1609,7 @@ class Marble extends GameObject {
|
||||||
var pTime = timeState.clone();
|
var pTime = timeState.clone();
|
||||||
pTime.dt = timeStep;
|
pTime.dt = timeStep;
|
||||||
pTime.currentAttemptTime = passedTime;
|
pTime.currentAttemptTime = passedTime;
|
||||||
this.heldPowerup.use(this, pTime);
|
this.heldPowerup.use(cast this, pTime);
|
||||||
this.heldPowerup = null;
|
this.heldPowerup = null;
|
||||||
if (this.level.isRecording) {
|
if (this.level.isRecording) {
|
||||||
this.level.replay.recordPowerupPickup(null);
|
this.level.replay.recordPowerupPickup(null);
|
||||||
|
|
@ -1655,7 +1656,7 @@ class Marble extends GameObject {
|
||||||
// MP Only Functions
|
// MP Only Functions
|
||||||
|
|
||||||
public function packUpdate(move:NetMove, timeState:TimeState) {
|
public function packUpdate(move:NetMove, timeState:TimeState) {
|
||||||
var b = new haxe.io.BytesOutput();
|
var b = new OutputBitStream();
|
||||||
b.writeByte(NetPacketType.MarbleUpdate);
|
b.writeByte(NetPacketType.MarbleUpdate);
|
||||||
var marbleUpdate = new MarbleUpdatePacket();
|
var marbleUpdate = new MarbleUpdatePacket();
|
||||||
marbleUpdate.clientId = connection != null ? connection.id : 0;
|
marbleUpdate.clientId = connection != null ? connection.id : 0;
|
||||||
|
|
@ -1670,6 +1671,7 @@ class Marble extends GameObject {
|
||||||
marbleUpdate.heliTick = this.helicopterUseTick;
|
marbleUpdate.heliTick = this.helicopterUseTick;
|
||||||
marbleUpdate.megaTick = this.megaMarbleUseTick;
|
marbleUpdate.megaTick = this.megaMarbleUseTick;
|
||||||
marbleUpdate.oob = this.outOfBounds;
|
marbleUpdate.oob = this.outOfBounds;
|
||||||
|
marbleUpdate.powerUpId = this.heldPowerup != null ? this.heldPowerup.netIndex : 0xFFFF;
|
||||||
marbleUpdate.serialize(b);
|
marbleUpdate.serialize(b);
|
||||||
return b.getBytes();
|
return b.getBytes();
|
||||||
}
|
}
|
||||||
|
|
@ -1694,6 +1696,11 @@ class Marble extends GameObject {
|
||||||
this.megaMarbleUseTick = p.megaTick;
|
this.megaMarbleUseTick = p.megaTick;
|
||||||
this.outOfBounds = p.oob;
|
this.outOfBounds = p.oob;
|
||||||
this.camera.oob = p.oob;
|
this.camera.oob = p.oob;
|
||||||
|
if (p.powerUpId == 0xFFFF) {
|
||||||
|
this.level.deselectPowerUp(cast this);
|
||||||
|
} else {
|
||||||
|
this.level.pickUpPowerUp(cast this, this.level.powerUps[p.powerUpId]);
|
||||||
|
}
|
||||||
if (this.controllable && Net.isClient) {
|
if (this.controllable && Net.isClient) {
|
||||||
// We are client, need to do something about the queue
|
// We are client, need to do something about the queue
|
||||||
var mm = Net.clientConnection.moveManager;
|
var mm = Net.clientConnection.moveManager;
|
||||||
|
|
@ -1712,7 +1719,7 @@ class Marble extends GameObject {
|
||||||
if (this.controllable && this.mode != Finish && !MarbleGame.instance.paused && !this.level.isWatching && !this.level.isReplayingMovement) {
|
if (this.controllable && this.mode != Finish && !MarbleGame.instance.paused && !this.level.isWatching && !this.level.isReplayingMovement) {
|
||||||
if (Net.isClient) {
|
if (Net.isClient) {
|
||||||
var axis = getMarbleAxis()[1];
|
var axis = getMarbleAxis()[1];
|
||||||
move = Net.clientConnection.moveManager.recordMove(this, axis, timeState);
|
move = Net.clientConnection.moveManager.recordMove(cast this, axis, timeState);
|
||||||
} else if (Net.isHost) {
|
} else if (Net.isHost) {
|
||||||
var axis = getMarbleAxis()[1];
|
var axis = getMarbleAxis()[1];
|
||||||
var innerMove = recordMove();
|
var innerMove = recordMove();
|
||||||
|
|
@ -1763,6 +1770,11 @@ class Marble extends GameObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (move.move.jump && this.outOfBounds) {
|
||||||
|
this.level.cancel(this.oobSchedule);
|
||||||
|
this.level.restart(cast this);
|
||||||
|
}
|
||||||
|
|
||||||
return move;
|
return move;
|
||||||
// if (Net.isHost) {
|
// if (Net.isHost) {
|
||||||
// packets.push({b: packUpdate(move, timeState), c: this.connection != null ? this.connection.id : 0});
|
// packets.push({b: packUpdate(move, timeState), c: this.connection != null ? this.connection.id : 0});
|
||||||
|
|
@ -1770,7 +1782,7 @@ class Marble extends GameObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateClient(timeState:TimeState, pathedInteriors:Array<PathedInterior>) {
|
public function updateClient(timeState:TimeState, pathedInteriors:Array<PathedInterior>) {
|
||||||
this.level.updateBlast(this, timeState);
|
this.level.updateBlast(cast this, timeState);
|
||||||
if (oldPos != null && newPos != null) {
|
if (oldPos != null && newPos != null) {
|
||||||
var deltaT = physicsAccumulator / 0.032;
|
var deltaT = physicsAccumulator / 0.032;
|
||||||
var renderPos = Util.lerpThreeVectors(this.oldPos, this.newPos, deltaT);
|
var renderPos = Util.lerpThreeVectors(this.oldPos, this.newPos, deltaT);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package src;
|
package src;
|
||||||
|
|
||||||
|
import net.PowerupPredictionStore;
|
||||||
import net.MarblePredictionStore;
|
import net.MarblePredictionStore;
|
||||||
import net.MarblePredictionStore.MarblePrediction;
|
import net.MarblePredictionStore.MarblePrediction;
|
||||||
import net.MarbleUpdateQueue;
|
import net.MarbleUpdateQueue;
|
||||||
|
|
@ -207,6 +208,7 @@ class MarbleWorld extends Scheduler {
|
||||||
|
|
||||||
var clientMarbles:Map<GameConnection, Marble> = [];
|
var clientMarbles:Map<GameConnection, Marble> = [];
|
||||||
var predictions:MarblePredictionStore;
|
var predictions:MarblePredictionStore;
|
||||||
|
var powerupPredictions:PowerupPredictionStore;
|
||||||
|
|
||||||
public var lastMoves:MarbleUpdateQueue;
|
public var lastMoves:MarbleUpdateQueue;
|
||||||
|
|
||||||
|
|
@ -238,17 +240,18 @@ class MarbleWorld extends Scheduler {
|
||||||
this.scene2d = scene2d;
|
this.scene2d = scene2d;
|
||||||
this.mission = mission;
|
this.mission = mission;
|
||||||
this.game = mission.game.toLowerCase();
|
this.game = mission.game.toLowerCase();
|
||||||
this.gameMode = GameModeFactory.getGameMode(this, mission.missionInfo.gamemode);
|
this.gameMode = GameModeFactory.getGameMode(cast this, mission.missionInfo.gamemode);
|
||||||
this.replay = new Replay(mission.path, mission.isClaMission ? mission.id : 0);
|
this.replay = new Replay(mission.path, mission.isClaMission ? mission.id : 0);
|
||||||
this.isRecording = record;
|
this.isRecording = record;
|
||||||
this.rewindManager = new RewindManager(this);
|
this.rewindManager = new RewindManager(cast this);
|
||||||
this.inputRecorder = new InputRecorder(this);
|
this.inputRecorder = new InputRecorder(cast this);
|
||||||
this.isMultiplayer = multiplayer;
|
this.isMultiplayer = multiplayer;
|
||||||
if (this.isMultiplayer) {
|
if (this.isMultiplayer) {
|
||||||
isRecording = false;
|
isRecording = false;
|
||||||
isWatching = false;
|
isWatching = false;
|
||||||
lastMoves = new MarbleUpdateQueue();
|
lastMoves = new MarbleUpdateQueue();
|
||||||
predictions = new MarblePredictionStore();
|
predictions = new MarblePredictionStore();
|
||||||
|
powerupPredictions = new PowerupPredictionStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the network RNG for hunt
|
// Set the network RNG for hunt
|
||||||
|
|
@ -345,7 +348,7 @@ class MarbleWorld extends Scheduler {
|
||||||
this.playGui = new PlayGui();
|
this.playGui = new PlayGui();
|
||||||
this.instanceManager = new InstanceManager(scene);
|
this.instanceManager = new InstanceManager(scene);
|
||||||
this.particleManager = new ParticleManager(cast this);
|
this.particleManager = new ParticleManager(cast this);
|
||||||
this.radar = new Radar(this, this.scene2d);
|
this.radar = new Radar(cast this, this.scene2d);
|
||||||
radar.init();
|
radar.init();
|
||||||
|
|
||||||
var worker = new ResourceLoaderWorker(() -> {
|
var worker = new ResourceLoaderWorker(() -> {
|
||||||
|
|
@ -954,8 +957,13 @@ class MarbleWorld extends Scheduler {
|
||||||
var worker = new ResourceLoaderWorker(() -> {
|
var worker = new ResourceLoaderWorker(() -> {
|
||||||
obj.idInLevel = this.dtsObjects.length; // Set the id of the thing
|
obj.idInLevel = this.dtsObjects.length; // Set the id of the thing
|
||||||
this.dtsObjects.push(obj);
|
this.dtsObjects.push(obj);
|
||||||
if (obj is PowerUp)
|
if (obj is PowerUp) {
|
||||||
|
var pw:PowerUp = cast obj;
|
||||||
|
pw.netIndex = this.powerUps.length;
|
||||||
this.powerUps.push(cast obj);
|
this.powerUps.push(cast obj);
|
||||||
|
if (Net.isClient)
|
||||||
|
powerupPredictions.alloc();
|
||||||
|
}
|
||||||
if (obj is ForceObject) {
|
if (obj is ForceObject) {
|
||||||
this.forceObjects.push(cast obj);
|
this.forceObjects.push(cast obj);
|
||||||
}
|
}
|
||||||
|
|
@ -1141,13 +1149,16 @@ class MarbleWorld extends Scheduler {
|
||||||
advanceTimeState.dt = 0.032;
|
advanceTimeState.dt = 0.032;
|
||||||
advanceTimeState.ticks = ourLastMoveTime;
|
advanceTimeState.ticks = ourLastMoveTime;
|
||||||
|
|
||||||
if (marbleNeedsPrediction & (1 << Net.clientId) > 0) {
|
if (marbleNeedsPrediction > 0) {
|
||||||
if (qm != null) {
|
// if (qm != null) {
|
||||||
var mvs = qm.powerupStates.copy();
|
// var mvs = qm.powerupStates.copy();
|
||||||
for (pw in marble.level.powerUps) {
|
for (pw in marble.level.powerUps) {
|
||||||
pw.lastPickUpTime = mvs.shift();
|
// var val = mvs.shift();
|
||||||
}
|
// if (pw.lastPickUpTime != val)
|
||||||
|
// Console.log('Revert powerup pickup: ${pw.lastPickUpTime} -> ${val}');
|
||||||
|
pw.lastPickUpTime = powerupPredictions.getState(pw.netIndex);
|
||||||
}
|
}
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
ackLag = ourQueuedMoves.length;
|
ackLag = ourQueuedMoves.length;
|
||||||
|
|
@ -1188,7 +1199,6 @@ class MarbleWorld extends Scheduler {
|
||||||
var m = move.move;
|
var m = move.move;
|
||||||
// Debug.drawSphere(@:privateAccess this.marble.newPos, this.marble._radius);
|
// Debug.drawSphere(@:privateAccess this.marble.newPos, this.marble._radius);
|
||||||
if (marbleNeedsPrediction & (1 << Net.clientId) > 0) {
|
if (marbleNeedsPrediction & (1 << Net.clientId) > 0) {
|
||||||
this.marble.heldPowerup = move.powerup;
|
|
||||||
@:privateAccess this.marble.moveMotionDir = move.motionDir;
|
@:privateAccess this.marble.moveMotionDir = move.motionDir;
|
||||||
@:privateAccess this.marble.advancePhysics(advanceTimeState, m, this.collisionWorld, this.pathedInteriors);
|
@:privateAccess this.marble.advancePhysics(advanceTimeState, m, this.collisionWorld, this.pathedInteriors);
|
||||||
this.predictions.storeState(this.marble, move.timeState.ticks);
|
this.predictions.storeState(this.marble, move.timeState.ticks);
|
||||||
|
|
@ -1475,12 +1485,14 @@ class MarbleWorld extends Scheduler {
|
||||||
ProfilerUI.measure("updateAudio");
|
ProfilerUI.measure("updateAudio");
|
||||||
AudioManager.update(this.scene);
|
AudioManager.update(this.scene);
|
||||||
|
|
||||||
if (this.marble.outOfBounds
|
if (!this.isMultiplayer) {
|
||||||
&& this.finishTime == null
|
if (this.marble.outOfBounds
|
||||||
&& (Key.isDown(Settings.controlsSettings.jump) || Gamepad.isDown(Settings.gamepadSettings.jump))
|
&& this.finishTime == null
|
||||||
&& !this.isWatching) {
|
&& (Key.isDown(Settings.controlsSettings.jump) || Gamepad.isDown(Settings.gamepadSettings.jump))
|
||||||
this.restart(this.marble);
|
&& !this.isWatching) {
|
||||||
return;
|
this.restart(this.marble);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isWatching) {
|
if (!this.isWatching) {
|
||||||
|
|
@ -1689,8 +1701,8 @@ class MarbleWorld extends Scheduler {
|
||||||
this.helpTextTimeState = this.timeState.timeSinceLoad;
|
this.helpTextTimeState = this.timeState.timeSinceLoad;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function pickUpGem(gem:Gem) {
|
public function pickUpGem(marble:Marble, gem:Gem) {
|
||||||
this.gameMode.onGemPickup(gem);
|
this.gameMode.onGemPickup(marble, gem);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function callCollisionHandlers(marble:Marble, timeState:TimeState, start:Vector, end:Vector) {
|
public function callCollisionHandlers(marble:Marble, timeState:TimeState, start:Vector, end:Vector) {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ interface GameMode {
|
||||||
public function onTimeExpire():Void;
|
public function onTimeExpire():Void;
|
||||||
public function onRestart():Void;
|
public function onRestart():Void;
|
||||||
public function onRespawn(marble:Marble):Void;
|
public function onRespawn(marble:Marble):Void;
|
||||||
public function onGemPickup(gem:Gem):Void;
|
public function onGemPickup(marble:Marble, gem:Gem):Void;
|
||||||
|
|
||||||
public function getPreloadFiles():Array<String>;
|
public function getPreloadFiles():Array<String>;
|
||||||
public function constructRewindState():RewindableState;
|
public function constructRewindState():RewindableState;
|
||||||
|
|
|
||||||
|
|
@ -282,25 +282,32 @@ class HuntMode extends NullMode {
|
||||||
@:privateAccess level.playGui.formatGemHuntCounter(points);
|
@:privateAccess level.playGui.formatGemHuntCounter(points);
|
||||||
}
|
}
|
||||||
|
|
||||||
override function onGemPickup(gem:Gem) {
|
override function onGemPickup(marble:Marble, gem:Gem) {
|
||||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/gem_collect.wav', ResourceLoader.getAudio, @:privateAccess this.level.soundResources));
|
if (marble == level.marble)
|
||||||
|
AudioManager.playSound(ResourceLoader.getResource('data/sound/gem_collect.wav', ResourceLoader.getAudio,
|
||||||
|
@:privateAccess this.level.soundResources));
|
||||||
|
else
|
||||||
|
AudioManager.playSound(ResourceLoader.getResource('data/sound/opponent_gem_collect.wav', ResourceLoader.getAudio,
|
||||||
|
@:privateAccess this.level.soundResources));
|
||||||
activeGems.remove(gem);
|
activeGems.remove(gem);
|
||||||
var beam = gemToBeamMap.get(gem);
|
var beam = gemToBeamMap.get(gem);
|
||||||
beam.setHide(true);
|
beam.setHide(true);
|
||||||
refillGemGroups();
|
refillGemGroups();
|
||||||
|
|
||||||
switch (gem.gemColor) {
|
if (marble == level.marble) {
|
||||||
case "red.gem":
|
switch (gem.gemColor) {
|
||||||
points += 1;
|
case "red.gem":
|
||||||
@:privateAccess level.playGui.addMiddleMessage('+1', 0xFF6666);
|
points += 1;
|
||||||
case "yellow.gem":
|
@:privateAccess level.playGui.addMiddleMessage('+1', 0xFF6666);
|
||||||
points += 2;
|
case "yellow.gem":
|
||||||
@:privateAccess level.playGui.addMiddleMessage('+2', 0xFFFF66);
|
points += 2;
|
||||||
case "blue.gem":
|
@:privateAccess level.playGui.addMiddleMessage('+2', 0xFFFF66);
|
||||||
points += 5;
|
case "blue.gem":
|
||||||
@:privateAccess level.playGui.addMiddleMessage('+5', 0x6666FF);
|
points += 5;
|
||||||
|
@:privateAccess level.playGui.addMiddleMessage('+5', 0x6666FF);
|
||||||
|
}
|
||||||
|
@:privateAccess level.playGui.formatGemHuntCounter(points);
|
||||||
}
|
}
|
||||||
@:privateAccess level.playGui.formatGemHuntCounter(points);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupGems() {
|
function setupGems() {
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class NullMode implements GameMode {
|
||||||
|
|
||||||
public function onRespawn(marble:Marble) {}
|
public function onRespawn(marble:Marble) {}
|
||||||
|
|
||||||
public function onGemPickup(gem:Gem) {
|
public function onGemPickup(marble:Marble, gem:Gem) {
|
||||||
this.level.gemCount++;
|
this.level.gemCount++;
|
||||||
var string:String;
|
var string:String;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package net;
|
package net;
|
||||||
|
|
||||||
|
import haxe.io.FPHelper;
|
||||||
import haxe.io.BytesOutput;
|
import haxe.io.BytesOutput;
|
||||||
import haxe.io.BytesInput;
|
import haxe.io.BytesInput;
|
||||||
import haxe.io.Bytes;
|
import haxe.io.Bytes;
|
||||||
|
|
@ -64,7 +65,7 @@ class InputBitStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readFloat() {
|
public function readFloat() {
|
||||||
return readInt32();
|
return FPHelper.i32ToFloat(readInt32());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,4 +130,8 @@ class OutputBitStream {
|
||||||
this.data.writeByte(this.lastByte);
|
this.data.writeByte(this.lastByte);
|
||||||
return this.data.getBytes();
|
return this.data.getBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function writeFloat(value:Float) {
|
||||||
|
writeInt(FPHelper.floatToI32(value), 32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ class MarblePrediction {
|
||||||
var omega:Vector;
|
var omega:Vector;
|
||||||
var isControl:Bool;
|
var isControl:Bool;
|
||||||
var blastAmount:Int;
|
var blastAmount:Int;
|
||||||
|
var powerupItemId:Int;
|
||||||
|
|
||||||
public function new(marble:Marble, tick:Int) {
|
public function new(marble:Marble, tick:Int) {
|
||||||
this.tick = tick;
|
this.tick = tick;
|
||||||
|
|
@ -22,11 +23,14 @@ class MarblePrediction {
|
||||||
omega = @:privateAccess marble.omega.clone();
|
omega = @:privateAccess marble.omega.clone();
|
||||||
blastAmount = @:privateAccess marble.blastTicks;
|
blastAmount = @:privateAccess marble.blastTicks;
|
||||||
isControl = @:privateAccess marble.controllable;
|
isControl = @:privateAccess marble.controllable;
|
||||||
|
powerupItemId = marble.heldPowerup != null ? marble.heldPowerup.netIndex : 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function getError(p:MarbleUpdatePacket) {
|
public inline function getError(p:MarbleUpdatePacket) {
|
||||||
// Just doing position errors is enough to make it work
|
// Just doing position errors is enough to make it work
|
||||||
var subs = position.sub(p.position).lengthSq(); // + velocity.sub(p.velocity).lengthSq() + omega.sub(p.omega).lengthSq();
|
var subs = position.sub(p.position).lengthSq(); // + velocity.sub(p.velocity).lengthSq() + omega.sub(p.omega).lengthSq();
|
||||||
|
if (p.powerUpId != powerupItemId)
|
||||||
|
subs += 1;
|
||||||
// if (isControl)
|
// if (isControl)
|
||||||
// subs += Math.abs(blastAmount - p.blastAmount);
|
// subs += Math.abs(blastAmount - p.blastAmount);
|
||||||
return subs;
|
return subs;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package net;
|
package net;
|
||||||
|
|
||||||
|
import net.BitStream.OutputBitStream;
|
||||||
|
import net.BitStream.InputBitStream;
|
||||||
import net.NetPacket.MarbleUpdatePacket;
|
import net.NetPacket.MarbleUpdatePacket;
|
||||||
import shapes.PowerUp;
|
import shapes.PowerUp;
|
||||||
import net.NetPacket.MarbleMovePacket;
|
import net.NetPacket.MarbleMovePacket;
|
||||||
|
|
@ -23,9 +25,6 @@ class NetMove {
|
||||||
var move:Move;
|
var move:Move;
|
||||||
var id:Int;
|
var id:Int;
|
||||||
var timeState:TimeState;
|
var timeState:TimeState;
|
||||||
// For rewind purposes
|
|
||||||
var powerup:PowerUp;
|
|
||||||
var powerupStates:Array<Float>;
|
|
||||||
|
|
||||||
public function new(move:Move, motionDir:Vector, timeState:TimeState, id:Int) {
|
public function new(move:Move, motionDir:Vector, timeState:TimeState, id:Int) {
|
||||||
this.move = move;
|
this.move = move;
|
||||||
|
|
@ -96,17 +95,12 @@ class MoveManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
var netMove = new NetMove(move, motionDir, timeState.clone(), nextMoveId++);
|
var netMove = new NetMove(move, motionDir, timeState.clone(), nextMoveId++);
|
||||||
netMove.powerup = marble.heldPowerup;
|
|
||||||
netMove.powerupStates = [];
|
|
||||||
for (pw in marble.level.powerUps) {
|
|
||||||
netMove.powerupStates.push(pw.lastPickUpTime);
|
|
||||||
}
|
|
||||||
queuedMoves.push(netMove);
|
queuedMoves.push(netMove);
|
||||||
|
|
||||||
if (nextMoveId >= 65535) // 65535 is reserved for null move
|
if (nextMoveId >= 65535) // 65535 is reserved for null move
|
||||||
nextMoveId = 0;
|
nextMoveId = 0;
|
||||||
|
|
||||||
var b = new haxe.io.BytesOutput();
|
var b = new OutputBitStream();
|
||||||
var movePacket = new MarbleMovePacket();
|
var movePacket = new MarbleMovePacket();
|
||||||
movePacket.clientId = Net.clientId;
|
movePacket.clientId = Net.clientId;
|
||||||
movePacket.move = netMove;
|
movePacket.move = netMove;
|
||||||
|
|
@ -119,7 +113,7 @@ class MoveManager {
|
||||||
return netMove;
|
return netMove;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static inline function packMove(m:NetMove, b:haxe.io.BytesOutput) {
|
public static inline function packMove(m:NetMove, b:OutputBitStream) {
|
||||||
b.writeUInt16(m.id);
|
b.writeUInt16(m.id);
|
||||||
b.writeByte(Std.int((m.move.d.x * 16) + 16));
|
b.writeByte(Std.int((m.move.d.x * 16) + 16));
|
||||||
b.writeByte(Std.int((m.move.d.y * 16) + 16));
|
b.writeByte(Std.int((m.move.d.y * 16) + 16));
|
||||||
|
|
@ -137,7 +131,7 @@ class MoveManager {
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static inline function unpackMove(b:haxe.io.BytesInput) {
|
public static inline function unpackMove(b:InputBitStream) {
|
||||||
var moveId = b.readUInt16();
|
var moveId = b.readUInt16();
|
||||||
var move = new Move();
|
var move = new Move();
|
||||||
move.d = new Vector();
|
move.d = new Vector();
|
||||||
|
|
@ -155,7 +149,7 @@ class MoveManager {
|
||||||
return netMove;
|
return netMove;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function queueMove(m:NetMove) {
|
public inline function queueMove(m:NetMove) {
|
||||||
queuedMoves.push(m);
|
queuedMoves.push(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,7 +163,7 @@ class MoveManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueueSize() {
|
public inline function getQueueSize() {
|
||||||
return queuedMoves.length;
|
return queuedMoves.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
package net;
|
package net;
|
||||||
|
|
||||||
|
import net.BitStream.InputBitStream;
|
||||||
|
import net.BitStream.OutputBitStream;
|
||||||
|
import net.NetPacket.PowerupPickupPacket;
|
||||||
import net.ClientConnection;
|
import net.ClientConnection;
|
||||||
import net.NetPacket.MarbleUpdatePacket;
|
import net.NetPacket.MarbleUpdatePacket;
|
||||||
import net.NetPacket.MarbleMovePacket;
|
import net.NetPacket.MarbleMovePacket;
|
||||||
|
|
@ -20,6 +23,7 @@ enum abstract NetPacketType(Int) from Int to Int {
|
||||||
var PingBack;
|
var PingBack;
|
||||||
var MarbleUpdate;
|
var MarbleUpdate;
|
||||||
var MarbleMove;
|
var MarbleMove;
|
||||||
|
var PowerupPickup;
|
||||||
var PlayerInfo;
|
var PlayerInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,7 +145,7 @@ class Net {
|
||||||
haxe.Timer.delay(() -> connectedCb(), 1500); // 1.5 second delay to do the RTT calculation
|
haxe.Timer.delay(() -> connectedCb(), 1500); // 1.5 second delay to do the RTT calculation
|
||||||
}
|
}
|
||||||
clientDatachannel.onMessage = (b) -> {
|
clientDatachannel.onMessage = (b) -> {
|
||||||
onPacketReceived(client, clientDatachannel, new haxe.io.BytesInput(b));
|
onPacketReceived(client, clientDatachannel, new InputBitStream(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
isMP = true;
|
isMP = true;
|
||||||
|
|
@ -155,7 +159,7 @@ class Net {
|
||||||
clients.set(c, new ClientConnection(clientId, c, dc));
|
clients.set(c, new ClientConnection(clientId, c, dc));
|
||||||
clientIdMap[clientId] = clients[c];
|
clientIdMap[clientId] = clients[c];
|
||||||
dc.onMessage = (msgBytes) -> {
|
dc.onMessage = (msgBytes) -> {
|
||||||
onPacketReceived(c, dc, new haxe.io.BytesInput(msgBytes));
|
onPacketReceived(c, dc, new InputBitStream(msgBytes));
|
||||||
}
|
}
|
||||||
var b = haxe.io.Bytes.alloc(3);
|
var b = haxe.io.Bytes.alloc(3);
|
||||||
b.set(0, ClientIdAssign);
|
b.set(0, ClientIdAssign);
|
||||||
|
|
@ -194,7 +198,7 @@ class Net {
|
||||||
return b.getBytes();
|
return b.getBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
static function onPacketReceived(c:RTCPeerConnection, dc:RTCDataChannel, input:haxe.io.BytesInput) {
|
static function onPacketReceived(c:RTCPeerConnection, dc:RTCDataChannel, input:InputBitStream) {
|
||||||
var packetType = input.readByte();
|
var packetType = input.readByte();
|
||||||
switch (packetType) {
|
switch (packetType) {
|
||||||
case NetCommand:
|
case NetCommand:
|
||||||
|
|
@ -250,6 +254,14 @@ class Net {
|
||||||
var cc = clientIdMap[movePacket.clientId];
|
var cc = clientIdMap[movePacket.clientId];
|
||||||
cc.moveManager.queueMove(movePacket.move);
|
cc.moveManager.queueMove(movePacket.move);
|
||||||
|
|
||||||
|
case PowerupPickup:
|
||||||
|
var powerupPickupPacket = new PowerupPickupPacket();
|
||||||
|
powerupPickupPacket.deserialize(input);
|
||||||
|
if (MarbleGame.instance.world != null) {
|
||||||
|
var m = @:privateAccess MarbleGame.instance.world.powerupPredictions;
|
||||||
|
m.acknowledgePowerupPickup(powerupPickupPacket, MarbleGame.instance.world.timeState, clientConnection.moveManager.getQueueSize());
|
||||||
|
}
|
||||||
|
|
||||||
case PlayerInfo:
|
case PlayerInfo:
|
||||||
var count = input.readByte();
|
var count = input.readByte();
|
||||||
for (i in 0...count) {
|
for (i in 0...count) {
|
||||||
|
|
@ -265,14 +277,14 @@ class Net {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function sendPacketToAll(packetData:haxe.io.BytesOutput) {
|
public static function sendPacketToAll(packetData:OutputBitStream) {
|
||||||
var bytes = packetData.getBytes();
|
var bytes = packetData.getBytes();
|
||||||
for (c => v in clients) {
|
for (c => v in clients) {
|
||||||
v.sendBytes(bytes);
|
v.sendBytes(bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function sendPacketToHost(packetData:haxe.io.BytesOutput) {
|
public static function sendPacketToHost(packetData:OutputBitStream) {
|
||||||
var bytes = packetData.getBytes();
|
var bytes = packetData.getBytes();
|
||||||
clientDatachannel.sendBytes(bytes);
|
clientDatachannel.sendBytes(bytes);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
package net;
|
package net;
|
||||||
|
|
||||||
|
import net.BitStream.InputBitStream;
|
||||||
|
import net.BitStream.OutputBitStream;
|
||||||
import h3d.Vector;
|
import h3d.Vector;
|
||||||
import net.MoveManager.NetMove;
|
import net.MoveManager.NetMove;
|
||||||
|
|
||||||
interface NetPacket {
|
interface NetPacket {
|
||||||
public function serialize(b:haxe.io.BytesOutput):Void;
|
public function serialize(b:OutputBitStream):Void;
|
||||||
public function deserialize(b:haxe.io.BytesInput):Void;
|
public function deserialize(b:InputBitStream):Void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@:publicFields
|
@:publicFields
|
||||||
|
|
@ -16,13 +18,13 @@ class MarbleMovePacket implements NetPacket {
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|
||||||
public inline function deserialize(b:haxe.io.BytesInput) {
|
public inline function deserialize(b:InputBitStream) {
|
||||||
clientId = b.readUInt16();
|
clientId = b.readUInt16();
|
||||||
clientTicks = b.readUInt16();
|
clientTicks = b.readUInt16();
|
||||||
move = MoveManager.unpackMove(b);
|
move = MoveManager.unpackMove(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function serialize(b:haxe.io.BytesOutput) {
|
public inline function serialize(b:OutputBitStream) {
|
||||||
b.writeUInt16(clientId);
|
b.writeUInt16(clientId);
|
||||||
b.writeUInt16(clientTicks);
|
b.writeUInt16(clientTicks);
|
||||||
MoveManager.packMove(move, b);
|
MoveManager.packMove(move, b);
|
||||||
|
|
@ -43,11 +45,12 @@ class MarbleUpdatePacket implements NetPacket {
|
||||||
var megaTick:Int;
|
var megaTick:Int;
|
||||||
var heliTick:Int;
|
var heliTick:Int;
|
||||||
var oob:Bool;
|
var oob:Bool;
|
||||||
|
var powerUpId:Int;
|
||||||
var moveQueueSize:Int;
|
var moveQueueSize:Int;
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|
||||||
public inline function serialize(b:haxe.io.BytesOutput) {
|
public inline function serialize(b:OutputBitStream) {
|
||||||
b.writeUInt16(clientId);
|
b.writeUInt16(clientId);
|
||||||
MoveManager.packMove(move, b);
|
MoveManager.packMove(move, b);
|
||||||
b.writeUInt16(serverTicks);
|
b.writeUInt16(serverTicks);
|
||||||
|
|
@ -66,9 +69,10 @@ class MarbleUpdatePacket implements NetPacket {
|
||||||
b.writeUInt16(heliTick);
|
b.writeUInt16(heliTick);
|
||||||
b.writeUInt16(megaTick);
|
b.writeUInt16(megaTick);
|
||||||
b.writeByte(oob ? 1 : 0);
|
b.writeByte(oob ? 1 : 0);
|
||||||
|
b.writeUInt16(powerUpId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function deserialize(b:haxe.io.BytesInput) {
|
public inline function deserialize(b:InputBitStream) {
|
||||||
clientId = b.readUInt16();
|
clientId = b.readUInt16();
|
||||||
move = MoveManager.unpackMove(b);
|
move = MoveManager.unpackMove(b);
|
||||||
serverTicks = b.readUInt16();
|
serverTicks = b.readUInt16();
|
||||||
|
|
@ -81,5 +85,27 @@ class MarbleUpdatePacket implements NetPacket {
|
||||||
heliTick = b.readUInt16();
|
heliTick = b.readUInt16();
|
||||||
megaTick = b.readUInt16();
|
megaTick = b.readUInt16();
|
||||||
oob = b.readByte() != 0;
|
oob = b.readByte() != 0;
|
||||||
|
powerUpId = b.readUInt16();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@:publicFields
|
||||||
|
class PowerupPickupPacket implements NetPacket {
|
||||||
|
var clientId:Int;
|
||||||
|
var serverTicks:Int;
|
||||||
|
var powerupItemId:Int;
|
||||||
|
|
||||||
|
public function new() {}
|
||||||
|
|
||||||
|
public inline function deserialize(b:InputBitStream) {
|
||||||
|
clientId = b.readUInt16();
|
||||||
|
serverTicks = b.readUInt16();
|
||||||
|
powerupItemId = b.readUInt16();
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function serialize(b:OutputBitStream) {
|
||||||
|
b.writeUInt16(clientId);
|
||||||
|
b.writeUInt16(serverTicks);
|
||||||
|
b.writeUInt16(powerupItemId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
src/net/PowerupPredictionStore.hx
Normal file
24
src/net/PowerupPredictionStore.hx
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
package net;
|
||||||
|
|
||||||
|
import src.TimeState;
|
||||||
|
import net.NetPacket.PowerupPickupPacket;
|
||||||
|
|
||||||
|
class PowerupPredictionStore {
|
||||||
|
var predictions:Array<Float>;
|
||||||
|
|
||||||
|
public function new() {
|
||||||
|
predictions = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alloc() {
|
||||||
|
predictions.push(Math.NEGATIVE_INFINITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function getState(netIndex:Int) {
|
||||||
|
return predictions[netIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function acknowledgePowerupPickup(packet:PowerupPickupPacket, timeState:TimeState, futureTicks:Int) {
|
||||||
|
predictions[packet.powerupItemId] = timeState.currentAttemptTime - futureTicks * 0.032; // Approximate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -59,7 +59,7 @@ class RPCMacro {
|
||||||
case EConst(CIdent("server")):
|
case EConst(CIdent("server")):
|
||||||
var lastExpr = macro {
|
var lastExpr = macro {
|
||||||
if (Net.isHost) {
|
if (Net.isHost) {
|
||||||
var stream = new haxe.io.BytesOutput();
|
var stream = new net.BitStream.OutputBitStream();
|
||||||
stream.writeByte(NetPacketType.NetCommand);
|
stream.writeByte(NetPacketType.NetCommand);
|
||||||
stream.writeByte($v{rpcFnId});
|
stream.writeByte($v{rpcFnId});
|
||||||
$b{serializeFns};
|
$b{serializeFns};
|
||||||
|
|
@ -72,7 +72,7 @@ class RPCMacro {
|
||||||
case EConst(CIdent("client")):
|
case EConst(CIdent("client")):
|
||||||
var lastExpr = macro {
|
var lastExpr = macro {
|
||||||
if (!Net.isHost) {
|
if (!Net.isHost) {
|
||||||
var stream = new haxe.io.BytesOutput();
|
var stream = new net.BitStream.OutputBitStream();
|
||||||
stream.writeByte(NetPacketType.NetCommand);
|
stream.writeByte(NetPacketType.NetCommand);
|
||||||
stream.writeByte($v{rpcFnId});
|
stream.writeByte($v{rpcFnId});
|
||||||
$b{serializeFns};
|
$b{serializeFns};
|
||||||
|
|
@ -113,7 +113,7 @@ class RPCMacro {
|
||||||
args: [
|
args: [
|
||||||
{
|
{
|
||||||
name: "stream",
|
name: "stream",
|
||||||
type: haxe.macro.TypeTools.toComplexType(Context.getType('haxe.io.Input'))
|
type: haxe.macro.TypeTools.toComplexType(Context.getType('net.BitStream.InputBitStream'))
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
expr: macro {
|
expr: macro {
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ class Gem extends DtsObject {
|
||||||
return;
|
return;
|
||||||
this.pickedUp = true;
|
this.pickedUp = true;
|
||||||
this.setOpacity(0); // Hide the gem
|
this.setOpacity(0); // Hide the gem
|
||||||
this.level.pickUpGem(this);
|
this.level.pickUpGem(marble, this);
|
||||||
// this.level.replay.recordMarbleInside(this);
|
// this.level.replay.recordMarbleInside(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
package shapes;
|
package shapes;
|
||||||
|
|
||||||
|
import net.BitStream.OutputBitStream;
|
||||||
|
import net.NetPacket.PowerupPickupPacket;
|
||||||
|
import net.Net;
|
||||||
import src.Marble;
|
import src.Marble;
|
||||||
import src.AudioManager;
|
import src.AudioManager;
|
||||||
import hxd.res.Sound;
|
import hxd.res.Sound;
|
||||||
|
|
@ -16,6 +19,7 @@ abstract class PowerUp extends DtsObject {
|
||||||
public var pickUpName:String;
|
public var pickUpName:String;
|
||||||
public var element:MissionElementItem;
|
public var element:MissionElementItem;
|
||||||
public var pickupSound:Sound;
|
public var pickupSound:Sound;
|
||||||
|
public var netIndex:Int;
|
||||||
|
|
||||||
var customPickupMessage:String = null;
|
var customPickupMessage:String = null;
|
||||||
|
|
||||||
|
|
@ -35,6 +39,17 @@ abstract class PowerUp extends DtsObject {
|
||||||
if (this.pickUp(marble)) {
|
if (this.pickUp(marble)) {
|
||||||
// this.level.replay.recordMarbleInside(this);
|
// this.level.replay.recordMarbleInside(this);
|
||||||
|
|
||||||
|
if (level.isMultiplayer && Net.isHost) {
|
||||||
|
var b = new OutputBitStream();
|
||||||
|
b.writeByte(NetPacketType.PowerupPickup);
|
||||||
|
var pickupPacket = new PowerupPickupPacket();
|
||||||
|
pickupPacket.clientId = @:privateAccess marble.connection != null ? @:privateAccess marble.connection.id : 0;
|
||||||
|
pickupPacket.serverTicks = timeState.ticks;
|
||||||
|
pickupPacket.powerupItemId = this.netIndex;
|
||||||
|
pickupPacket.serialize(b);
|
||||||
|
Net.sendPacketToAll(b);
|
||||||
|
}
|
||||||
|
|
||||||
this.lastPickUpTime = timeState.currentAttemptTime;
|
this.lastPickUpTime = timeState.currentAttemptTime;
|
||||||
if (this.autoUse)
|
if (this.autoUse)
|
||||||
this.use(marble, timeState);
|
this.use(marble, timeState);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue