add dummy connections

This commit is contained in:
RandomityGuy 2024-02-01 12:48:28 +05:30
parent d833ac8a2b
commit ef92860d89
11 changed files with 210 additions and 60 deletions

View file

@ -1,5 +1,6 @@
package src; package src;
import net.Net;
#if !js #if !js
import sys.FileSystem; import sys.FileSystem;
#end #end
@ -187,6 +188,8 @@ class Console {
} else if (cmdType == 'rollback') { } else if (cmdType == 'rollback') {
var t = Std.parseFloat(cmdSplit[1]); var t = Std.parseFloat(cmdSplit[1]);
MarbleGame.instance.world.rollback(t); MarbleGame.instance.world.rollback(t);
} else if (cmdType == 'addDummy') {
Net.addDummyConnection();
} else { } else {
error("Unknown command"); error("Unknown command");
} }

View file

@ -1,5 +1,7 @@
package src; package src;
import net.ClientConnection;
import net.ClientConnection.GameConnection;
import net.NetPacket.MarbleUpdatePacket; import net.NetPacket.MarbleUpdatePacket;
import net.MoveManager; import net.MoveManager;
import net.MoveManager.NetMove; import net.MoveManager.NetMove;
@ -292,7 +294,7 @@ class Marble extends GameObject {
public var cubemapRenderer:CubemapRenderer; public var cubemapRenderer:CubemapRenderer;
var connection:net.Net.ClientConnection; var connection:GameConnection;
var moveMotionDir:Vector; var moveMotionDir:Vector;
var lastMove:Move; var lastMove:Move;
var isNetUpdate:Bool = false; var isNetUpdate:Bool = false;
@ -332,7 +334,7 @@ class Marble extends GameObject {
this.helicopterSound.pause = true; this.helicopterSound.pause = true;
} }
public function init(level:MarbleWorld, connection:ClientConnection, onFinish:Void->Void) { public function init(level:MarbleWorld, connection:GameConnection, onFinish:Void->Void) {
this.level = level; this.level = level;
this.connection = connection; this.connection = connection;
if (this.level != null) if (this.level != null)
@ -1060,6 +1062,7 @@ class Marble extends GameObject {
searchbox.addSpherePos(position.x + velocity.x * deltaT, position.y + velocity.y * deltaT, position.z + velocity.z * deltaT, _radius); searchbox.addSpherePos(position.x + velocity.x * deltaT, position.y + velocity.y * deltaT, position.z + velocity.z * deltaT, _radius);
var foundObjs = this.collisionWorld.boundingSearch(searchbox); var foundObjs = this.collisionWorld.boundingSearch(searchbox);
foundObjs.push(this.collisionWorld.staticWorld);
var finalT = deltaT; var finalT = deltaT;
var found = false; var found = false;
@ -1102,7 +1105,7 @@ class Marble extends GameObject {
// var iterationFound = false; // var iterationFound = false;
for (obj in foundObjs) { for (obj in foundObjs) {
// Its an MP so bruh // Its an MP so bruh
if (!obj.go.isCollideable) if (obj.go != null && !obj.go.isCollideable)
continue; continue;
var invMatrix = @:privateAccess obj.invTransform; var invMatrix = @:privateAccess obj.invTransform;

View file

@ -7,7 +7,8 @@ import net.NetPacket.MarbleMovePacket;
import net.MoveManager; import net.MoveManager;
import net.NetCommands; import net.NetCommands;
import net.Net; import net.Net;
import net.Net.ClientConnection; import net.ClientConnection;
import net.ClientConnection.GameConnection;
import rewind.InputRecorder; import rewind.InputRecorder;
import gui.AchievementsGui; import gui.AchievementsGui;
import src.Radar; import src.Radar;
@ -203,7 +204,7 @@ class MarbleWorld extends Scheduler {
var tickAccumulator:Float = 0.0; var tickAccumulator:Float = 0.0;
var maxPredictionTicks:Int = 16; var maxPredictionTicks:Int = 16;
var clientMarbles:Map<ClientConnection, Marble> = []; var clientMarbles:Map<GameConnection, Marble> = [];
public var lastMoves:MarbleUpdateQueue; public var lastMoves:MarbleUpdateQueue;
@ -307,7 +308,7 @@ class MarbleWorld extends Scheduler {
this.gameMode.missionScan(this.mission); this.gameMode.missionScan(this.mission);
this.resourceLoadFuncs.push(fwd -> this.initScene(fwd)); this.resourceLoadFuncs.push(fwd -> this.initScene(fwd));
if (this.isMultiplayer) { if (this.isMultiplayer) {
for (client in Net.clients) { for (client in Net.clientIdMap) {
this.resourceLoadFuncs.push(fwd -> this.initMarble(client, fwd)); // Others this.resourceLoadFuncs.push(fwd -> this.initMarble(client, fwd)); // Others
} }
} }
@ -322,6 +323,7 @@ class MarbleWorld extends Scheduler {
public function postInit() { public function postInit() {
// Add the sky at the last so that cubemap reflections work // Add the sky at the last so that cubemap reflections work
this.collisionWorld.finalizeStaticGeometry();
this.playGui.init(this.scene2d, this.mission.game.toLowerCase()); this.playGui.init(this.scene2d, this.mission.game.toLowerCase());
this.scene.addChild(this.sky); this.scene.addChild(this.sky);
this._ready = true; this._ready = true;
@ -415,7 +417,7 @@ class MarbleWorld extends Scheduler {
worker.run(); worker.run();
} }
public function initMarble(client:ClientConnection, onFinish:Void->Void) { public function initMarble(client:GameConnection, onFinish:Void->Void) {
Console.log("Initializing marble"); Console.log("Initializing marble");
var worker = new ResourceLoaderWorker(onFinish); var worker = new ResourceLoaderWorker(onFinish);
var marblefiles = [ var marblefiles = [
@ -767,8 +769,11 @@ class MarbleWorld extends Scheduler {
var tmat = Matrix.T(interiorPosition.x, interiorPosition.y, interiorPosition.z); var tmat = Matrix.T(interiorPosition.x, interiorPosition.y, interiorPosition.z);
mat.multiply(mat, tmat); mat.multiply(mat, tmat);
if (hasCollision)
this.collisionWorld.addStaticInterior(interior.collider, mat);
interior.isCollideable = false;
interior.setTransform(mat); interior.setTransform(mat);
interior.isCollideable = hasCollision;
onFinish(); onFinish();
}); });
@ -886,7 +891,7 @@ class MarbleWorld extends Scheduler {
public function addInterior(obj:InteriorObject, onFinish:Void->Void) { public function addInterior(obj:InteriorObject, onFinish:Void->Void) {
this.interiors.push(obj); this.interiors.push(obj);
obj.init(cast this, () -> { obj.init(cast this, () -> {
this.collisionWorld.addEntity(obj.collider); // this.collisionWorld.addEntity(obj.collider);
if (obj.useInstancing) if (obj.useInstancing)
this.instanceManager.addObject(obj); this.instanceManager.addObject(obj);
else else
@ -970,7 +975,7 @@ class MarbleWorld extends Scheduler {
}); });
} }
public function addMarble(marble:Marble, client:ClientConnection, onFinish:Void->Void) { public function addMarble(marble:Marble, client:GameConnection, onFinish:Void->Void) {
marble.level = cast this; marble.level = cast this;
if (marble.controllable) { if (marble.controllable) {
marble.init(cast this, client, () -> { marble.init(cast this, client, () -> {
@ -1379,7 +1384,7 @@ class MarbleWorld extends Scheduler {
// return (a.c == client.id) ? 1 : (b.c == client.id) ? -1 : 0; // return (a.c == client.id) ? 1 : (b.c == client.id) ? -1 : 0;
// }); // });
for (packet in packets) { for (packet in packets) {
client.datachannel.sendBytes(packet); client.sendBytes(packet);
} }
} }
} }

View file

@ -40,6 +40,7 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
public var userData:Int; public var userData:Int;
public var fastTransform:Bool = false; public var fastTransform:Bool = false;
public var isWorldStatic:Bool = false;
var _transformKey:Int = 0; var _transformKey:Int = 0;
@ -187,6 +188,11 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
var tform = transform.clone(); var tform = transform.clone();
// tform.setPosition(tform.getPosition().add(this.velocity.multiply(timeState.dt))); // tform.setPosition(tform.getPosition().add(this.velocity.multiply(timeState.dt)));
if (isWorldStatic) {
tform.load(Matrix.I());
invtform.load(Matrix.I());
}
var contacts = []; var contacts = [];
for (obj in surfaces) { for (obj in surfaces) {
@ -246,7 +252,8 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
cinfo.force = surface.force; cinfo.force = surface.force;
cinfo.friction = surface.friction; cinfo.friction = surface.friction;
contacts.push(cinfo); contacts.push(cinfo);
this.go.onMarbleContact(collisionEntity.marble, timeState, cinfo); if (this.go != null)
this.go.onMarbleContact(collisionEntity.marble, timeState, cinfo);
// surfaceBestContact = cinfo; // surfaceBestContact = cinfo;
// } // }
} }

View file

@ -219,6 +219,42 @@ class CollisionSurface implements IOctreeObject implements IBVHObject {
new Vector(_transformedNormals[p1 * 3], _transformedNormals[p1 * 3 + 1], _transformedNormals[p1 * 3 + 2])); new Vector(_transformedNormals[p1 * 3], _transformedNormals[p1 * 3 + 1], _transformedNormals[p1 * 3 + 2]));
} }
public inline function getTriangle(idx:Int) {
var p1 = indices[idx];
var p2 = indices[idx + 1];
var p3 = indices[idx + 2];
return new TransformedCollisionTriangle(getPoint(p1), getPoint(p2), getPoint(p3), getNormal(p1));
}
public function getTransformed(m:Matrix, invtform:Matrix) {
var tformed = new CollisionSurface();
tformed.points = this.points.copy();
tformed.normals = this.normals.copy();
tformed.indices = this.indices.copy();
tformed.friction = this.friction;
tformed.force = this.force;
tformed.restitution = this.restitution;
tformed.transformKeys = this.transformKeys.copy();
for (i in 0...Std.int(points.length / 3)) {
var v = getPoint(i);
var v2 = v.transformed(m);
tformed.points[i * 3] = v2.x;
tformed.points[i * 3 + 1] = v2.y;
tformed.points[i * 3 + 2] = v2.z;
var n = getNormal(i);
var n2 = n.transformed3x3(invtform).normalized();
tformed.normals[i * 3] = n2.x;
tformed.normals[i * 3 + 1] = n2.y;
tformed.normals[i * 3 + 2] = n2.z;
}
tformed.generateBoundingBox();
return tformed;
}
public function dispose() { public function dispose() {
points = null; points = null;
normals = null; normals = null;

View file

@ -1,5 +1,6 @@
package collision; package collision;
import h3d.Matrix;
import src.MarbleGame; import src.MarbleGame;
import src.TimeState; import src.TimeState;
import h3d.col.Bounds; import h3d.col.Bounds;
@ -8,6 +9,7 @@ import h3d.Vector;
import octree.Octree; import octree.Octree;
class CollisionWorld { class CollisionWorld {
public var staticWorld:CollisionEntity;
public var octree:Octree; public var octree:Octree;
public var entities:Array<CollisionEntity> = []; public var entities:Array<CollisionEntity> = [];
public var dynamicEntities:Array<CollisionEntity> = []; public var dynamicEntities:Array<CollisionEntity> = [];
@ -20,6 +22,7 @@ class CollisionWorld {
public function new() { public function new() {
this.octree = new Octree(); this.octree = new Octree();
this.dynamicOctree = new Octree(); this.dynamicOctree = new Octree();
this.staticWorld = new CollisionEntity(null);
} }
public function sphereIntersection(spherecollision:SphereCollisionEntity, timeState:TimeState) { public function sphereIntersection(spherecollision:SphereCollisionEntity, timeState:TimeState) {
@ -50,6 +53,8 @@ class CollisionWorld {
} }
} }
contacts = contacts.concat(this.staticWorld.sphereIntersection(spherecollision, timeState));
var dynSearch = dynamicOctree.boundingSearch(box).map(x -> cast(x, CollisionEntity)); var dynSearch = dynamicOctree.boundingSearch(box).map(x -> cast(x, CollisionEntity));
for (obj in dynSearch) { for (obj in dynSearch) {
if (obj != spherecollision) { if (obj != spherecollision) {
@ -116,6 +121,7 @@ class CollisionWorld {
for (obj in objs) { for (obj in objs) {
results = results.concat(obj.rayCast(rayStart, rayDirection)); results = results.concat(obj.rayCast(rayStart, rayDirection));
} }
results = results.concat(this.staticWorld.rayCast(rayStart, rayDirection));
return results; return results;
} }
@ -153,6 +159,17 @@ class CollisionWorld {
} }
} }
public function addStaticInterior(entity:CollisionEntity, transform:Matrix) {
var invTform = transform.getInverse();
for (surf in entity.surfaces) {
staticWorld.addSurface(surf.getTransformed(transform, invTform));
}
}
public function finalizeStaticGeometry() {
this.staticWorld.finalize();
}
public function dispose() { public function dispose() {
for (e in entities) { for (e in entities) {
e.dispose(); e.dispose();
@ -165,5 +182,7 @@ class CollisionWorld {
dynamicEntities = null; dynamicEntities = null;
dynamicOctree = null; dynamicOctree = null;
dynamicEntitySet = null; dynamicEntitySet = null;
staticWorld.dispose();
staticWorld = null;
} }
} }

View file

@ -151,6 +151,7 @@ class HuntState implements RewindableState {
class HuntMode extends NullMode { class HuntMode extends NullMode {
var gemSpawnPoints:Array<GemSpawnSphere> = []; var gemSpawnPoints:Array<GemSpawnSphere> = [];
var playerSpawnPoints:Array<MissionElementSpawnSphere> = []; var playerSpawnPoints:Array<MissionElementSpawnSphere> = [];
var spawnPointTaken = [];
var gemOctree:Octree; var gemOctree:Octree;
var gemGroupRadius:Float; var gemGroupRadius:Float;
@ -170,8 +171,10 @@ class HuntMode extends NullMode {
if ([MissionElementType.SpawnSphere].contains(element._type)) { if ([MissionElementType.SpawnSphere].contains(element._type)) {
var spawnSphere:MissionElementSpawnSphere = cast element; var spawnSphere:MissionElementSpawnSphere = cast element;
var dbname = spawnSphere.datablock.toLowerCase(); var dbname = spawnSphere.datablock.toLowerCase();
if (dbname == "spawnspheremarker") if (dbname == "spawnspheremarker") {
playerSpawnPoints.push(spawnSphere); playerSpawnPoints.push(spawnSphere);
spawnPointTaken.push(false);
}
if (dbname == "gemspawnspheremarker") if (dbname == "gemspawnspheremarker")
gemSpawnPoints.push(new GemSpawnSphere(spawnSphere)); gemSpawnPoints.push(new GemSpawnSphere(spawnSphere));
} else if (element._type == MissionElementType.SimGroup) { } else if (element._type == MissionElementType.SimGroup) {
@ -183,7 +186,12 @@ class HuntMode extends NullMode {
}; };
override function getSpawnTransform() { override function getSpawnTransform() {
var randomSpawn = playerSpawnPoints[Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1))]; var idx = Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1));
while (spawnPointTaken[idx]) {
idx = Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1));
}
spawnPointTaken[idx] = true;
var randomSpawn = playerSpawnPoints[idx];
var spawnPos = MisParser.parseVector3(randomSpawn.position); var spawnPos = MisParser.parseVector3(randomSpawn.position);
spawnPos.x *= -1; spawnPos.x *= -1;
var spawnRot = MisParser.parseRotation(randomSpawn.rotation); var spawnRot = MisParser.parseRotation(randomSpawn.rotation);

View file

@ -0,0 +1,59 @@
package net;
import haxe.io.Bytes;
import datachannel.RTCPeerConnection;
import datachannel.RTCDataChannel;
import net.MoveManager;
enum abstract GameplayState(Int) from Int to Int {
var UNKNOWN;
var LOBBY;
var GAME;
}
@:publicFields
class ClientConnection extends GameConnection {
var socket:RTCPeerConnection;
var datachannel:RTCDataChannel;
var rtt:Float;
var pingSendTime:Float;
var _rttRecords:Array<Float> = [];
public function new(id:Int, socket:RTCPeerConnection, datachannel:RTCDataChannel) {
super(id);
this.socket = socket;
this.datachannel = datachannel;
this.state = GameplayState.LOBBY;
this.rtt = 0;
}
override function sendBytes(b:Bytes) {
datachannel.sendBytes(b);
}
}
@:publicFields
class DummyConnection extends GameConnection {
public function new(id:Int) {
super(id);
this.state = GameplayState.GAME;
}
}
@:publicFields
abstract class GameConnection {
var id:Int;
var state:GameplayState;
var moveManager:MoveManager;
public function new(id:Int) {
this.id = id;
this.moveManager = new MoveManager(this);
}
public function ready() {
state = GameplayState.GAME;
}
public function sendBytes(b:haxe.io.Bytes) {}
}

View file

@ -4,7 +4,7 @@ import shapes.PowerUp;
import net.NetPacket.MarbleMovePacket; import net.NetPacket.MarbleMovePacket;
import src.TimeState; import src.TimeState;
import src.Console; import src.Console;
import net.Net.ClientConnection; import net.ClientConnection;
import net.Net.NetPacketType; import net.Net.NetPacketType;
import src.MarbleWorld; import src.MarbleWorld;
import src.Marble.Move; import src.Marble.Move;
@ -38,7 +38,7 @@ class NetMove {
} }
class MoveManager { class MoveManager {
var connection:ClientConnection; var connection:GameConnection;
var queuedMoves:Array<NetMove>; var queuedMoves:Array<NetMove>;
var nextMoveId:Int; var nextMoveId:Int;
var lastMove:NetMove; var lastMove:NetMove;
@ -49,10 +49,12 @@ class MoveManager {
public var stall = false; public var stall = false;
public function new(connection:ClientConnection) { public function new(connection:GameConnection) {
queuedMoves = []; queuedMoves = [];
nextMoveId = 0; nextMoveId = 0;
this.connection = connection; this.connection = connection;
var mv = new Move();
mv.d = new Vector(0, 0);
} }
public function recordMove(marble:Marble, motionDir:Vector, timeState:TimeState) { public function recordMove(marble:Marble, motionDir:Vector, timeState:TimeState) {

View file

@ -1,5 +1,6 @@
package net; package net;
import net.ClientConnection;
import net.NetPacket.MarbleUpdatePacket; import net.NetPacket.MarbleUpdatePacket;
import net.NetPacket.MarbleMovePacket; import net.NetPacket.MarbleMovePacket;
import haxe.Json; import haxe.Json;
@ -11,12 +12,6 @@ import net.NetCommands;
import src.MarbleGame; import src.MarbleGame;
import hx.ws.Types.MessageType; import hx.ws.Types.MessageType;
enum abstract GameplayState(Int) from Int to Int {
var UNKNOWN;
var LOBBY;
var GAME;
}
enum abstract NetPacketType(Int) from Int to Int { enum abstract NetPacketType(Int) from Int to Int {
var NullPacket; var NullPacket;
var ClientIdAssign; var ClientIdAssign;
@ -25,31 +20,7 @@ enum abstract NetPacketType(Int) from Int to Int {
var PingBack; var PingBack;
var MarbleUpdate; var MarbleUpdate;
var MarbleMove; var MarbleMove;
} var PlayerInfo;
@:publicFields
class ClientConnection {
var id:Int;
var socket:RTCPeerConnection;
var datachannel:RTCDataChannel;
var state:GameplayState;
var moveManager:MoveManager;
var rtt:Float;
var pingSendTime:Float;
var _rttRecords:Array<Float> = [];
public function new(id:Int, socket:RTCPeerConnection, datachannel:RTCDataChannel) {
this.socket = socket;
this.datachannel = datachannel;
this.id = id;
this.state = GameplayState.LOBBY;
this.rtt = 0;
this.moveManager = new MoveManager(this);
}
public function ready() {
state = GameplayState.GAME;
}
} }
class Net { class Net {
@ -66,8 +37,8 @@ class Net {
public static var clientId:Int; public static var clientId:Int;
public static var networkRNG:Float; public static var networkRNG:Float;
public static var clients:Map<RTCPeerConnection, ClientConnection> = []; public static var clients:Map<RTCPeerConnection, GameConnection> = [];
public static var clientIdMap:Map<Int, ClientConnection> = []; public static var clientIdMap:Map<Int, GameConnection> = [];
public static var clientConnection:ClientConnection; public static var clientConnection:ClientConnection;
public static function hostServer() { public static function hostServer() {
@ -105,7 +76,7 @@ class Net {
peer.onGatheringStateChange = (s) -> { peer.onGatheringStateChange = (s) -> {
if (s == RTC_GATHERING_COMPLETE) { if (s == RTC_GATHERING_COMPLETE) {
var sdpObj = StringTools.trim(peer.localDescription); var sdpObj = StringTools.trim(peer.localDescription);
sdpObj = sdpObj + '\r\n' + candidates.join('\r\n'); sdpObj = sdpObj + '\r\n' + candidates.join('\r\n') + '\r\n';
masterWs.send(Json.stringify({ masterWs.send(Json.stringify({
type: "connect", type: "connect",
sdpObj: { sdpObj: {
@ -120,6 +91,11 @@ class Net {
} }
} }
static function addGhost(id:Int) {
var ghost = new DummyConnection(id);
clientIdMap[id] = ghost;
}
public static function joinServer(connectedCb:() -> Void) { public static function joinServer(connectedCb:() -> Void) {
masterWs = new WebSocket("ws://localhost:8080"); masterWs = new WebSocket("ws://localhost:8080");
masterWs.onopen = () -> { masterWs.onopen = () -> {
@ -134,7 +110,7 @@ class Net {
if (s == RTC_GATHERING_COMPLETE) { if (s == RTC_GATHERING_COMPLETE) {
Console.log("Local Description Set!"); Console.log("Local Description Set!");
var sdpObj = StringTools.trim(client.localDescription); var sdpObj = StringTools.trim(client.localDescription);
sdpObj = sdpObj + '\r\n' + candidates.join('\r\n'); sdpObj = sdpObj + '\r\n' + candidates.join('\r\n') + '\r\n';
masterWs.send(Json.stringify({ masterWs.send(Json.stringify({
type: "connect", type: "connect",
sdpObj: { sdpObj: {
@ -160,7 +136,7 @@ class Net {
Console.log("Successfully connected!"); Console.log("Successfully connected!");
clients.set(client, new ClientConnection(0, client, clientDatachannel)); // host is always 0 clients.set(client, new ClientConnection(0, client, clientDatachannel)); // host is always 0
clientIdMap[0] = clients[client]; clientIdMap[0] = clients[client];
clientConnection = clients[client]; clientConnection = cast clients[client];
onConnectedToServer(); onConnectedToServer();
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
} }
@ -190,7 +166,7 @@ class Net {
var b = haxe.io.Bytes.alloc(2); var b = haxe.io.Bytes.alloc(2);
b.set(0, Ping); b.set(0, Ping);
b.set(1, 3); // Count b.set(1, 3); // Count
clients[c].pingSendTime = Console.time(); cast(clients[c], ClientConnection).pingSendTime = Console.time();
dc.sendBytes(b); dc.sendBytes(b);
Console.log("Sending ping packet!"); Console.log("Sending ping packet!");
} }
@ -201,11 +177,23 @@ class Net {
var b = haxe.io.Bytes.alloc(2); var b = haxe.io.Bytes.alloc(2);
b.set(0, Ping); b.set(0, Ping);
b.set(1, 3); // Count b.set(1, 3); // Count
clients[client].pingSendTime = Console.time(); cast(clients[client], ClientConnection).pingSendTime = Console.time();
clientDatachannel.sendBytes(b); clientDatachannel.sendBytes(b);
Console.log("Sending ping packet!"); Console.log("Sending ping packet!");
} }
static function sendPlayerInfosBytes() {
var b = new haxe.io.BytesOutput();
b.writeByte(PlayerInfo);
var cnt = 0;
for (c in clientIdMap)
cnt++;
b.writeByte(cnt);
for (c => v in clientIdMap)
b.writeByte(c);
return b.getBytes();
}
static function onPacketReceived(c:RTCPeerConnection, dc:RTCDataChannel, input:haxe.io.BytesInput) { static function onPacketReceived(c:RTCPeerConnection, dc:RTCDataChannel, input:haxe.io.BytesInput) {
var packetType = input.readByte(); var packetType = input.readByte();
switch (packetType) { switch (packetType) {
@ -227,7 +215,7 @@ class Net {
case PingBack: case PingBack:
var pingLeft = input.readByte(); var pingLeft = input.readByte();
Console.log("Got pingback packet!"); Console.log("Got pingback packet!");
var conn = clients[c]; var conn:ClientConnection = cast clients[c];
var now = Console.time(); var now = Console.time();
conn._rttRecords.push((now - conn.pingSendTime)); conn._rttRecords.push((now - conn.pingSendTime));
if (pingLeft > 0) { if (pingLeft > 0) {
@ -241,6 +229,10 @@ class Net {
conn.rtt += r; conn.rtt += r;
conn.rtt /= conn._rttRecords.length; conn.rtt /= conn._rttRecords.length;
Console.log('Got RTT ${conn.rtt} for client ${conn.id}'); Console.log('Got RTT ${conn.rtt} for client ${conn.id}');
if (Net.isHost) {
var b = sendPlayerInfosBytes();
conn.sendBytes(b);
}
} }
case MarbleUpdate: case MarbleUpdate:
@ -258,15 +250,25 @@ class Net {
var cc = clientIdMap[movePacket.clientId]; var cc = clientIdMap[movePacket.clientId];
cc.moveManager.queueMove(movePacket.move); cc.moveManager.queueMove(movePacket.move);
case PlayerInfo:
var count = input.readByte();
for (i in 0...count) {
var id = input.readByte();
if (id != 0 && id != Net.clientId && !clientIdMap.exists(id)) {
Console.log('Adding ghost connection ${id}');
addGhost(id);
}
}
case _: case _:
trace("unknown command: " + packetType); Console.log("unknown command: " + packetType);
} }
} }
public static function sendPacketToAll(packetData:haxe.io.BytesOutput) { public static function sendPacketToAll(packetData:haxe.io.BytesOutput) {
var bytes = packetData.getBytes(); var bytes = packetData.getBytes();
for (c => v in clients) { for (c => v in clients) {
v.datachannel.sendBytes(packetData.getBytes()); v.sendBytes(bytes);
} }
} }
@ -274,4 +276,10 @@ class Net {
var bytes = packetData.getBytes(); var bytes = packetData.getBytes();
clientDatachannel.sendBytes(bytes); clientDatachannel.sendBytes(bytes);
} }
public static function addDummyConnection() {
if (Net.isHost) {
addGhost(Net.clientId++);
}
}
} }

View file

@ -1,6 +1,6 @@
package net; package net;
import net.Net.GameplayState; import net.ClientConnection.GameplayState;
import net.Net.NetPacketType; import net.Net.NetPacketType;
import gui.MultiplayerLevelSelectGui; import gui.MultiplayerLevelSelectGui;
import src.MarbleGame; import src.MarbleGame;
@ -46,7 +46,7 @@ class NetCommands {
@:rpc(server) public static function setStartTime(t:Float) { @:rpc(server) public static function setStartTime(t:Float) {
if (MarbleGame.instance.world != null) { if (MarbleGame.instance.world != null) {
if (Net.isClient) { if (Net.isClient) {
t -= Net.clientIdMap[0].rtt / 2; // Subtract receving time t -= cast(Net.clientIdMap[0], ClientConnection).rtt / 2; // Subtract receving time
} }
MarbleGame.instance.world.startRealTime = MarbleGame.instance.world.timeState.timeSinceLoad + t; MarbleGame.instance.world.startRealTime = MarbleGame.instance.world.timeState.timeSinceLoad + t;
} }