mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
attempt sync
This commit is contained in:
parent
086553d95a
commit
b1ec446360
7 changed files with 275 additions and 42 deletions
|
|
@ -53,6 +53,7 @@ class Debug {
|
|||
debugSphere.setScale(sph.radius);
|
||||
debugSphere.emitInstance();
|
||||
}
|
||||
_spheres = [];
|
||||
} else {
|
||||
if (debugSphere != null) {
|
||||
debugSphere.remove();
|
||||
|
|
|
|||
|
|
@ -702,6 +702,8 @@ class Marble extends GameObject {
|
|||
|
||||
normP.scale(1 + bounce);
|
||||
|
||||
velocity.load(velocity.sub(normP.multiply(ourMass)));
|
||||
|
||||
otherMarble.velocity.load(otherMarble.velocity.add(normP.multiply(1 / theirMass)));
|
||||
contacts[i].velocity.load(otherMarble.velocity);
|
||||
} else {
|
||||
|
|
@ -1048,7 +1050,8 @@ class Marble extends GameObject {
|
|||
found: false,
|
||||
foundContacts: [],
|
||||
lastContactPos: null,
|
||||
lastContactNormal: null
|
||||
lastContactNormal: null,
|
||||
foundMarbles: [],
|
||||
};
|
||||
}
|
||||
var searchbox = new Bounds();
|
||||
|
|
@ -1065,6 +1068,34 @@ class Marble extends GameObject {
|
|||
var testTriangles = [];
|
||||
|
||||
var finalContacts = [];
|
||||
var foundMarbles = [];
|
||||
|
||||
// Marble-Marble
|
||||
var nextPos = position.add(velocity.multiply(deltaT));
|
||||
for (marble in this.collisionWorld.marbleEntities) {
|
||||
if (marble == this.collider)
|
||||
continue;
|
||||
var otherPosition = marble.transform.getPosition();
|
||||
var isec = Collision.capsuleSphereNearestOverlap(position, nextPos, _radius, otherPosition, marble.radius);
|
||||
if (isec.result) {
|
||||
foundMarbles.push(marble);
|
||||
isec.t *= deltaT;
|
||||
if (isec.t >= finalT) {
|
||||
var vel = position.add(velocity.multiply(finalT)).sub(otherPosition);
|
||||
vel.normalize();
|
||||
var newVelLen = this.velocity.sub(marble.velocity).dot(vel);
|
||||
if (newVelLen < 0.0) {
|
||||
finalT = isec.t;
|
||||
|
||||
var posDiff = nextPos.sub(position).multiply(isec.t);
|
||||
var p = posDiff.add(position);
|
||||
lastContactNormal = p.sub(otherPosition);
|
||||
lastContactNormal.normalize();
|
||||
lastContactPos = p.sub(lastContactNormal.multiply(_radius));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for (iter in 0...10) {
|
||||
// var iterationFound = false;
|
||||
|
|
@ -1379,13 +1410,14 @@ class Marble extends GameObject {
|
|||
foundContacts: testTriangles,
|
||||
lastContactPos: lastContactPos,
|
||||
lastContactNormal: position.sub(lastContactPos).normalized(),
|
||||
foundMarbles: foundMarbles
|
||||
};
|
||||
}
|
||||
|
||||
function nudgeToContacts(position:Vector, radius:Float, foundContacts:Array<{
|
||||
v:Array<Vector>,
|
||||
n:Vector
|
||||
}>) {
|
||||
}>, foundMarbles:Array<SphereCollisionEntity>) {
|
||||
var it = 0;
|
||||
var concernedContacts = foundContacts; // PathedInteriors have their own nudge logic
|
||||
var prevResolved = 0;
|
||||
|
|
@ -1444,6 +1476,14 @@ class Marble extends GameObject {
|
|||
prevResolved = resolved;
|
||||
it++;
|
||||
} while (true && it < 10);
|
||||
for (marble in foundMarbles) {
|
||||
var marblePosition = marble.transform.getPosition();
|
||||
var dist = marblePosition.distance(position);
|
||||
if (dist < radius + marble.radius + 0.001) {
|
||||
var separatingDistance = position.sub(marblePosition).normalized();
|
||||
position = position.add(separatingDistance.multiply(radius + marble.radius + 0.001 - dist));
|
||||
}
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
|
|
@ -1547,7 +1587,7 @@ class Marble extends GameObject {
|
|||
}
|
||||
var expectedPos = finalPosData.position;
|
||||
// var newPos = expectedPos;
|
||||
var newPos = nudgeToContacts(expectedPos, _radius, finalPosData.foundContacts);
|
||||
var newPos = nudgeToContacts(expectedPos, _radius, finalPosData.foundContacts, finalPosData.foundMarbles);
|
||||
|
||||
if (this.velocity.lengthSq() > 1e-8) {
|
||||
var posDiff = newPos.sub(expectedPos);
|
||||
|
|
@ -1648,11 +1688,19 @@ class Marble extends GameObject {
|
|||
|
||||
public function unpackUpdate(p:MarbleUpdatePacket) {
|
||||
// Assume packet header is already read
|
||||
// Check if we aren't colliding with a marble
|
||||
// for (marble in this.level.collisionWorld.marbleEntities) {
|
||||
// if (marble != this.collider && marble.transform.getPosition().distance(p.position) < marble.radius + this._radius) {
|
||||
// Console.log("Marble updated inside another one!");
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
this.oldPos = this.newPos;
|
||||
this.newPos = p.position;
|
||||
this.collider.transform.setPosition(this.newPos);
|
||||
this.velocity = p.velocity;
|
||||
this.omega = p.omega;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function updateServer(timeState:TimeState, collisionWorld:CollisionWorld, pathedInteriors:Array<PathedInterior>, packets:Array<haxe.io.Bytes>) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package src;
|
||||
|
||||
import haxe.Exception;
|
||||
import net.NetPacket.MarbleUpdatePacket;
|
||||
import net.NetPacket.MarbleMovePacket;
|
||||
import net.MoveManager;
|
||||
|
|
@ -1022,48 +1023,178 @@ class MarbleWorld extends Scheduler {
|
|||
}
|
||||
|
||||
public function applyReceivedMoves() {
|
||||
if (!lastMoves[Net.clientId].applied) {
|
||||
var allApplied = false;
|
||||
for (client => lastMove in lastMoves) {
|
||||
if (lastMove.applied)
|
||||
continue;
|
||||
if (lastMove.clientId == Net.clientId)
|
||||
marble.unpackUpdate(lastMove);
|
||||
else
|
||||
clientMarbles[Net.clientIdMap[client]].unpackUpdate(lastMove);
|
||||
if (lastMove.applied) {
|
||||
allApplied = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!allApplied) {
|
||||
for (client => lastMove in lastMoves) {
|
||||
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() {
|
||||
// First acknowledge the marble's last move so we can get that over with
|
||||
var ourLastMove = lastMoves[Net.clientId];
|
||||
if (ourLastMove == null)
|
||||
return;
|
||||
var ackLag = -1;
|
||||
if (!ourLastMove.applied)
|
||||
ackLag = Net.clientConnection.moveManager.acknowledgeMove(ourLastMove.move.id);
|
||||
else
|
||||
return;
|
||||
|
||||
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();
|
||||
if (ourQueuedMoves.length > 0 && ourQueuedMoves[0].timeState.ticks < tickStart)
|
||||
tickStart = ourQueuedMoves[0].timeState.ticks;
|
||||
|
||||
var advanceTimeState = timeState.clone();
|
||||
advanceTimeState.dt = 0.032;
|
||||
/*
|
||||
for (client => lastMove in lastMoves) {
|
||||
if (lastMove.applied)
|
||||
continue;
|
||||
var marbleToUpdate = lastMove.clientId == Net.clientId ? marble : clientMarbles[Net.clientIdMap[client]];
|
||||
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) {
|
||||
var moveManager = @:privateAccess Net.clientConnection.moveManager;
|
||||
var catchUpTickCount = 0;
|
||||
Net.clientConnection.moveManager.acknowledgeMove(lastMove.move.id);
|
||||
var advanceTimeState = timeState.clone();
|
||||
advanceTimeState.dt = 0.032;
|
||||
for (move in @:privateAccess moveManager.queuedMoves) {
|
||||
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 {
|
||||
var tickDiff = timeState.ticks - lastMove.serverTicks;
|
||||
if (tickDiff > this.maxPredictionTicks)
|
||||
tickDiff = this.maxPredictionTicks;
|
||||
if (tickDiff > 0) {
|
||||
var advanceTimeState = timeState.clone();
|
||||
advanceTimeState.dt = 0.032;
|
||||
lastMove.applied = true;
|
||||
}
|
||||
} else {
|
||||
var m = lastMove.move.move;
|
||||
Debug.drawSphere(@:privateAccess marbleToUpdate.newPos, marbleToUpdate._radius);
|
||||
@:privateAccess marbleToUpdate.moveMotionDir = lastMove.move.motionDir;
|
||||
for (o in 0...(tickDiff + 1)) {
|
||||
@:privateAccess marbleToUpdate.advancePhysics(advanceTimeState, m, this.collisionWorld, this.pathedInteriors);
|
||||
}
|
||||
}
|
||||
}
|
||||
@:privateAccess marbleToUpdate.isNetUpdate = false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Tick the remaining moves (ours)
|
||||
if (!ourLastMove.applied) {
|
||||
@:privateAccess this.marble.isNetUpdate = true;
|
||||
var totalTicksToDo = ourQueuedMoves.length;
|
||||
var endTick = ourLastMoveTime + totalTicksToDo;
|
||||
for (move in ourQueuedMoves) {
|
||||
var m = move.move;
|
||||
Debug.drawSphere(@:privateAccess this.marble.newPos, this.marble._radius);
|
||||
@:privateAccess this.marble.moveMotionDir = move.motionDir;
|
||||
@:privateAccess this.marble.advancePhysics(advanceTimeState, m, this.collisionWorld, this.pathedInteriors);
|
||||
|
||||
// for (client => lastMove in lastMoves) {
|
||||
// if (lastMove.clientId == Net.clientId || lastMove.calculationTicks >= endTick)
|
||||
// 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]];
|
||||
@: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;
|
||||
tickDiff--;
|
||||
}
|
||||
}
|
||||
|
||||
// if (ourQueuedMoves.length >= 2) {
|
||||
// trace('Move queue tick diff: ${ourQueuedMoves[ourQueuedMoves.length - 1].timeState.ticks - ourQueuedMoves[0].timeState.ticks}');
|
||||
// }
|
||||
ourLastMove.applied = true;
|
||||
@: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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -477,4 +477,51 @@ class Collision {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function capsuleSphereNearestOverlap(a0:Vector, a1:Vector, radA:Float, b:Vector, radB:Float) {
|
||||
var V = a1.sub(a0);
|
||||
var A0B = a0.sub(b);
|
||||
var d1 = A0B.dot(V);
|
||||
var d2 = A0B.dot(A0B);
|
||||
var d3 = V.dot(V);
|
||||
var R2 = (radA + radB) * (radA + radB);
|
||||
if (d2 < R2) {
|
||||
// starting in collision state
|
||||
return {
|
||||
result: true,
|
||||
t: 0.0
|
||||
}
|
||||
}
|
||||
if (d3 < 0.01) // no movement, and don't start in collision state, so no collision
|
||||
return {
|
||||
result: false,
|
||||
t: 0.0
|
||||
}
|
||||
|
||||
var b24ac = Math.sqrt(d1 * d1 - d2 * d3 + d3 * R2);
|
||||
var t1 = (-d1 - b24ac) / d3;
|
||||
if (t1 > 0 && t1 < 1.0) {
|
||||
return {
|
||||
result: true,
|
||||
t: t1
|
||||
}
|
||||
}
|
||||
var t2 = (-d1 + b24ac) / d3;
|
||||
if (t2 > 0 && t2 < 1.0) {
|
||||
return {
|
||||
result: true,
|
||||
t: t2
|
||||
}
|
||||
}
|
||||
if (t1 < 0 && t2 > 0) {
|
||||
return {
|
||||
result: true,
|
||||
t: 0.0
|
||||
}
|
||||
}
|
||||
return {
|
||||
result: false,
|
||||
t: 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class CollisionWorld {
|
|||
public var dynamicEntities:Array<CollisionEntity> = [];
|
||||
public var dynamicOctree:Octree;
|
||||
|
||||
var marbleEntities:Array<SphereCollisionEntity> = [];
|
||||
public var marbleEntities:Array<SphereCollisionEntity> = [];
|
||||
|
||||
var dynamicEntitySet:Map<CollisionEntity, Bool> = [];
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class MoveManager {
|
|||
var lastMove:NetMove;
|
||||
var lastAckMoveId:Int = -1;
|
||||
|
||||
static var maxMoves = 16;
|
||||
static var maxMoves = 32;
|
||||
|
||||
public function new(connection:ClientConnection) {
|
||||
queuedMoves = [];
|
||||
|
|
@ -155,16 +155,20 @@ class MoveManager {
|
|||
|
||||
public function acknowledgeMove(m:Int) {
|
||||
if (m == 65535 || m == -1)
|
||||
return;
|
||||
return -1;
|
||||
if (m <= lastAckMoveId)
|
||||
return; // Already acked
|
||||
return -1; // Already acked
|
||||
if (queuedMoves.length == 0)
|
||||
return;
|
||||
return -1;
|
||||
while (m != queuedMoves[0].id) {
|
||||
queuedMoves.shift();
|
||||
}
|
||||
if (m == queuedMoves[0].id)
|
||||
var delta = -1;
|
||||
if (m == queuedMoves[0].id) {
|
||||
delta = queuedMoves[0].id - lastAckMoveId;
|
||||
queuedMoves.shift();
|
||||
}
|
||||
lastAckMoveId = m;
|
||||
return delta;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class MarbleUpdatePacket implements NetPacket {
|
|||
var clientId:Int;
|
||||
var move:NetMove;
|
||||
var serverTicks:Int;
|
||||
var calculationTicks:Int;
|
||||
var position:Vector;
|
||||
var velocity:Vector;
|
||||
var omega:Vector;
|
||||
|
|
@ -60,6 +61,7 @@ class MarbleUpdatePacket implements NetPacket {
|
|||
clientId = b.readUInt16();
|
||||
move = MoveManager.unpackMove(b);
|
||||
serverTicks = b.readUInt16();
|
||||
calculationTicks = serverTicks;
|
||||
position = 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());
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue