network helicopter and mega marble properly

This commit is contained in:
RandomityGuy 2024-02-25 01:33:56 +05:30
parent 6c1ed2e43b
commit 3b16113d02
8 changed files with 211 additions and 94 deletions

View file

@ -255,14 +255,15 @@ class Marble extends GameObject {
var megaMarbleEnableTime:Float = -1e8;
var blastUseTime:Float = -1e8;
public var helicopterUseTick:Int = 0;
public var megaMarbleUseTick:Int = 0;
public var blastAmount:Float = 0;
public var blastTicks:Int = 0;
public var blastUseTick:Int = 0; // blast is 12 ticks long
var blastPerc:Float = 0.0;
var teleportEnableTime:Null<Float> = null;
var teleportDisableTime:Null<Float> = null;
var bounceEmitDelay:Float = 0;
var bounceEmitterData:ParticleData;
@ -286,8 +287,6 @@ class Marble extends GameObject {
public var prevPos:Vector;
var cloak:Bool = false;
var teleporting:Bool = false;
var isUltra:Bool = false;
var _firstTick = true;
@ -564,7 +563,7 @@ class Marble extends GameObject {
var gWorkGravityDir = this.currentUp.multiply(-1);
var A = new Vector();
A = gWorkGravityDir.multiply(this._gravity);
if (currentTime - this.helicopterEnableTime < 5) {
if (currentTime - this.helicopterEnableTime < 5 || (helicopterUseTick > 0 && (tick - helicopterUseTick) <= 156)) {
A = A.multiply(0.25);
}
if (this.level != null) {
@ -620,7 +619,7 @@ class Marble extends GameObject {
var motionDir = axes[1];
var upDir = axes[2];
var airAccel = this._airAccel;
if (currentTime - this.helicopterEnableTime < 5) {
if (currentTime - this.helicopterEnableTime < 5 || (helicopterUseTick > 0 && (tick - helicopterUseTick) <= 156)) {
airAccel *= 2;
}
A.load(A.add(sideDir.multiply(m.d.x).add(motionDir.multiply(m.d.y)).multiply(airAccel)));
@ -954,17 +953,18 @@ class Marble extends GameObject {
if (minVelocityBounceSoft <= contactVel) {
var hardBounceSpeed = minVelocityBounceHard;
var bounceSoundNum = Math.floor(Math.random() * 4);
var sndList = (time - this.megaMarbleEnableTime < 10) ? [
"data/sound/mega_bouncehard1.wav",
"data/sound/mega_bouncehard2.wav",
"data/sound/mega_bouncehard3.wav",
"data/sound/mega_bouncehard4.wav"
] : [
"data/sound/bouncehard1.wav",
"data/sound/bouncehard2.wav",
"data/sound/bouncehard3.wav",
"data/sound/bouncehard4.wav"
];
var sndList = ((time - this.megaMarbleEnableTime < 10)
|| (this.megaMarbleUseTick > 0 && (this.level.timeState.ticks - this.megaMarbleUseTick) < 312)) ? [
"data/sound/mega_bouncehard1.wav",
"data/sound/mega_bouncehard2.wav",
"data/sound/mega_bouncehard3.wav",
"data/sound/mega_bouncehard4.wav"
] : [
"data/sound/bouncehard1.wav",
"data/sound/bouncehard2.wav",
"data/sound/bouncehard3.wav",
"data/sound/bouncehard4.wav"
];
var snd = ResourceLoader.getResource(sndList[bounceSoundNum], ResourceLoader.getAudio, this.soundResources);
var gain = bounceMinGain;
@ -1016,7 +1016,8 @@ class Marble extends GameObject {
if (slipVolume < 0)
slipVolume = 0;
if (time.currentAttemptTime - this.megaMarbleEnableTime < 10) {
if (time.currentAttemptTime - this.megaMarbleEnableTime < 10
|| (this.megaMarbleUseTick > 0 && (this.level.timeState.ticks - this.megaMarbleUseTick) < 312)) {
if (this.rollMegaSound != null) {
rollMegaSound.volume = rollVolume;
rollSound.volume = 0;
@ -1661,6 +1662,8 @@ class Marble extends GameObject {
marbleUpdate.moveQueueSize = this.connection != null ? this.connection.moveManager.getQueueSize() : 255;
marbleUpdate.blastAmount = this.blastTicks;
marbleUpdate.blastTick = this.blastUseTick;
marbleUpdate.heliTick = this.helicopterUseTick;
marbleUpdate.megaTick = this.megaMarbleUseTick;
marbleUpdate.serialize(b);
return b.getBytes();
}
@ -1681,6 +1684,8 @@ class Marble extends GameObject {
this.omega = p.omega;
this.blastTicks = p.blastAmount;
this.blastUseTick = p.blastTick;
this.helicopterUseTick = p.heliTick;
this.megaMarbleUseTick = p.megaTick;
if (this.controllable && Net.isClient) {
// We are client, need to do something about the queue
var mm = Net.clientConnection.moveManager;
@ -1737,6 +1742,19 @@ class Marble extends GameObject {
playedSounds = [];
advancePhysics(timeState, move.move, collisionWorld, pathedInteriors);
physicsAccumulator = 0;
if (this.megaMarbleUseTick > 0) {
if ((this.level.timeState.ticks - this.megaMarbleUseTick) < 312) {
this._radius = 0.675;
this.collider.radius = 0.675;
} else if ((this.level.timeState.ticks - this.megaMarbleUseTick) > 312) {
this.collider.radius = this._radius = 0.3;
if (!this.isNetUpdate && this.controllable)
AudioManager.playSound(ResourceLoader.getResource("data/sound/MegaShrink.wav", ResourceLoader.getAudio, this.soundResources), null, false);
this.megaMarbleUseTick = 0;
}
}
return move;
// if (Net.isHost) {
// packets.push({b: packUpdate(move, timeState), c: this.connection != null ? this.connection.id : 0});
@ -1771,6 +1789,12 @@ class Marble extends GameObject {
updatePowerupStates(timeState.currentAttemptTime, timeState.dt);
if ((this.megaMarbleUseTick > 0 && (this.level.timeState.ticks - this.megaMarbleUseTick) < 312)) {
this._marbleScale = this._defaultScale * 2.25;
} else {
this._marbleScale = this._defaultScale;
}
var s = this._renderScale * this._renderScale;
if (s <= this._marbleScale * this._marbleScale)
s = 0.1;
@ -1778,29 +1802,13 @@ class Marble extends GameObject {
s = 0.4;
s = timeState.dt / s * 2.302585124969482;
s = 1.0 / (s * (s * 0.2349999994039536 * s) + s + 1.0 + 0.4799999892711639 * s * s);
s = 1.0 / (s * (s * 0.235 * s) + s + 1.0 + 0.48 * s * s);
this._renderScale *= s;
s = 1 - s;
this._renderScale += s * this._marbleScale;
var marbledts = cast(this.getChildAt(0), DtsObject);
marbledts.setScale(this._renderScale);
if (this._radius != 0.675 && timeState.currentAttemptTime - this.megaMarbleEnableTime < 10) {
this._prevRadius = this._radius;
this._radius = 0.675;
this.collider.radius = 0.675;
this._marbleScale *= 2.25;
var boost = this.currentUp.multiply(5);
this.velocity = this.velocity.add(boost);
} else if (timeState.currentAttemptTime - this.megaMarbleEnableTime > 10) {
if (this._radius != this._prevRadius) {
this._radius = this._prevRadius;
this.collider.radius = this._radius;
this._marbleScale = this._defaultScale;
AudioManager.playSound(ResourceLoader.getResource("data/sound/MegaShrink.wav", ResourceLoader.getAudio, this.soundResources), null, false);
}
}
this.updateFinishAnimation(timeState.dt);
if (this.mode == Finish) {
this.setPosition(this.finishAnimPosition.x, this.finishAnimPosition.y, this.finishAnimPosition.z);
@ -1968,8 +1976,6 @@ class Marble extends GameObject {
}
}
this.updateTeleporterState(timeState);
this.updateFinishAnimation(timeState.dt);
if (this.mode == Finish) {
this.setPosition(this.finishAnimPosition.x, this.finishAnimPosition.y, this.finishAnimPosition.z);
@ -2063,7 +2069,8 @@ class Marble extends GameObject {
public function updatePowerupStates(currentTime:Float, dt:Float) {
if (!this.controllable && this.connection == null)
return;
if (currentTime - this.helicopterEnableTime < 5) {
if (currentTime - this.helicopterEnableTime < 5
|| (helicopterUseTick > 0 && (this.level.timeState.ticks - helicopterUseTick) <= 156)) {
this.helicopter.setPosition(x, y, z);
this.helicopter.setRotationQuat(this.level.getOrientationQuat(currentTime));
this.helicopterSound.pause = false;
@ -2089,7 +2096,8 @@ class Marble extends GameObject {
public function getMass() {
if (this.level == null)
return 1;
if (this.level.timeState.currentAttemptTime - this.megaMarbleEnableTime < 10) {
if (this.level.timeState.currentAttemptTime - this.megaMarbleEnableTime < 10
|| (this.megaMarbleUseTick > 0 && (this.level.timeState.ticks - this.megaMarbleUseTick) < 312)) {
return 5;
} else {
return 1;
@ -2156,46 +2164,18 @@ class Marble extends GameObject {
this.appliedImpulses.push({impulse: impulse, contactImpulse: contactImpulse});
}
public function enableHelicopter(time:Float) {
this.helicopterEnableTime = time;
public function enableHelicopter(timeState:TimeState) {
if (this.level.isMultiplayer)
this.helicopterUseTick = timeState.ticks;
else
this.helicopterEnableTime = timeState.currentAttemptTime;
}
public function enableMegaMarble(time:Float) {
this.megaMarbleEnableTime = time;
}
function updateTeleporterState(time:TimeState) {
var teleportFadeCompletion:Float = 0;
if (this.teleportEnableTime != null)
teleportFadeCompletion = Util.clamp((time.currentAttemptTime - this.teleportEnableTime) / 0.5, 0, 1);
if (this.teleportDisableTime != null)
teleportFadeCompletion = Util.clamp(1 - (time.currentAttemptTime - this.teleportDisableTime) / 0.5, 0, 1);
if (teleportFadeCompletion > 0) {
var ourDts:DtsObject = cast this.children[0];
ourDts.setOpacity(Util.lerp(1, 0.25, teleportFadeCompletion));
this.teleporting = true;
} else {
if (this.teleporting) {
var ourDts:DtsObject = cast this.children[0];
ourDts.setOpacity(1);
this.teleporting = false;
}
}
}
public function setCloaking(active:Bool, time:TimeState) {
this.cloak = active;
if (this.cloak) {
var completion = (this.teleportDisableTime != null) ? Util.clamp((time.currentAttemptTime - this.teleportDisableTime) / 0.5, 0, 1) : 1;
this.teleportEnableTime = time.currentAttemptTime - 0.5 * (1 - completion);
this.teleportDisableTime = null;
} else {
var completion = Util.clamp((time.currentAttemptTime - this.teleportEnableTime) / 0.5, 0, 1);
this.teleportDisableTime = time.currentAttemptTime - 0.5 * (1 - completion);
this.teleportEnableTime = null;
}
public function enableMegaMarble(timeState:TimeState) {
if (this.level.isMultiplayer)
this.megaMarbleUseTick = timeState.ticks;
else
this.megaMarbleEnableTime = timeState.currentAttemptTime;
}
public function setMode(mode:Mode) {
@ -2221,17 +2201,11 @@ class Marble extends GameObject {
this.blastUseTime = Math.NEGATIVE_INFINITY;
this.blastUseTick = 0;
this.blastTicks = 0;
this.helicopterUseTick = 0;
this.megaMarbleUseTick = 0;
this.lastContactNormal = new Vector(0, 0, 1);
this.contactEntities = [];
this.cloak = false;
this._firstTick = true;
if (this.teleporting) {
var ourDts:DtsObject = cast this.children[0];
ourDts.setOpacity(1);
}
this.teleporting = false;
this.teleportDisableTime = null;
this.teleportEnableTime = null;
this.finishAnimTime = 0;
this.physicsAccumulator = 0;
this.prevRot = this.getRotationQuat().clone();

View file

@ -1166,10 +1166,12 @@ class MarbleWorld extends Scheduler {
// if (m.serverTicks == ourLastMoveTime) {
var marbleToUpdate = clientMarbles[Net.clientIdMap[client]];
Debug.drawSphere(@:privateAccess marbleToUpdate.newPos, marbleToUpdate._radius);
if (marbleNeedsPrediction & (1 << Net.clientId) > 0)
var distFromUs = @:privateAccess marbleToUpdate.newPos.distance(this.marble.newPos);
if (distFromUs < 5)
m.calculationTicks = ourQueuedMoves.length; // ourQueuedMoves.length;
else
m.calculationTicks = ourQueuedMoves.length;
m.calculationTicks = Std.int(Math.max(1, ourQueuedMoves.length - (distFromUs - 5) / 5));
// - Std.int((@:privateAccess Net.clientConnection.moveManager.ackRTT - ourLastMove.moveQueueSize) / 2);
marblesToTick.set(client, m);

132
src/net/BitStream.hx Normal file
View file

@ -0,0 +1,132 @@
package net;
import haxe.io.BytesOutput;
import haxe.io.BytesInput;
import haxe.io.Bytes;
class InputBitStream {
var data:Bytes;
var position:Int;
var shift:Int;
public function new(data:Bytes) {
this.data = data;
this.position = 0;
this.shift = 0;
}
function readBits(bits:Int = 8) {
if (this.shift + bits >= 8) {
var extra = (this.shift + bits) % 8;
var remain = bits - extra;
var first = data.get(position) >> shift;
var result = first;
this.position++;
if (extra > 0) {
var second = (data.get(position) & (0xFF >> (8 - extra))) << remain;
result |= second;
}
this.shift = extra;
return result;
} else {
var result = (data.get(position) >> shift) & (0xFF >> (8 - bits));
shift += bits;
return result;
}
}
public function readInt(bits:Int = 32) {
var value = 0;
var shift = 0;
while (bits > 0) {
value |= readBits(bits < 8 ? bits : 8) << shift;
shift += 8;
bits -= 8;
}
return value;
}
public function readFlag() {
return readInt(1);
}
public function readByte() {
return readInt(8);
}
public function readUInt16() {
return readInt(16);
}
public function readInt32() {
return readInt(32);
}
public function readFloat() {
return readInt32();
}
}
class OutputBitStream {
var data:BytesOutput;
var position:Int;
var shift:Int;
var lastByte:Int;
public function new(data:BytesOutput = null) {
this.data = data;
if (this.data == null)
this.data = new BytesOutput();
this.position = 0;
this.shift = 0;
this.lastByte = 0;
}
function writeBits(value:Int, bits:Int) {
value = value & (0xFF >> (8 - bits));
if (this.shift + bits >= 8) {
var extra = (shift + bits) % 8;
var remain = bits - extra;
var first = value & (0xFF >> (8 - remain));
lastByte |= first << shift;
var second = (value >> remain) & (0xFF >> (8 - extra));
this.data.writeByte(this.lastByte);
this.lastByte = second;
this.shift = extra;
} else {
lastByte |= (value << this.shift) & (0xFF >> (8 - bits - this.shift));
}
}
public function writeInt(value:Int, bits:Int = 32) {
while (bits > 0) {
this.writeBits(value & 0xFF, bits < 8 ? bits : 8);
value >>= 8;
bits -= 8;
}
}
public function writeFlag(value:Int) {
writeInt(value, 1);
}
public function writeByte(value:Int) {
writeInt(value, 8);
}
public function writeUInt16(value:Int) {
writeInt(value, 16);
}
public function writeInt32(value:Int) {
writeInt(value, 32);
}
public function getBytes() {
this.data.writeByte(this.lastByte);
return this.data.getBytes();
}
}

View file

@ -25,9 +25,10 @@ class MarblePrediction {
}
public inline function getError(p:MarbleUpdatePacket) {
var subs = position.sub(p.position).lengthSq() + velocity.sub(p.velocity).lengthSq() + omega.sub(p.omega).lengthSq();
if (isControl)
subs += Math.abs(blastAmount - p.blastAmount);
// Just doing position errors is enough to make it work
var subs = position.sub(p.position).lengthSq(); // + velocity.sub(p.velocity).lengthSq() + omega.sub(p.omega).lengthSq();
// if (isControl)
// subs += Math.abs(blastAmount - p.blastAmount);
return subs;
}
}

View file

@ -50,7 +50,7 @@ class Net {
isHost = true;
isClient = false;
clientId = 0;
masterWs = new WebSocket("ws://192.168.1.2:8080");
masterWs = new WebSocket("ws://localhost:8080");
masterWs.onmessage = (m) -> {
switch (m) {
@ -97,7 +97,7 @@ class Net {
}
public static function joinServer(connectedCb:() -> Void) {
masterWs = new WebSocket("ws://192.168.1.2:8080");
masterWs = new WebSocket("ws://localhost:8080");
masterWs.onopen = () -> {
client = new RTCPeerConnection(["stun:stun.l.google.com:19302"], "0.0.0.0");
var candidates = [];

View file

@ -40,6 +40,8 @@ class MarbleUpdatePacket implements NetPacket {
var omega:Vector;
var blastAmount:Int;
var blastTick:Int;
var megaTick:Int;
var heliTick:Int;
var moveQueueSize:Int;
public function new() {}
@ -60,6 +62,8 @@ class MarbleUpdatePacket implements NetPacket {
b.writeFloat(omega.z);
b.writeUInt16(blastAmount);
b.writeUInt16(blastTick);
b.writeUInt16(heliTick);
b.writeUInt16(megaTick);
}
public inline function deserialize(b:haxe.io.BytesInput) {
@ -72,5 +76,7 @@ class MarbleUpdatePacket implements NetPacket {
omega = new Vector(b.readFloat(), b.readFloat(), b.readFloat());
blastAmount = b.readUInt16();
blastTick = b.readUInt16();
heliTick = b.readUInt16();
megaTick = b.readUInt16();
}
}

View file

@ -34,7 +34,7 @@ class Helicopter extends PowerUp {
}
public function use(marble:Marble, timeState:TimeState) {
marble.enableHelicopter(timeState.currentAttemptTime);
marble.enableHelicopter(timeState);
this.level.deselectPowerUp(marble);
}

View file

@ -41,7 +41,9 @@ class MegaMarble extends PowerUp {
}
public function use(marble:Marble, timeState:TimeState) {
marble.enableMegaMarble(timeState.currentAttemptTime);
marble.enableMegaMarble(timeState);
var boost = marble.currentUp.multiply(5);
marble.velocity.load(marble.velocity.add(boost));
this.level.deselectPowerUp(marble);
if (this.level.marble == marble && @:privateAccess !marble.isNetUpdate)
AudioManager.playSound(ResourceLoader.getResource('data/sound/use_mega.wav', ResourceLoader.getAudio, this.soundResources));