attempt at something

This commit is contained in:
RandomityGuy 2024-01-29 00:15:09 +05:30
parent b1ec446360
commit 42ec5701e3
8 changed files with 137 additions and 151 deletions

View file

@ -12,7 +12,8 @@ class Debug {
static var _triangles:Array<h3d.col.Point> = []; static var _triangles:Array<h3d.col.Point> = [];
static var _spheres:Array<{ static var _spheres:Array<{
position:Vector, position:Vector,
radius:Float radius:Float,
lifetime:Float
}> = []; }> = [];
static var debugTriangles:h3d.scene.Mesh; static var debugTriangles:h3d.scene.Mesh;
@ -20,7 +21,7 @@ class Debug {
public static function init() {} public static function init() {}
public static function update() { public static function update(dt:Float) {
if (_triangles.length != 0 && drawBounds) { if (_triangles.length != 0 && drawBounds) {
var prim = new h3d.prim.Polygon(_triangles.copy()); var prim = new h3d.prim.Polygon(_triangles.copy());
if (debugTriangles != null) { if (debugTriangles != null) {
@ -48,12 +49,17 @@ class Debug {
MarbleGame.instance.scene.addChild(debugSphere); MarbleGame.instance.scene.addChild(debugSphere);
} }
debugSphere.begin(_spheres.length); debugSphere.begin(_spheres.length);
var toremove = [];
for (sph in _spheres) { for (sph in _spheres) {
debugSphere.setPosition(sph.position.x, sph.position.y, sph.position.z); debugSphere.setPosition(sph.position.x, sph.position.y, sph.position.z);
debugSphere.setScale(sph.radius); debugSphere.setScale(sph.radius);
debugSphere.emitInstance(); debugSphere.emitInstance();
sph.lifetime -= dt;
if (sph.lifetime < 0)
toremove.push(sph);
} }
_spheres = []; for (sph in toremove)
_spheres.remove(sph);
} else { } else {
if (debugSphere != null) { if (debugSphere != null) {
debugSphere.remove(); debugSphere.remove();
@ -72,6 +78,6 @@ class Debug {
public static function drawSphere(centre:Vector, radius:Float) { public static function drawSphere(centre:Vector, radius:Float) {
if (drawBounds) if (drawBounds)
_spheres.push({position: centre.clone(), radius: radius}); _spheres.push({position: centre.clone(), radius: radius, lifetime: 0.032});
} }
} }

View file

@ -243,6 +243,7 @@ class Marble extends GameObject {
public var contacts:Array<CollisionInfo> = []; public var contacts:Array<CollisionInfo> = [];
public var bestContact:CollisionInfo; public var bestContact:CollisionInfo;
public var contactEntities:Array<CollisionEntity> = []; public var contactEntities:Array<CollisionEntity> = [];
public var collidingMarbles:Array<Marble> = [];
var queuedContacts:Array<CollisionInfo> = []; var queuedContacts:Array<CollisionInfo> = [];
var appliedImpulses:Array<{impulse:Vector, contactImpulse:Bool}> = []; var appliedImpulses:Array<{impulse:Vector, contactImpulse:Bool}> = [];
@ -295,6 +296,7 @@ class Marble extends GameObject {
var connection:net.Net.ClientConnection; var connection:net.Net.ClientConnection;
var moveMotionDir:Vector; var moveMotionDir:Vector;
var isNetUpdate:Bool = false; var isNetUpdate:Bool = false;
var collisionToken:Int = 0;
public function new() { public function new() {
super(); super();
@ -527,6 +529,11 @@ class Marble extends GameObject {
this.contacts = queuedContacts; this.contacts = queuedContacts;
var c = collisiomWorld.sphereIntersection(this.collider, timeState); var c = collisiomWorld.sphereIntersection(this.collider, timeState);
this.contactEntities = c.foundEntities; this.contactEntities = c.foundEntities;
this.collidingMarbles = [];
for (e in this.contacts) {
if (e.collider is SphereCollisionEntity)
this.collidingMarbles.push(cast(e.collider, SphereCollisionEntity).marble);
}
contacts = contacts.concat(c.contacts); contacts = contacts.concat(c.contacts);
} }
@ -1661,7 +1668,7 @@ class Marble extends GameObject {
newPos = this.collider.transform.getPosition(); newPos = this.collider.transform.getPosition();
if (this.prevPos != null) { if (this.prevPos != null && !this.isNetUpdate) {
var tempTimeState = timeState.clone(); var tempTimeState = timeState.clone();
tempTimeState.currentAttemptTime = passedTime; tempTimeState.currentAttemptTime = passedTime;
this.level.callCollisionHandlers(cast this, tempTimeState, oldPos, newPos); this.level.callCollisionHandlers(cast this, tempTimeState, oldPos, newPos);
@ -1697,7 +1704,7 @@ class Marble extends GameObject {
// } // }
this.oldPos = this.newPos; this.oldPos = this.newPos;
this.newPos = p.position; this.newPos = p.position;
this.collider.transform.setPosition(this.newPos); this.collider.transform.setPosition(p.position);
this.velocity = p.velocity; this.velocity = p.velocity;
this.omega = p.omega; this.omega = p.omega;
return true; return true;
@ -1739,6 +1746,12 @@ class Marble extends GameObject {
playedSounds = []; playedSounds = [];
advancePhysics(timeState, move.move, collisionWorld, pathedInteriors); advancePhysics(timeState, move.move, collisionWorld, pathedInteriors);
for (marble in this.collidingMarbles) {
marble.collisionToken = timeState.ticks;
}
if (this.collidingMarbles.length != 0)
this.collisionToken = timeState.ticks;
physicsAccumulator = 0; physicsAccumulator = 0;
if (Net.isHost) { if (Net.isHost) {

View file

@ -189,7 +189,7 @@ class MarbleGame {
world = null; world = null;
return; return;
} }
Debug.update(); Debug.update(dt);
if (Util.isTouchDevice()) { if (Util.isTouchDevice()) {
touchInput.update(); touchInput.update();
} }

View file

@ -1,5 +1,6 @@
package src; package src;
import net.MarbleUpdateQueue;
import haxe.Exception; import haxe.Exception;
import net.NetPacket.MarbleUpdatePacket; import net.NetPacket.MarbleUpdatePacket;
import net.NetPacket.MarbleMovePacket; import net.NetPacket.MarbleMovePacket;
@ -202,7 +203,7 @@ class MarbleWorld extends Scheduler {
var clientMarbles:Map<ClientConnection, Marble> = []; var clientMarbles:Map<ClientConnection, Marble> = [];
public var lastMoves:Map<Int, MarbleUpdatePacket> = []; public var lastMoves:MarbleUpdateQueue;
// Loading // Loading
var resourceLoadFuncs:Array<(() -> Void)->Void> = []; var resourceLoadFuncs:Array<(() -> Void)->Void> = [];
@ -242,6 +243,7 @@ class MarbleWorld extends Scheduler {
if (this.isMultiplayer) { if (this.isMultiplayer) {
isRecording = false; isRecording = false;
isWatching = false; isWatching = false;
lastMoves = new MarbleUpdateQueue();
} }
// Set the network RNG for hunt // Set the network RNG for hunt
@ -1023,180 +1025,113 @@ class MarbleWorld extends Scheduler {
} }
public function applyReceivedMoves() { public function applyReceivedMoves() {
if (!lastMoves[Net.clientId].applied) { if (!lastMoves.ourMoveApplied) {
var allApplied = false; var ourMove = lastMoves.myMarbleUpdate;
for (client => lastMove in lastMoves) { if (ourMove != null) {
if (lastMove.applied) { marble.unpackUpdate(ourMove);
allApplied = true; for (client => arr in lastMoves.otherMarbleUpdates) {
var lastMove = null;
while (arr.length > 0) {
var p = arr[0];
if (p.serverTicks <= ourMove.serverTicks && p.serverTicks >= ourMove.collisionToken) {
clientMarbles[Net.clientIdMap[client]].unpackUpdate(p);
lastMove = arr.shift();
} else {
break; break;
} }
} }
if (!allApplied) { if (lastMove != null)
for (client => lastMove in lastMoves) { arr.insert(0, lastMove);
var isApplied = lastMove.clientId == Net.clientId ? marble.unpackUpdate(lastMove) : clientMarbles[Net.clientIdMap[client]].unpackUpdate(lastMove);
} }
} }
} }
// for (client => lastMove in lastMoves) {
// if (lastMove.applied)
// continue;
// var isApplied = lastMove.clientId == Net.clientId ? marble.unpackUpdate(lastMove) : clientMarbles[Net.clientIdMap[client]].unpackUpdate(lastMove);
// if (!isApplied)
// lastMove.applied = true;
// }
} }
public function applyClientPrediction() { public function applyClientPrediction() {
// First acknowledge the marble's last move so we can get that over with // First acknowledge the marble's last move so we can get that over with
var ourLastMove = lastMoves[Net.clientId]; var ourLastMove = lastMoves.myMarbleUpdate;
if (ourLastMove == null) if (ourLastMove == null)
return; return;
var ackLag = -1; var ackLag = -1;
if (!ourLastMove.applied) if (!lastMoves.ourMoveApplied)
ackLag = Net.clientConnection.moveManager.acknowledgeMove(ourLastMove.move.id); ackLag = Net.clientConnection.moveManager.acknowledgeMove(ourLastMove.move.id);
else else
return; return;
var ourLastMoveTime = ourLastMove.serverTicks; var ourLastMoveTime = ourLastMove.serverTicks;
// Then find the minimum tick from which we need to begin our predictions from
var tickStart = timeState.ticks;
var ourQueuedMoves = @:privateAccess Net.clientConnection.moveManager.queuedMoves.copy(); var ourQueuedMoves = @:privateAccess Net.clientConnection.moveManager.queuedMoves.copy();
if (ourQueuedMoves.length > 0 && ourQueuedMoves[0].timeState.ticks < tickStart)
tickStart = ourQueuedMoves[0].timeState.ticks;
var advanceTimeState = timeState.clone(); var advanceTimeState = timeState.clone();
advanceTimeState.dt = 0.032; advanceTimeState.dt = 0.032;
/*
for (client => lastMove in lastMoves) {
if (lastMove.applied)
continue;
if (lastMove.serverTicks < tickStart)
tickStart = lastMove.serverTicks;
}
// Now actually do the sim, tick by tick
for (tick in tickStart...timeState.ticks) {
for (client => lastMove in lastMoves) {
if (lastMove.applied || (tick < lastMove.serverTicks && lastMove.clientId != Net.clientId))
continue;
var marbleToUpdate = lastMove.clientId == Net.clientId ? marble : clientMarbles[Net.clientIdMap[client]];
@:privateAccess marbleToUpdate.isNetUpdate = true;
if (marbleToUpdate == marble) {
if (ourQueuedMoves.length > 0) {
if (ourQueuedMoves[0].timeState.ticks <= tick) {
var move = ourQueuedMoves.shift();
Debug.drawSphere(@:privateAccess marbleToUpdate.newPos, marbleToUpdate._radius);
@:privateAccess marbleToUpdate.moveMotionDir = move.motionDir;
@:privateAccess marbleToUpdate.advancePhysics(advanceTimeState, move.move, this.collisionWorld, this.pathedInteriors);
}
} else {
lastMove.applied = true;
}
} else {
var m = lastMove.move.move;
Debug.drawSphere(@:privateAccess marbleToUpdate.newPos, marbleToUpdate._radius);
@:privateAccess marbleToUpdate.moveMotionDir = lastMove.move.motionDir;
@:privateAccess marbleToUpdate.advancePhysics(advanceTimeState, m, this.collisionWorld, this.pathedInteriors);
}
@:privateAccess marbleToUpdate.isNetUpdate = false;
}
}
*/
// Tick the remaining moves (ours) // Tick the remaining moves (ours)
if (!ourLastMove.applied) { if (!lastMoves.ourMoveApplied) {
@:privateAccess this.marble.isNetUpdate = true; @:privateAccess this.marble.isNetUpdate = true;
var totalTicksToDo = ourQueuedMoves.length; var totalTicksToDo = ourQueuedMoves.length;
var endTick = ourLastMoveTime + totalTicksToDo; var endTick = ourLastMoveTime + totalTicksToDo;
var currentTick = ourLastMoveTime;
var marblesToTick = new Map();
for (client => arr in lastMoves.otherMarbleUpdates) {
if (arr.length > 0) {
var m = arr[0];
if (m.serverTicks <= ourLastMoveTime && m.serverTicks >= ourLastMove.collisionToken) {
m.calculationTicks = Std.int(/*ourLastMoveTime - m.serverTicks + */ ourQueuedMoves.length);
marblesToTick.set(client, m);
arr.shift();
}
}
}
for (move in ourQueuedMoves) { for (move in ourQueuedMoves) {
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);
@: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);
if (this.marble.collidingMarbles.length > 0)
this.lastMoves.addCollisionFrame(currentTick);
// for (client => lastMove in lastMoves) { for (client => m in marblesToTick) {
// if (lastMove.clientId == Net.clientId || lastMove.calculationTicks >= endTick) if (m.calculationTicks > 0) {
// continue;
// trace('tick diff: ${lastMove.serverTicks - ourLastMoveTime}');
// lastMove.calculationTicks++;
// // lastMove.serverTicks++;
// var marbleToUpdate = clientMarbles[Net.clientIdMap[client]];
// @:privateAccess marbleToUpdate.isNetUpdate = true;
// var m = lastMove.move.move;
// @:privateAccess marbleToUpdate.moveMotionDir = lastMove.move.motionDir;
// @:privateAccess marbleToUpdate.advancePhysics(advanceTimeState, m, this.collisionWorld, this.pathedInteriors);
// @:privateAccess marbleToUpdate.isNetUpdate = false;
// }
}
for (client => lastMove in lastMoves) {
if (lastMove.clientId == Net.clientId)
continue;
// lastMove.calculationTicks++;
// lastMove.serverTicks++;
var tickDiff = ackLag + 1; // - (lastMove.serverTicks - ourLastMoveTime) + 1;
while (tickDiff > 0) {
var marbleToUpdate = clientMarbles[Net.clientIdMap[client]]; var marbleToUpdate = clientMarbles[Net.clientIdMap[client]];
Debug.drawSphere(@:privateAccess marbleToUpdate.newPos, marbleToUpdate._radius);
var mv = m.move.move;
@:privateAccess marbleToUpdate.isNetUpdate = true; @:privateAccess marbleToUpdate.isNetUpdate = true;
var m = lastMove.move.move; @:privateAccess marbleToUpdate.moveMotionDir = m.move.motionDir;
@:privateAccess marbleToUpdate.moveMotionDir = lastMove.move.motionDir; @:privateAccess marbleToUpdate.advancePhysics(advanceTimeState, mv, this.collisionWorld, this.pathedInteriors);
@:privateAccess marbleToUpdate.advancePhysics(advanceTimeState, m, this.collisionWorld, this.pathedInteriors);
@:privateAccess marbleToUpdate.isNetUpdate = false; @:privateAccess marbleToUpdate.isNetUpdate = false;
tickDiff--; if (marbleToUpdate.collidingMarbles.length > 0)
this.lastMoves.addCollisionFrame(currentTick);
m.calculationTicks--;
}
}
currentTick++;
}
for (client => m in marblesToTick) {
if (m.calculationTicks >= 0) {
var marbleToUpdate = clientMarbles[Net.clientIdMap[client]];
while (m.calculationTicks > 0) {
var mv = m.move.move;
@:privateAccess marbleToUpdate.isNetUpdate = true;
@:privateAccess marbleToUpdate.moveMotionDir = m.move.motionDir;
@:privateAccess marbleToUpdate.advancePhysics(advanceTimeState, mv, this.collisionWorld, this.pathedInteriors);
@:privateAccess marbleToUpdate.isNetUpdate = false;
if (marbleToUpdate.collidingMarbles.length > 0)
this.lastMoves.addCollisionFrame(currentTick);
m.calculationTicks--;
}
} }
} }
// if (ourQueuedMoves.length >= 2) { lastMoves.ourMoveApplied = true;
// trace('Move queue tick diff: ${ourQueuedMoves[ourQueuedMoves.length - 1].timeState.ticks - ourQueuedMoves[0].timeState.ticks}');
// }
ourLastMove.applied = true;
@:privateAccess this.marble.isNetUpdate = false; @:privateAccess this.marble.isNetUpdate = false;
} }
// for (client => lastMove in lastMoves) {
// if (lastMove.applied)
// continue;
// if (lastMove.serverTicks > timeState.ticks) {
// trace('Marble ticked ahead ${lastMove.serverTicks - timeState.ticks} ticks');
// lastMove.serverTicks = timeState.ticks;
// }
// if (lastMove.serverTicks < tickStart)
// tickStart = lastMove.serverTicks;
// }
// for (tick in tickStart...timeState.ticks) {
// for (client => lastMove in lastMoves) {
// if (lastMove.applied || tick < lastMove.serverTicks)
// continue;
// // if (lastMove.calculationTicks > 0) {
// // lastMove.calculationTicks--;
// // continue;
// // }
// var marbleToUpdate = clientMarbles[Net.clientIdMap[client]];
// @:privateAccess marbleToUpdate.isNetUpdate = true;
// var m = lastMove.move.move;
// Debug.drawSphere(@:privateAccess marbleToUpdate.newPos, marbleToUpdate._radius);
// @:privateAccess marbleToUpdate.moveMotionDir = lastMove.move.motionDir;
// @:privateAccess marbleToUpdate.advancePhysics(advanceTimeState, m, this.collisionWorld, this.pathedInteriors);
// @:privateAccess marbleToUpdate.isNetUpdate = false;
// }
// }
// Now mark them all as applied
for (client => lastMove in lastMoves) {
lastMove.applied = true;
}
} }
public function rollback(t:Float) { public function rollback(t:Float) {

View file

@ -0,0 +1,36 @@
package net;
import net.NetPacket.MarbleUpdatePacket;
import net.Net;
@:publicFields
class MarbleUpdateQueue {
var otherMarbleUpdates:Map<Int, Array<MarbleUpdatePacket>> = [];
var myMarbleUpdate:MarbleUpdatePacket;
var ourMoveApplied:Bool = false;
var collisionFrame:Int;
public function new() {}
public function enqueue(update:MarbleUpdatePacket) {
var cc = update.clientId;
if (update.serverTicks < collisionFrame)
return;
if (cc != Net.clientId) {
if (otherMarbleUpdates.exists(cc)) {
otherMarbleUpdates[cc].push(update);
} else {
otherMarbleUpdates[cc] = [update];
}
} else {
if (myMarbleUpdate == null || update.serverTicks > myMarbleUpdate.serverTicks) {
myMarbleUpdate = update;
ourMoveApplied = false;
}
}
}
public function addCollisionFrame(tick:Int) {
collisionFrame = tick + 2;
}
}

View file

@ -36,7 +36,7 @@ class MoveManager {
var lastMove:NetMove; var lastMove:NetMove;
var lastAckMoveId:Int = -1; var lastAckMoveId:Int = -1;
static var maxMoves = 32; static var maxMoves = 45;
public function new(connection:ClientConnection) { public function new(connection:ClientConnection) {
queuedMoves = []; queuedMoves = [];

View file

@ -248,12 +248,7 @@ class Net {
var cc = marbleUpdatePacket.clientId; var cc = marbleUpdatePacket.clientId;
if (MarbleGame.instance.world != null) { if (MarbleGame.instance.world != null) {
var m = MarbleGame.instance.world.lastMoves; var m = MarbleGame.instance.world.lastMoves;
if (m.exists(cc)) { m.enqueue(marbleUpdatePacket);
if (m[cc].serverTicks < marbleUpdatePacket.serverTicks)
m.set(cc, marbleUpdatePacket);
} else {
m.set(cc, marbleUpdatePacket);
}
} }
case MarbleMove: case MarbleMove:

View file

@ -34,11 +34,11 @@ class MarbleUpdatePacket implements NetPacket {
var clientId:Int; var clientId:Int;
var move:NetMove; var move:NetMove;
var serverTicks:Int; var serverTicks:Int;
var calculationTicks:Int; var calculationTicks:Int = -1;
var position:Vector; var position:Vector;
var velocity:Vector; var velocity:Vector;
var omega:Vector; var omega:Vector;
var applied:Bool = false; var collisionToken:Int;
public function new() {} public function new() {}
@ -46,6 +46,7 @@ class MarbleUpdatePacket implements NetPacket {
b.writeUInt16(clientId); b.writeUInt16(clientId);
MoveManager.packMove(move, b); MoveManager.packMove(move, b);
b.writeUInt16(serverTicks); b.writeUInt16(serverTicks);
b.writeUInt16(collisionToken);
b.writeFloat(position.x); b.writeFloat(position.x);
b.writeFloat(position.y); b.writeFloat(position.y);
b.writeFloat(position.z); b.writeFloat(position.z);
@ -61,7 +62,7 @@ class MarbleUpdatePacket implements NetPacket {
clientId = b.readUInt16(); clientId = b.readUInt16();
move = MoveManager.unpackMove(b); move = MoveManager.unpackMove(b);
serverTicks = b.readUInt16(); serverTicks = b.readUInt16();
calculationTicks = serverTicks; collisionToken = b.readUInt16();
position = new Vector(b.readFloat(), b.readFloat(), b.readFloat()); position = new Vector(b.readFloat(), b.readFloat(), b.readFloat());
velocity = new Vector(b.readFloat(), b.readFloat(), b.readFloat()); velocity = new Vector(b.readFloat(), b.readFloat(), b.readFloat());
omega = new Vector(b.readFloat(), b.readFloat(), b.readFloat()); omega = new Vector(b.readFloat(), b.readFloat(), b.readFloat());