mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
add dummy connections
This commit is contained in:
parent
d833ac8a2b
commit
ef92860d89
11 changed files with 210 additions and 60 deletions
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
59
src/net/ClientConnection.hx
Normal file
59
src/net/ClientConnection.hx
Normal 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) {}
|
||||||
|
}
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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++);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue