mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
make client predict other marbles too
This commit is contained in:
parent
5ab1bb7a65
commit
1fef9a5bdc
6 changed files with 368 additions and 53 deletions
|
|
@ -21,6 +21,7 @@ class SignallingHandler extends WebSocketHandler {
|
|||
case StrMessage(content):
|
||||
var conts = Json.parse(content);
|
||||
if (conts.type == "connect") {
|
||||
trace('Connect received');
|
||||
var other = clients.find(x -> x != this);
|
||||
other.send(Json.stringify(conts.sdpObj));
|
||||
}
|
||||
|
|
|
|||
121
src/Marble.hx
121
src/Marble.hx
|
|
@ -1,5 +1,7 @@
|
|||
package src;
|
||||
|
||||
import net.MoveManager;
|
||||
import net.MoveManager.NetMove;
|
||||
import shaders.marble.CrystalMarb;
|
||||
import shaders.marble.ClassicMarb;
|
||||
import shapes.HelicopterImage;
|
||||
|
|
@ -286,6 +288,8 @@ class Marble extends GameObject {
|
|||
public var cubemapRenderer:CubemapRenderer;
|
||||
|
||||
var connection:net.Net.ClientConnection;
|
||||
var moveMotionDir:Vector;
|
||||
var isNetUpdate:Bool = false;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
|
@ -529,7 +533,7 @@ class Marble extends GameObject {
|
|||
var motiondir = new Vector(0, -1, 0);
|
||||
if (level.isReplayingMovement)
|
||||
return level.currentInputMoves[1].marbleAxes;
|
||||
if (this.controllable) {
|
||||
if (this.controllable && !this.isNetUpdate) {
|
||||
motiondir.transform(Matrix.R(0, 0, camera.CameraYaw));
|
||||
motiondir.transform(level.newOrientationQuat.toMatrix());
|
||||
var updir = this.level.currentUp;
|
||||
|
|
@ -539,7 +543,11 @@ class Marble extends GameObject {
|
|||
motiondir = updir.cross(sidedir);
|
||||
return [sidedir, motiondir, updir];
|
||||
} else {
|
||||
return [new Vector(1, 0, 0), motiondir, new Vector(0, 0, 1)];
|
||||
if (moveMotionDir != null)
|
||||
motiondir = moveMotionDir;
|
||||
var updir = this.level.currentUp;
|
||||
var sidedir = motiondir.cross(updir);
|
||||
return [sidedir, motiondir, updir];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -568,7 +576,7 @@ class Marble extends GameObject {
|
|||
for (contact in contacts) {
|
||||
if (contact.force != 0 && !forceObjects.contains(contact.otherObject)) {
|
||||
if (contact.otherObject is RoundBumper) {
|
||||
if (!level.isReplayingMovement && !playedSounds.contains("data/sound/bumperding1.wav")) {
|
||||
if (!level.isReplayingMovement && !playedSounds.contains("data/sound/bumperding1.wav") && !this.isNetUpdate) {
|
||||
AudioManager.playSound(ResourceLoader.getResource("data/sound/bumperding1.wav", ResourceLoader.getAudio, this.soundResources));
|
||||
playedSounds.push("data/sound/bumperding1.wav");
|
||||
}
|
||||
|
|
@ -808,7 +816,10 @@ class Marble extends GameObject {
|
|||
}
|
||||
if (sv < this._jumpImpulse) {
|
||||
this.velocity.load(this.velocity.add(bestContact.normal.multiply((this._jumpImpulse - sv))));
|
||||
if (!level.isReplayingMovement && !playedSounds.contains("data/sound/jump.wav")) {
|
||||
if (!level.isReplayingMovement
|
||||
&& !playedSounds.contains("data/sound/jump.wav")
|
||||
&& !this.isNetUpdate
|
||||
&& this.controllable) {
|
||||
AudioManager.playSound(ResourceLoader.getResource("data/sound/jump.wav", ResourceLoader.getAudio, this.soundResources));
|
||||
playedSounds.push("data/sound/jump.wav");
|
||||
}
|
||||
|
|
@ -888,7 +899,7 @@ class Marble extends GameObject {
|
|||
}
|
||||
|
||||
function bounceEmitter(speed:Float, normal:Vector) {
|
||||
if (!this.controllable || level.isReplayingMovement)
|
||||
if (!this.controllable || level.isReplayingMovement || this.isNetUpdate)
|
||||
return;
|
||||
if (this.bounceEmitDelay == 0 && this._minBounceSpeed <= speed) {
|
||||
this.level.particleManager.createEmitter(bounceParticleOptions, this.bounceEmitterData,
|
||||
|
|
@ -923,7 +934,7 @@ class Marble extends GameObject {
|
|||
}
|
||||
|
||||
function playBoundSound(time:Float, contactVel:Float) {
|
||||
if (level.isReplayingMovement)
|
||||
if (level.isReplayingMovement || this.isNetUpdate)
|
||||
return;
|
||||
if (minVelocityBounceSoft <= contactVel) {
|
||||
var hardBounceSpeed = minVelocityBounceHard;
|
||||
|
|
@ -1607,20 +1618,102 @@ class Marble extends GameObject {
|
|||
}
|
||||
|
||||
// MP Only Functions
|
||||
public function updateServer(timeState:TimeState, collisionWorld:CollisionWorld, pathedInteriors:Array<PathedInterior>) {
|
||||
var move:Move = null;
|
||||
if (this.controllable && this.mode != Finish && !MarbleGame.instance.paused && !this.level.isWatching && !this.level.isReplayingMovement) {
|
||||
move = recordMove();
|
||||
|
||||
public function packUpdate(move:NetMove) {
|
||||
var b = new haxe.io.BytesOutput();
|
||||
b.writeByte(NetPacketType.MarbleUpdate);
|
||||
b.writeUInt16(connection != null ? connection.id : 0);
|
||||
MoveManager.packMove(move, b);
|
||||
b.writeUInt16(this.level.ticks); // So we can get the clients to do stuff about it
|
||||
b.writeFloat(this.newPos.x);
|
||||
b.writeFloat(this.newPos.y);
|
||||
b.writeFloat(this.newPos.z);
|
||||
b.writeFloat(this.velocity.x);
|
||||
b.writeFloat(this.velocity.y);
|
||||
b.writeFloat(this.velocity.z);
|
||||
b.writeFloat(this.omega.x);
|
||||
b.writeFloat(this.omega.y);
|
||||
b.writeFloat(this.omega.z);
|
||||
return b.getBytes();
|
||||
}
|
||||
|
||||
public function unpackUpdate(b:haxe.io.BytesInput) {
|
||||
// Assume packet header is already read
|
||||
var serverMove = MoveManager.unpackMove(b);
|
||||
if (Net.isClient)
|
||||
Net.clientConnection.moveManager.acknowledgeMove(serverMove.id);
|
||||
var serverTicks = b.readUInt16();
|
||||
this.oldPos = this.newPos;
|
||||
this.newPos = new Vector(b.readFloat(), b.readFloat(), b.readFloat());
|
||||
this.collider.transform.setPosition(this.newPos);
|
||||
this.velocity = new Vector(b.readFloat(), b.readFloat(), b.readFloat());
|
||||
this.omega = new Vector(b.readFloat(), b.readFloat(), b.readFloat());
|
||||
|
||||
// Apply the moves we have queued
|
||||
if (Net.isClient) {
|
||||
this.isNetUpdate = true;
|
||||
if (this.controllable) {
|
||||
for (move in @:privateAccess Net.clientConnection.moveManager.queuedMoves) {
|
||||
moveMotionDir = move.motionDir;
|
||||
advancePhysics(move.timeState, move.move, this.level.collisionWorld, this.level.pathedInteriors);
|
||||
}
|
||||
} else {
|
||||
var tickDiff = this.level.ticks - serverTicks;
|
||||
if (tickDiff > 0) {
|
||||
var timeState = this.level.timeState.clone();
|
||||
timeState.dt = 0.032;
|
||||
var m = serverMove.move;
|
||||
moveMotionDir = serverMove.motionDir;
|
||||
for (o in 0...tickDiff) {
|
||||
advancePhysics(timeState, m, this.level.collisionWorld, this.level.pathedInteriors);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.isNetUpdate = false;
|
||||
}
|
||||
if (!this.controllable && this.connection != null) {
|
||||
move = new Move();
|
||||
move.d = new Vector(0, 0);
|
||||
}
|
||||
|
||||
public function updateServer(timeState:TimeState, collisionWorld:CollisionWorld, pathedInteriors:Array<PathedInterior>, packets:Array<haxe.io.Bytes>) {
|
||||
var move:NetMove = null;
|
||||
if (this.controllable && this.mode != Finish && !MarbleGame.instance.paused && !this.level.isWatching && !this.level.isReplayingMovement) {
|
||||
if (Net.isClient) {
|
||||
var axis = getMarbleAxis()[1];
|
||||
move = Net.clientConnection.moveManager.recordMove(axis, timeState);
|
||||
} else if (Net.isHost) {
|
||||
var axis = getMarbleAxis()[1];
|
||||
var innerMove = recordMove();
|
||||
move = new NetMove(innerMove, axis, timeState, 65535);
|
||||
}
|
||||
}
|
||||
var moveId = 65535;
|
||||
if (!this.controllable && this.connection != null && Net.isHost) {
|
||||
var nextMove = this.connection.moveManager.getNextMove();
|
||||
if (nextMove == null) {
|
||||
var axis = getMarbleAxis()[1];
|
||||
var innerMove = new Move();
|
||||
innerMove.d = new Vector(0, 0);
|
||||
move = new NetMove(innerMove, axis, timeState, 65535);
|
||||
} else {
|
||||
move = nextMove;
|
||||
moveMotionDir = nextMove.motionDir;
|
||||
moveId = nextMove.id;
|
||||
}
|
||||
}
|
||||
if (move == null) {
|
||||
var axis = getMarbleAxis()[1];
|
||||
var innerMove = new Move();
|
||||
innerMove.d = new Vector(0, 0);
|
||||
move = new NetMove(innerMove, axis, timeState, 65535);
|
||||
}
|
||||
|
||||
playedSounds = [];
|
||||
advancePhysics(timeState, move, collisionWorld, pathedInteriors);
|
||||
advancePhysics(timeState, move.move, collisionWorld, pathedInteriors);
|
||||
|
||||
physicsAccumulator = 0;
|
||||
|
||||
if (Net.isHost) {
|
||||
packets.push(packUpdate(move));
|
||||
}
|
||||
}
|
||||
|
||||
public function updateClient(timeState:TimeState, pathedInteriors:Array<PathedInterior>) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package src;
|
||||
|
||||
import net.MoveManager;
|
||||
import net.NetCommands;
|
||||
import net.Net;
|
||||
import net.Net.ClientConnection;
|
||||
|
|
@ -195,6 +196,9 @@ class MarbleWorld extends Scheduler {
|
|||
|
||||
public var startRealTime:Float = 0;
|
||||
public var multiplayerStarted:Bool = false;
|
||||
public var ticks:Int = 0; // How many 32ms ticks have happened
|
||||
|
||||
var tickAccumulator:Float = 0.0;
|
||||
|
||||
var clientMarbles:Map<ClientConnection, Marble> = [];
|
||||
|
||||
|
|
@ -233,6 +237,10 @@ class MarbleWorld extends Scheduler {
|
|||
this.rewindManager = new RewindManager(this);
|
||||
this.inputRecorder = new InputRecorder(this);
|
||||
this.isMultiplayer = multiplayer;
|
||||
if (this.isMultiplayer) {
|
||||
isRecording = false;
|
||||
isWatching = false;
|
||||
}
|
||||
|
||||
// Set the network RNG for hunt
|
||||
if (isMultiplayer && gameMode is modes.HuntMode && Net.isHost) {
|
||||
|
|
@ -1055,16 +1063,13 @@ class MarbleWorld extends Scheduler {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Key.isPressed(Key.T)) {
|
||||
rollback(0.4);
|
||||
}
|
||||
|
||||
var realDt = dt;
|
||||
|
||||
if ((Key.isDown(Settings.controlsSettings.rewind)
|
||||
|| MarbleGame.instance.touchInput.rewindButton.pressed
|
||||
|| Gamepad.isDown(Settings.gamepadSettings.rewind))
|
||||
&& Settings.optionsSettings.rewindEnabled
|
||||
&& !this.isMultiplayer
|
||||
&& !this.isWatching
|
||||
&& this.finishTime == null) {
|
||||
this.rewinding = true;
|
||||
|
|
@ -1072,7 +1077,8 @@ class MarbleWorld extends Scheduler {
|
|||
if ((Key.isReleased(Settings.controlsSettings.rewind)
|
||||
|| !MarbleGame.instance.touchInput.rewindButton.pressed
|
||||
|| Gamepad.isReleased(Settings.gamepadSettings.rewind))
|
||||
&& this.rewinding) {
|
||||
&& this.rewinding
|
||||
&& !this.isMultiplayer) {
|
||||
if (this.isRecording) {
|
||||
this.replay.spliceReplay(timeState.currentAttemptTime);
|
||||
}
|
||||
|
|
@ -1207,9 +1213,35 @@ class MarbleWorld extends Scheduler {
|
|||
}
|
||||
|
||||
ProfilerUI.measure("updateMarbles");
|
||||
marble.update(timeState, collisionWorld, this.pathedInteriors);
|
||||
for (client => marble in clientMarbles) {
|
||||
if (this.isMultiplayer) {
|
||||
tickAccumulator += timeState.dt;
|
||||
while (tickAccumulator >= 0.032) {
|
||||
var fixedDt = timeState.clone();
|
||||
fixedDt.dt = 0.032;
|
||||
tickAccumulator -= 0.032;
|
||||
var packets = [];
|
||||
marble.updateServer(fixedDt, collisionWorld, pathedInteriors, packets);
|
||||
for (client => marble in clientMarbles) {
|
||||
marble.updateServer(fixedDt, collisionWorld, pathedInteriors, packets);
|
||||
}
|
||||
if (Net.isHost) {
|
||||
for (client => marble in clientMarbles) { // Oh no!
|
||||
for (packet in packets) {
|
||||
client.datachannel.sendBytes(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
ticks++;
|
||||
}
|
||||
marble.updateClient(timeState, this.pathedInteriors);
|
||||
for (client => marble in clientMarbles) {
|
||||
marble.updateClient(timeState, this.pathedInteriors);
|
||||
}
|
||||
} else {
|
||||
marble.update(timeState, collisionWorld, this.pathedInteriors);
|
||||
for (client => marble in clientMarbles) {
|
||||
marble.update(timeState, collisionWorld, this.pathedInteriors);
|
||||
}
|
||||
}
|
||||
_cubemapNeedsUpdate = true;
|
||||
Renderer.dirtyBuffers = true;
|
||||
|
|
@ -1243,7 +1275,7 @@ class MarbleWorld extends Scheduler {
|
|||
}
|
||||
}
|
||||
|
||||
if (!this.rewinding && Settings.optionsSettings.rewindEnabled)
|
||||
if (!this.rewinding && Settings.optionsSettings.rewindEnabled && !this.isMultiplayer)
|
||||
this.rewindManager.recordFrame();
|
||||
|
||||
if (!this.isReplayingMovement) {
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ class SphereCollisionEntity extends CollisionEntity {
|
|||
contact.collider = this;
|
||||
contact.friction = 1;
|
||||
contact.restitution = 1;
|
||||
contact.velocity = this.velocity;
|
||||
contact.velocity = this.velocity.clone();
|
||||
contact.otherObject = this.go;
|
||||
contact.point = position.add(normDist);
|
||||
contact.normal = normDist.multiply(-1);
|
||||
|
|
@ -102,9 +102,9 @@ class SphereCollisionEntity extends CollisionEntity {
|
|||
othercontact.collider = collisionEntity;
|
||||
othercontact.friction = 1;
|
||||
othercontact.restitution = 1;
|
||||
othercontact.velocity = this.velocity;
|
||||
othercontact.point = thispos.add(position).multiply(0.5);
|
||||
othercontact.normal = contact.point.sub(position).normalized();
|
||||
othercontact.velocity = collisionEntity.velocity.clone();
|
||||
othercontact.point = thispos.sub(normDist);
|
||||
othercontact.normal = normDist.clone();
|
||||
othercontact.contactDistance = contact.point.distance(position);
|
||||
othercontact.force = 0;
|
||||
othercontact.penetration = this.radius - (thispos.sub(othercontact.point).dot(othercontact.normal));
|
||||
|
|
|
|||
157
src/net/MoveManager.hx
Normal file
157
src/net/MoveManager.hx
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
package net;
|
||||
|
||||
import src.TimeState;
|
||||
import src.Console;
|
||||
import net.Net.ClientConnection;
|
||||
import net.Net.NetPacketType;
|
||||
import src.MarbleWorld;
|
||||
import src.Marble.Move;
|
||||
import h3d.Vector;
|
||||
import src.Gamepad;
|
||||
import src.Settings;
|
||||
import hxd.Key;
|
||||
import src.MarbleGame;
|
||||
import src.Util;
|
||||
|
||||
@:publicFields
|
||||
class NetMove {
|
||||
var motionDir:Vector;
|
||||
var move:Move;
|
||||
var id:Int;
|
||||
var timeState:TimeState;
|
||||
|
||||
public function new(move:Move, motionDir:Vector, timeState:TimeState, id:Int) {
|
||||
this.move = move;
|
||||
this.motionDir = motionDir;
|
||||
this.id = id;
|
||||
this.timeState = timeState;
|
||||
}
|
||||
}
|
||||
|
||||
class MoveManager {
|
||||
var connection:ClientConnection;
|
||||
var queuedMoves:Array<NetMove>;
|
||||
var nextMoveId:Int;
|
||||
var lastMove:NetMove;
|
||||
var lastAckMoveId:Int = -1;
|
||||
|
||||
static var maxMoves = 45; // Taken from Torque
|
||||
|
||||
public function new(connection:ClientConnection) {
|
||||
queuedMoves = [];
|
||||
nextMoveId = 0;
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
public function recordMove(motionDir:Vector, timeState:TimeState) {
|
||||
if (queuedMoves.length >= maxMoves)
|
||||
return queuedMoves[queuedMoves.length - 1];
|
||||
var move = new Move();
|
||||
move.d = new Vector();
|
||||
move.d.x = Gamepad.getAxis(Settings.gamepadSettings.moveYAxis);
|
||||
move.d.y = -Gamepad.getAxis(Settings.gamepadSettings.moveXAxis);
|
||||
if (Key.isDown(Settings.controlsSettings.forward)) {
|
||||
move.d.x -= 1;
|
||||
}
|
||||
if (Key.isDown(Settings.controlsSettings.backward)) {
|
||||
move.d.x += 1;
|
||||
}
|
||||
if (Key.isDown(Settings.controlsSettings.left)) {
|
||||
move.d.y += 1;
|
||||
}
|
||||
if (Key.isDown(Settings.controlsSettings.right)) {
|
||||
move.d.y -= 1;
|
||||
}
|
||||
if (Key.isDown(Settings.controlsSettings.jump)
|
||||
|| MarbleGame.instance.touchInput.jumpButton.pressed
|
||||
|| Gamepad.isDown(Settings.gamepadSettings.jump)) {
|
||||
move.jump = true;
|
||||
}
|
||||
if ((!Util.isTouchDevice() && Key.isDown(Settings.controlsSettings.powerup))
|
||||
|| (Util.isTouchDevice() && MarbleGame.instance.touchInput.powerupButton.pressed)
|
||||
|| Gamepad.isDown(Settings.gamepadSettings.powerup)) {
|
||||
move.powerup = true;
|
||||
}
|
||||
if (MarbleGame.instance.touchInput.movementInput.pressed) {
|
||||
move.d.y = -MarbleGame.instance.touchInput.movementInput.value.x;
|
||||
move.d.x = MarbleGame.instance.touchInput.movementInput.value.y;
|
||||
}
|
||||
|
||||
var netMove = new NetMove(move, motionDir, timeState.clone(), nextMoveId++);
|
||||
queuedMoves.push(netMove);
|
||||
|
||||
if (nextMoveId >= 65535) // 65535 is reserved for null move
|
||||
nextMoveId = 0;
|
||||
|
||||
var b = new haxe.io.BytesOutput();
|
||||
b.writeByte(NetPacketType.MarbleMove);
|
||||
b.writeUInt16(Net.clientId);
|
||||
|
||||
Net.sendPacketToHost(packMove(netMove, b));
|
||||
|
||||
return netMove;
|
||||
}
|
||||
|
||||
public static function packMove(m:NetMove, b:haxe.io.BytesOutput) {
|
||||
b.writeUInt16(m.id);
|
||||
b.writeFloat(m.move.d.x);
|
||||
b.writeFloat(m.move.d.y);
|
||||
var flags = 0;
|
||||
if (m.move.jump)
|
||||
flags |= 1;
|
||||
if (m.move.powerup)
|
||||
flags |= 2;
|
||||
b.writeByte(flags);
|
||||
b.writeFloat(m.motionDir.x);
|
||||
b.writeFloat(m.motionDir.y);
|
||||
b.writeFloat(m.motionDir.z);
|
||||
return b;
|
||||
}
|
||||
|
||||
public static function unpackMove(b:haxe.io.BytesInput) {
|
||||
var moveId = b.readUInt16();
|
||||
var move = new Move();
|
||||
move.d = new Vector();
|
||||
move.d.x = b.readFloat();
|
||||
move.d.y = b.readFloat();
|
||||
var flags = b.readByte();
|
||||
move.jump = (flags & 1) != 0;
|
||||
move.powerup = (flags & 2) != 0;
|
||||
var motionDir = new Vector();
|
||||
motionDir.x = b.readFloat();
|
||||
motionDir.y = b.readFloat();
|
||||
motionDir.z = b.readFloat();
|
||||
var netMove = new NetMove(move, motionDir, MarbleGame.instance.world.timeState.clone(), moveId);
|
||||
return netMove;
|
||||
}
|
||||
|
||||
public function queueMove(m:NetMove) {
|
||||
queuedMoves.push(m);
|
||||
}
|
||||
|
||||
public function getNextMove() {
|
||||
if (queuedMoves.length == 0)
|
||||
return lastMove;
|
||||
else {
|
||||
lastMove = queuedMoves[0];
|
||||
queuedMoves.shift();
|
||||
return lastMove;
|
||||
}
|
||||
}
|
||||
|
||||
public function acknowledgeMove(m:Int) {
|
||||
if (m == 65535 || m == -1)
|
||||
return;
|
||||
if (m <= lastAckMoveId)
|
||||
return; // Already acked
|
||||
if (queuedMoves.length == 0)
|
||||
return;
|
||||
while (m != queuedMoves[0].id) {
|
||||
trace('Ignoring move ${queuedMoves[0].id}, need ${m}');
|
||||
queuedMoves.shift();
|
||||
}
|
||||
if (m == queuedMoves[0].id)
|
||||
queuedMoves.shift();
|
||||
lastAckMoveId = m;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,8 @@ import datachannel.RTCDataChannel;
|
|||
import hx.ws.WebSocket;
|
||||
import src.Console;
|
||||
import net.NetCommands;
|
||||
import src.MarbleGame;
|
||||
import hx.ws.Types.MessageType;
|
||||
|
||||
enum abstract GameplayState(Int) from Int to Int {
|
||||
var UNKNOWN;
|
||||
|
|
@ -19,6 +21,8 @@ enum abstract NetPacketType(Int) from Int to Int {
|
|||
var NetCommand;
|
||||
var Ping;
|
||||
var PingBack;
|
||||
var MarbleUpdate;
|
||||
var MarbleMove;
|
||||
}
|
||||
|
||||
@:publicFields
|
||||
|
|
@ -27,6 +31,7 @@ class ClientConnection {
|
|||
var socket:RTCPeerConnection;
|
||||
var datachannel:RTCDataChannel;
|
||||
var state:GameplayState;
|
||||
var moveManager:MoveManager;
|
||||
var rtt:Float;
|
||||
var pingSendTime:Float;
|
||||
var _rttRecords:Array<Float> = [];
|
||||
|
|
@ -37,6 +42,7 @@ class ClientConnection {
|
|||
this.id = id;
|
||||
this.state = GameplayState.LOBBY;
|
||||
this.rtt = 0;
|
||||
this.moveManager = new MoveManager(this);
|
||||
}
|
||||
|
||||
public function ready() {
|
||||
|
|
@ -60,6 +66,7 @@ class Net {
|
|||
public static var networkRNG:Float;
|
||||
public static var clients:Map<RTCPeerConnection, ClientConnection> = [];
|
||||
public static var clientIdMap:Map<Int, ClientConnection> = [];
|
||||
public static var clientConnection:ClientConnection;
|
||||
|
||||
public static function hostServer() {
|
||||
// host = new RTCPeerConnection(["stun.l.google.com:19302"], "0.0.0.0");
|
||||
|
|
@ -76,41 +83,45 @@ class Net {
|
|||
switch (m) {
|
||||
case StrMessage(content):
|
||||
var conts = Json.parse(content);
|
||||
var peer = new RTCPeerConnection(["stun.l.google.com:19302"], "0.0.0.0");
|
||||
var peer = new RTCPeerConnection(["stun:stun.l.google.com:19302"], "0.0.0.0");
|
||||
peer.setRemoteDescription(conts.sdp, conts.type);
|
||||
addClient(peer);
|
||||
|
||||
var candidates = [];
|
||||
peer.onLocalCandidate = (c) -> {
|
||||
if (c != "")
|
||||
candidates.push('a=${c}');
|
||||
}
|
||||
peer.onGatheringStateChange = (s) -> {
|
||||
if (s == RTC_GATHERING_COMPLETE) {
|
||||
var sdpObj = StringTools.trim(peer.localDescription);
|
||||
sdpObj = sdpObj + '\r\n' + candidates.join('\r\n');
|
||||
masterWs.send(Json.stringify({
|
||||
type: "connect",
|
||||
sdpObj: {
|
||||
sdp: sdpObj,
|
||||
type: "offer"
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
peer.onDataChannel = (dc) -> {
|
||||
onClientConnect(peer, dc);
|
||||
};
|
||||
case _: {}
|
||||
case BytesMessage(content): {}
|
||||
}
|
||||
}
|
||||
|
||||
isMP = true;
|
||||
}
|
||||
|
||||
static function addClient(peer:RTCPeerConnection) {
|
||||
var candidates = [];
|
||||
peer.onLocalCandidate = (c) -> {
|
||||
if (c != "")
|
||||
candidates.push('a=${c}');
|
||||
}
|
||||
peer.onGatheringStateChange = (s) -> {
|
||||
if (s == RTC_GATHERING_COMPLETE) {
|
||||
var sdpObj = StringTools.trim(peer.localDescription);
|
||||
sdpObj = sdpObj + '\r\n' + candidates.join('\r\n');
|
||||
masterWs.send(Json.stringify({
|
||||
type: "connect",
|
||||
sdpObj: {
|
||||
sdp: sdpObj,
|
||||
type: "answer"
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
peer.onDataChannel = (dc:datachannel.RTCDataChannel) -> {
|
||||
onClientConnect(peer, dc);
|
||||
}
|
||||
}
|
||||
|
||||
public static function joinServer(connectedCb:() -> Void) {
|
||||
masterWs = new WebSocket("ws://localhost:8080");
|
||||
|
||||
client = new RTCPeerConnection(["stun.l.google.com:19302"], "0.0.0.0");
|
||||
client = new RTCPeerConnection(["stun:stun.l.google.com:19302"], "0.0.0.0");
|
||||
var candidates = [];
|
||||
|
||||
client.onLocalCandidate = (c) -> {
|
||||
|
|
@ -119,6 +130,7 @@ class Net {
|
|||
}
|
||||
client.onGatheringStateChange = (s) -> {
|
||||
if (s == RTC_GATHERING_COMPLETE) {
|
||||
Console.log("Local Description Set!");
|
||||
var sdpObj = StringTools.trim(client.localDescription);
|
||||
sdpObj = sdpObj + '\r\n' + candidates.join('\r\n');
|
||||
masterWs.send(Json.stringify({
|
||||
|
|
@ -134,6 +146,7 @@ class Net {
|
|||
masterWs.onmessage = (m) -> {
|
||||
switch (m) {
|
||||
case StrMessage(content):
|
||||
Console.log("Remote Description Received!");
|
||||
var conts = Json.parse(content);
|
||||
client.setRemoteDescription(conts.sdp, conts.type);
|
||||
case _: {}
|
||||
|
|
@ -142,8 +155,10 @@ class Net {
|
|||
|
||||
clientDatachannel = client.createDatachannel("mp");
|
||||
clientDatachannel.onOpen = (n) -> {
|
||||
Console.log("Successfully connected!");
|
||||
clients.set(client, new ClientConnection(0, client, clientDatachannel)); // host is always 0
|
||||
clientIdMap[0] = clients[client];
|
||||
clientConnection = clients[client];
|
||||
onConnectedToServer();
|
||||
haxe.Timer.delay(() -> connectedCb(), 1500); // 1.5 second delay to do the RTT calculation
|
||||
}
|
||||
|
|
@ -172,7 +187,7 @@ class Net {
|
|||
var b = haxe.io.Bytes.alloc(2);
|
||||
b.set(0, Ping);
|
||||
b.set(1, 3); // Count
|
||||
clients[c].pingSendTime = Sys.time();
|
||||
clients[c].pingSendTime = Console.time();
|
||||
dc.sendBytes(b);
|
||||
Console.log("Sending ping packet!");
|
||||
}
|
||||
|
|
@ -183,7 +198,7 @@ class Net {
|
|||
var b = haxe.io.Bytes.alloc(2);
|
||||
b.set(0, Ping);
|
||||
b.set(1, 3); // Count
|
||||
clients[client].pingSendTime = Sys.time();
|
||||
clients[client].pingSendTime = Console.time();
|
||||
clientDatachannel.sendBytes(b);
|
||||
Console.log("Sending ping packet!");
|
||||
}
|
||||
|
|
@ -210,7 +225,7 @@ class Net {
|
|||
var pingLeft = input.readByte();
|
||||
Console.log("Got pingback packet!");
|
||||
var conn = clients[c];
|
||||
var now = Sys.time();
|
||||
var now = Console.time();
|
||||
conn._rttRecords.push((now - conn.pingSendTime));
|
||||
if (pingLeft > 0) {
|
||||
conn.pingSendTime = now;
|
||||
|
|
@ -225,6 +240,23 @@ class Net {
|
|||
Console.log('Got RTT ${conn.rtt} for client ${conn.id}');
|
||||
}
|
||||
|
||||
case MarbleUpdate:
|
||||
var marbleClientId = input.readUInt16();
|
||||
if (marbleClientId == clientId) {
|
||||
if (MarbleGame.instance.world != null)
|
||||
MarbleGame.instance.world.marble.unpackUpdate(input);
|
||||
} else {
|
||||
var cc = clientIdMap[marbleClientId];
|
||||
if (MarbleGame.instance.world != null)
|
||||
@:privateAccess MarbleGame.instance.world.clientMarbles[cc].unpackUpdate(input);
|
||||
}
|
||||
|
||||
case MarbleMove:
|
||||
var marbleClientId = input.readUInt16();
|
||||
var cc = clientIdMap[marbleClientId];
|
||||
var m = MoveManager.unpackMove(input);
|
||||
cc.moveManager.queueMove(m);
|
||||
|
||||
case _:
|
||||
trace("unknown command: " + packetType);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue