more net ui and netcode

This commit is contained in:
RandomityGuy 2024-04-09 23:35:20 +05:30
parent cabc437ca0
commit 038e0ed16e
12 changed files with 144 additions and 58 deletions

View file

@ -258,6 +258,8 @@ class Marble extends GameObject {
var oldPos:Vector; var oldPos:Vector;
var newPos:Vector; var newPos:Vector;
var prevRot:Quat; var prevRot:Quat;
var posStore:Vector;
var netCorrected:Bool;
public var contacts:Array<CollisionInfo> = []; public var contacts:Array<CollisionInfo> = [];
public var bestContact:CollisionInfo; public var bestContact:CollisionInfo;
@ -324,6 +326,7 @@ class Marble extends GameObject {
var isNetUpdate:Bool = false; var isNetUpdate:Bool = false;
var netFlags:Int = 0; var netFlags:Int = 0;
var serverTicks:Int; var serverTicks:Int;
var recvServerTick:Int;
public function new() { public function new() {
super(); super();
@ -368,6 +371,9 @@ class Marble extends GameObject {
var isUltra = true; var isUltra = true;
this.posStore = new Vector();
this.netCorrected = false;
var marbleDts = new DtsObject(); var marbleDts = new DtsObject();
Console.log("Marble: " + Settings.optionsSettings.marbleModel + " (" + Settings.optionsSettings.marbleSkin + ")"); Console.log("Marble: " + Settings.optionsSettings.marbleModel + " (" + Settings.optionsSettings.marbleSkin + ")");
marbleDts.dtsPath = Settings.optionsSettings.marbleModel; marbleDts.dtsPath = Settings.optionsSettings.marbleModel;
@ -1748,8 +1754,9 @@ class Marble extends GameObject {
// } // }
// } // }
this.serverTicks = p.serverTicks; this.serverTicks = p.serverTicks;
this.oldPos = this.newPos; this.recvServerTick = p.serverTicks;
this.newPos = p.position; // this.oldPos = this.newPos;
// this.newPos = p.position;
this.collider.transform.setPosition(p.position); this.collider.transform.setPosition(p.position);
this.velocity = p.velocity; this.velocity = p.velocity;
this.omega = p.omega; this.omega = p.omega;
@ -1767,29 +1774,36 @@ class Marble extends GameObject {
this.level.pickUpPowerUp(cast this, this.level.powerUps[p.powerUpId]); this.level.pickUpPowerUp(cast this, this.level.powerUps[p.powerUpId]);
} }
if (this.controllable && Net.isClient) { // if (this.controllable && Net.isClient) {
// We are client, need to do something about the queue // // We are client, need to do something about the queue
var mm = Net.clientConnection.moveManager; // var mm = Net.clientConnection.moveManager;
// trace('Queue size: ${mm.getQueueSize()}, server: ${p.moveQueueSize}'); // // trace('Queue size: ${mm.getQueueSize()}, server: ${p.moveQueueSize}');
if (mm.getQueueSize() / p.moveQueueSize < 2) { // if (mm.getQueueSize() / p.moveQueueSize < 2) {
mm.stall = true; // mm.stall = true;
} else { // } else {
mm.stall = false; // mm.stall = false;
} // }
} // }
return true; return true;
} }
function calculateNetSmooth() {
if (this.netCorrected) {
this.netCorrected = false;
this.oldPos.load(this.posStore);
}
}
public function updateServer(timeState:TimeState, collisionWorld:CollisionWorld, pathedInteriors:Array<PathedInterior>) { public function updateServer(timeState:TimeState, collisionWorld:CollisionWorld, pathedInteriors:Array<PathedInterior>) {
var move:NetMove = null; var move:NetMove = null;
if (this.controllable && this.mode != Finish && !MarbleGame.instance.paused && !this.level.isWatching && !this.level.isReplayingMovement) { if (this.controllable && this.mode != Finish && !MarbleGame.instance.paused && !this.level.isWatching && !this.level.isReplayingMovement) {
if (Net.isClient) { if (Net.isClient) {
var axis = getMarbleAxis()[1]; var axis = getMarbleAxis()[1];
move = Net.clientConnection.recordMove(cast this, axis, timeState); move = Net.clientConnection.recordMove(cast this, axis, timeState, recvServerTick);
} else if (Net.isHost) { } else if (Net.isHost) {
var axis = getMarbleAxis()[1]; var axis = getMarbleAxis()[1];
var innerMove = recordMove(); var innerMove = recordMove();
move = new NetMove(innerMove, axis, timeState, 65535); move = new NetMove(innerMove, axis, timeState, recvServerTick, 65535);
} }
} }
var moveId = 65535; var moveId = 65535;
@ -1800,30 +1814,35 @@ class Marble extends GameObject {
var axis = getMarbleAxis()[1]; var axis = getMarbleAxis()[1];
var innerMove = new Move(); var innerMove = new Move();
innerMove.d = new Vector(0, 0); innerMove.d = new Vector(0, 0);
move = new NetMove(innerMove, axis, timeState, 65535); move = new NetMove(innerMove, axis, timeState, recvServerTick, 65535);
} else { } else {
move = nextMove; move = nextMove;
moveMotionDir = nextMove.motionDir; moveMotionDir = nextMove.motionDir;
moveId = nextMove.id; moveId = nextMove.id;
} }
} }
if (move == null) { if (move == null && !this.controllable) {
var axis = moveMotionDir != null ? moveMotionDir : new Vector(0, -1, 0); var axis = moveMotionDir != null ? moveMotionDir : new Vector(0, -1, 0);
var innerMove = lastMove; var innerMove = lastMove;
if (innerMove == null) { if (innerMove == null) {
innerMove = new Move(); innerMove = new Move();
innerMove.d = new Vector(0, 0); innerMove.d = new Vector(0, 0);
} }
move = new NetMove(innerMove, axis, timeState, 65535); move = new NetMove(innerMove, axis, timeState, recvServerTick, 65535);
} }
playedSounds = []; if (move != null) {
advancePhysics(timeState, move.move, collisionWorld, pathedInteriors); playedSounds = [];
physicsAccumulator = 0; advancePhysics(timeState, move.move, collisionWorld, pathedInteriors);
physicsAccumulator = 0;
if (move.move.jump && this.outOfBounds) { if (move.move.jump && this.outOfBounds) {
this.level.cancel(this.oobSchedule); this.level.cancel(this.oobSchedule);
this.level.restart(cast this); this.level.restart(cast this);
}
} else {
physicsAccumulator = 0;
newPos.load(oldPos);
} }
return move; return move;
@ -1833,6 +1852,7 @@ class Marble extends GameObject {
} }
public function updateClient(timeState:TimeState, pathedInteriors:Array<PathedInterior>) { public function updateClient(timeState:TimeState, pathedInteriors:Array<PathedInterior>) {
calculateNetSmooth();
this.level.updateBlast(cast this, timeState); this.level.updateBlast(cast this, timeState);
if (oldPos != null && newPos != null) { if (oldPos != null && newPos != null) {
var deltaT = physicsAccumulator / 0.032; var deltaT = physicsAccumulator / 0.032;
@ -2318,6 +2338,8 @@ class Marble extends GameObject {
this.prevRot = this.getRotationQuat().clone(); this.prevRot = this.getRotationQuat().clone();
this.oldPos = this.getAbsPos().getPosition(); this.oldPos = this.getAbsPos().getPosition();
this.newPos = this.getAbsPos().getPosition(); this.newPos = this.getAbsPos().getPosition();
this.posStore = new Vector();
this.netCorrected = false;
if (this._radius != this._prevRadius) { if (this._radius != this._prevRadius) {
this._radius = this._prevRadius; this._radius = this._prevRadius;
this._marbleScale = this._renderScale = this._defaultScale; this._marbleScale = this._renderScale = this._defaultScale;

View file

@ -1077,7 +1077,7 @@ class MarbleWorld extends Scheduler {
if (!lastMoves.ourMoveApplied) { if (!lastMoves.ourMoveApplied) {
var ourMove = lastMoves.myMarbleUpdate; var ourMove = lastMoves.myMarbleUpdate;
if (ourMove != null) { if (ourMove != null) {
var ourMoveStruct = Net.clientConnection.acknowledgeMove(ourMove.move.id, timeState); var ourMoveStruct = Net.clientConnection.acknowledgeMove(ourMove.move, timeState);
lastMoves.ourMoveApplied = true; lastMoves.ourMoveApplied = true;
for (client => arr in lastMoves.otherMarbleUpdates) { for (client => arr in lastMoves.otherMarbleUpdates) {
var lastMove = null; var lastMove = null;
@ -1203,9 +1203,11 @@ class MarbleWorld extends Scheduler {
var marbleToUpdate = clientMarbles[Net.clientIdMap[client]]; var marbleToUpdate = clientMarbles[Net.clientIdMap[client]];
// Debug.drawSphere(@:privateAccess marbleToUpdate.newPos, marbleToUpdate._radius); // Debug.drawSphere(@:privateAccess marbleToUpdate.newPos, marbleToUpdate._radius);
var distFromUs = @:privateAccess marbleToUpdate.newPos.distance(this.marble.newPos); // var distFromUs = @:privateAccess marbleToUpdate.newPos.distance(this.marble.newPos);
// if (distFromUs < 5) // { // if (distFromUs < 5) // {
m.calculationTicks = ourQueuedMoves.length; m.calculationTicks = ourQueuedMoves.length;
@:privateAccess marbleToUpdate.posStore.load(marbleToUpdate.newPos);
@:privateAccess marbleToUpdate.netCorrected = true;
// } else { // } else {
// m.calculationTicks = Std.int(Math.max(1, ourQueuedMoves.length - (distFromUs - 5) / 3)); // m.calculationTicks = Std.int(Math.max(1, ourQueuedMoves.length - (distFromUs - 5) / 3));
// } // }
@ -1220,6 +1222,9 @@ class MarbleWorld extends Scheduler {
Debug.drawSphere(@:privateAccess this.marble.newPos, this.marble._radius); Debug.drawSphere(@:privateAccess this.marble.newPos, this.marble._radius);
// var syncTickStates = new Map(); // var syncTickStates = new Map();
@:privateAccess this.marble.posStore.load(this.marble.newPos);
@:privateAccess this.marble.netCorrected = true;
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);
@ -1479,9 +1484,11 @@ class MarbleWorld extends Scheduler {
for (client => marble in clientMarbles) { for (client => marble in clientMarbles) {
otherMoves.push(marble.updateServer(fixedDt, collisionWorld, pathedInteriors)); otherMoves.push(marble.updateServer(fixedDt, collisionWorld, pathedInteriors));
} }
this.predictions.storeState(marble, myMove.timeState.ticks); if (myMove != null) {
for (client => marble in clientMarbles) {
this.predictions.storeState(marble, myMove.timeState.ticks); this.predictions.storeState(marble, myMove.timeState.ticks);
for (client => marble in clientMarbles) {
this.predictions.storeState(marble, myMove.timeState.ticks);
}
} }
if (Net.isHost) { if (Net.isHost) {
for (client => othermarble in clientMarbles) { // Oh no! for (client => othermarble in clientMarbles) { // Oh no!

View file

@ -114,8 +114,9 @@ class CreateMatchGui extends GuiImage {
nextButton.gamepadAccelerator = ["A"]; nextButton.gamepadAccelerator = ["A"];
nextButton.accelerators = [hxd.Key.ENTER]; nextButton.accelerators = [hxd.Key.ENTER];
nextButton.pressedAction = (e) -> { nextButton.pressedAction = (e) -> {
Net.hostServer('${Settings.highscoreName}\'s Server', maxPlayers, privateSlots, privateGame); Net.hostServer('${Settings.highscoreName}\'s Server', maxPlayers, privateSlots, privateGame, () -> {
MarbleGame.canvas.setContent(new MultiplayerLevelSelectGui(true)); MarbleGame.canvas.setContent(new MultiplayerLevelSelectGui(true));
});
}; };
bottomBar.addChild(nextButton); bottomBar.addChild(nextButton);
} }

View file

@ -55,7 +55,7 @@ class EnterNameDlg extends GuiImage {
textInput.text.selectionTile = h2d.Tile.fromColor(0x88BCEE, 0, hxd.Math.ceil(textInput.text.font.lineHeight)); textInput.text.selectionTile = h2d.Tile.fromColor(0x88BCEE, 0, hxd.Math.ceil(textInput.text.font.lineHeight));
textFrame.addChild(textInput); textFrame.addChild(textInput);
textInput.text.text = Settings.highscoreName; textInput.text.text = Settings.highscoreName == "" ? "Player Name" : Settings.highscoreName;
var okButton = new GuiXboxButton("Ok", 120); var okButton = new GuiXboxButton("Ok", 120);
okButton.position = new Vector(211, 248); okButton.position = new Vector(211, 248);

View file

@ -1,5 +1,6 @@
package gui; package gui;
import net.Net;
import gui.GuiControl.MouseState; import gui.GuiControl.MouseState;
import src.AudioManager; import src.AudioManager;
import src.MarbleGame; import src.MarbleGame;
@ -82,7 +83,8 @@ class ExitGameDlg extends GuiImage {
innerCtrl.addChild(btnList); innerCtrl.addChild(btnList);
btnList.addButton(0, "Resume", (evt) -> noFunc(btnList)); btnList.addButton(0, "Resume", (evt) -> noFunc(btnList));
btnList.addButton(0, "Restart", (evt) -> restartFunc(btnList)); if (!Net.isMP)
btnList.addButton(0, "Restart", (evt) -> restartFunc(btnList));
btnList.addButton(4, "Exit Level", (evt) -> { btnList.addButton(4, "Exit Level", (evt) -> {
MarbleGame.canvas.pushDialog(new MessageBoxYesNoDlg("Are you sure you want to exit this level? You will lose your current level progress.", MarbleGame.canvas.pushDialog(new MessageBoxYesNoDlg("Are you sure you want to exit this level? You will lose your current level progress.",
() -> yesFunc(btnList), () -> {})); () -> yesFunc(btnList), () -> {}));

View file

@ -18,7 +18,7 @@ class MultiplayerLevelSelectGui extends GuiImage {
static var currentSelectionStatic:Int = 0; static var currentSelectionStatic:Int = 0;
static var setLevelFn:Int->Void; static var setLevelFn:Int->Void;
static var playSelectedLevel:Void->Void; static var playSelectedLevel:Int->Void;
var playerList:GuiMLTextListCtrl; var playerList:GuiMLTextListCtrl;
var updatePlayerCountFn:(Int, Int, Int, Int) -> Void; var updatePlayerCountFn:(Int, Int, Int, Int) -> Void;
@ -200,7 +200,8 @@ class MultiplayerLevelSelectGui extends GuiImage {
}; };
bottomBar.addChild(nextButton); bottomBar.addChild(nextButton);
playSelectedLevel = () -> { playSelectedLevel = (index:Int) -> {
curMission = difficultyMissions[index];
MarbleGame.instance.playMission(curMission, true); MarbleGame.instance.playMission(curMission, true);
} }

View file

@ -69,7 +69,7 @@ abstract class GameConnection {
moveManager.queueMove(m); moveManager.queueMove(m);
} }
public inline function acknowledgeMove(m:Int, timeState:TimeState) { public inline function acknowledgeMove(m:NetMove, timeState:TimeState) {
return moveManager.acknowledgeMove(m, timeState); return moveManager.acknowledgeMove(m, timeState);
} }
@ -81,8 +81,8 @@ abstract class GameConnection {
return moveManager.getQueueSize(); return moveManager.getQueueSize();
} }
public function recordMove(marble:src.Marble, motionDir:h3d.Vector, timeState:TimeState) { public function recordMove(marble:src.Marble, motionDir:h3d.Vector, timeState:TimeState, serverTicks:Int) {
return moveManager.recordMove(marble, motionDir, timeState); return moveManager.recordMove(marble, motionDir, timeState, serverTicks);
} }
public function getNextMove() { public function getNextMove() {

View file

@ -26,10 +26,18 @@ class MasterServerClient {
var open = false; var open = false;
public function new(onOpenFunc:() -> Void) { public function new(onOpenFunc:() -> Void) {
#if sys
var senderThread = sys.thread.Thread.current();
#end
ws = new WebSocket(serverIp); ws = new WebSocket(serverIp);
ws.onopen = () -> { ws.onopen = () -> {
open = true; open = true;
#if sys
senderThread.events.run(onOpenFunc);
#end
#if js
onOpenFunc(); onOpenFunc();
#end
} }
ws.onmessage = (m) -> { ws.onmessage = (m) -> {
switch (m) { switch (m) {
@ -44,8 +52,15 @@ class MasterServerClient {
public static function connectToMasterServer(onConnect:() -> Void) { public static function connectToMasterServer(onConnect:() -> Void) {
if (instance == null) if (instance == null)
instance = new MasterServerClient(onConnect); instance = new MasterServerClient(onConnect);
else else {
onConnect(); if (instance.open)
onConnect();
else {
instance.ws.close();
instance = null;
instance = new MasterServerClient(onConnect);
}
}
} }
public static function disconnectFromMasterServer() { public static function disconnectFromMasterServer() {

View file

@ -25,11 +25,13 @@ class NetMove {
var move:Move; var move:Move;
var id:Int; var id:Int;
var timeState:TimeState; var timeState:TimeState;
var serverTicks:Int;
public function new(move:Move, motionDir:Vector, timeState:TimeState, id:Int) { public function new(move:Move, motionDir:Vector, timeState:TimeState, serverTicks:Int, id:Int) {
this.move = move; this.move = move;
this.motionDir = motionDir; this.motionDir = motionDir;
this.id = id; this.id = id;
this.serverTicks = serverTicks;
this.timeState = timeState; this.timeState = timeState;
} }
} }
@ -44,6 +46,12 @@ class MoveManager {
var maxMoves = 45; var maxMoves = 45;
var serverTargetMoveListSize = 3;
var serverMaxMoveListSize = 5;
var serverAvgMoveListSize = 3.0;
var serverSmoothMoveAvg = 0.15;
var serverMoveListSizeSlack = 1.0;
public var stall = false; public var stall = false;
public function new(connection:GameConnection) { public function new(connection:GameConnection) {
@ -54,9 +62,10 @@ class MoveManager {
mv.d = new Vector(0, 0); mv.d = new Vector(0, 0);
} }
public function recordMove(marble:Marble, motionDir:Vector, timeState:TimeState) { public function recordMove(marble:Marble, motionDir:Vector, timeState:TimeState, serverTicks:Int) {
if (queuedMoves.length >= maxMoves || stall) if (queuedMoves.length >= maxMoves || stall) {
return queuedMoves[queuedMoves.length - 1]; return queuedMoves[queuedMoves.length - 1];
}
var move = new Move(); var move = new Move();
move.d = new Vector(); move.d = new Vector();
move.d.x = Gamepad.getAxis(Settings.gamepadSettings.moveYAxis); move.d.x = Gamepad.getAxis(Settings.gamepadSettings.moveYAxis);
@ -94,7 +103,7 @@ class MoveManager {
move.d.x = MarbleGame.instance.touchInput.movementInput.value.y; move.d.x = MarbleGame.instance.touchInput.movementInput.value.y;
} }
var netMove = new NetMove(move, motionDir, timeState.clone(), nextMoveId++); var netMove = new NetMove(move, motionDir, timeState.clone(), serverTicks, nextMoveId++);
queuedMoves.push(netMove); queuedMoves.push(netMove);
if (nextMoveId >= 65535) // 65535 is reserved for null move if (nextMoveId >= 65535) // 65535 is reserved for null move
@ -113,6 +122,11 @@ class MoveManager {
return netMove; return netMove;
} }
function copyMove(to:Int, from:Int) {
queuedMoves[to].move = queuedMoves[from].move;
queuedMoves[to].motionDir.load(queuedMoves[from].motionDir);
}
public static inline function packMove(m:NetMove, b:OutputBitStream) { public static inline function packMove(m:NetMove, b:OutputBitStream) {
b.writeUInt16(m.id); b.writeUInt16(m.id);
b.writeByte(Std.int((m.move.d.x * 16) + 16)); b.writeByte(Std.int((m.move.d.x * 16) + 16));
@ -139,7 +153,7 @@ class MoveManager {
motionDir.x = b.readFloat(); motionDir.x = b.readFloat();
motionDir.y = b.readFloat(); motionDir.y = b.readFloat();
motionDir.z = b.readFloat(); motionDir.z = b.readFloat();
var netMove = new NetMove(move, motionDir, MarbleGame.instance.world.timeState.clone(), moveId); var netMove = new NetMove(move, motionDir, MarbleGame.instance.world.timeState.clone(), 0, moveId);
return netMove; return netMove;
} }
@ -148,9 +162,31 @@ class MoveManager {
} }
public function getNextMove() { public function getNextMove() {
if (queuedMoves.length == 0) if (Net.isHost) {
serverAvgMoveListSize *= (1 - serverSmoothMoveAvg);
serverAvgMoveListSize += serverSmoothMoveAvg * queuedMoves.length;
if (serverAvgMoveListSize < serverTargetMoveListSize - serverMoveListSizeSlack
&& queuedMoves.length < serverTargetMoveListSize
&& queuedMoves.length != 0) {
// Send null move
return null;
}
if (queuedMoves.length > serverMaxMoveListSize
|| (serverAvgMoveListSize > serverTargetMoveListSize + serverMoveListSizeSlack
&& queuedMoves.length > serverTargetMoveListSize)) {
var dropAmt = queuedMoves.length - serverTargetMoveListSize;
while (dropAmt-- > 0) {
queuedMoves.pop();
}
serverAvgMoveListSize = serverTargetMoveListSize;
}
}
if (queuedMoves.length == 0) {
// if (lastMove != null) {
// lastMove.id++; // So that we force client's move to be overriden by this one
// }
return lastMove; return lastMove;
else { } else {
lastMove = queuedMoves[0]; lastMove = queuedMoves[0];
queuedMoves.shift(); queuedMoves.shift();
return lastMove; return lastMove;
@ -161,25 +197,29 @@ class MoveManager {
return queuedMoves.length; return queuedMoves.length;
} }
public function acknowledgeMove(m:Int, timeState:TimeState) { public function acknowledgeMove(m:NetMove, timeState:TimeState) {
if (m == 65535 || m == -1) if (m.id == 65535 || m.id == -1) {
return null; return null;
if (m <= lastAckMoveId) }
if (m.id <= lastAckMoveId)
return null; // Already acked return null; // Already acked
if (queuedMoves.length == 0) if (queuedMoves.length == 0)
return null; return null;
while (m != queuedMoves[0].id) { if (m.id >= nextMoveId) {
return queuedMoves[0]; // Input lag
}
while (m.id != queuedMoves[0].id) {
queuedMoves.shift(); queuedMoves.shift();
} }
var delta = -1; var delta = -1;
var mv = null; var mv = null;
if (m == queuedMoves[0].id) { if (m.id == queuedMoves[0].id) {
delta = queuedMoves[0].id - lastAckMoveId; delta = queuedMoves[0].id - lastAckMoveId;
mv = queuedMoves.shift(); mv = queuedMoves.shift();
ackRTT = timeState.ticks - mv.timeState.ticks; ackRTT = timeState.ticks - mv.timeState.ticks;
maxMoves = ackRTT + 2; maxMoves = ackRTT + 2;
} }
lastAckMoveId = m; lastAckMoveId = m.id;
return mv; return mv;
} }

View file

@ -79,7 +79,7 @@ class Net {
public static var serverInfo:ServerInfo; public static var serverInfo:ServerInfo;
public static var remoteServerInfo:RemoteServerInfo; public static var remoteServerInfo:RemoteServerInfo;
public static function hostServer(name:String, maxPlayers:Int, privateSlots:Int, privateServer:Bool) { public static function hostServer(name:String, maxPlayers:Int, privateSlots:Int, privateServer:Bool, onHosted:() -> Void) {
serverInfo = new ServerInfo(name, 1, maxPlayers, privateSlots, privateServer, Std.int(999999 * Math.random()), "Lobby", getPlatform()); serverInfo = new ServerInfo(name, 1, maxPlayers, privateSlots, privateServer, Std.int(999999 * Math.random()), "Lobby", getPlatform());
MasterServerClient.connectToMasterServer(() -> { MasterServerClient.connectToMasterServer(() -> {
isHost = true; isHost = true;
@ -87,6 +87,7 @@ class Net {
clientId = 0; clientId = 0;
isMP = true; isMP = true;
MasterServerClient.instance.sendServerInfo(serverInfo); MasterServerClient.instance.sendServerInfo(serverInfo);
onHosted();
}); });
} }

View file

@ -13,8 +13,8 @@ class NetCommands {
MultiplayerLevelSelectGui.setLevelFn(i); MultiplayerLevelSelectGui.setLevelFn(i);
} }
@:rpc(server) public static function playLevel() { @:rpc(server) public static function playLevel(levelIndex:Int) {
MultiplayerLevelSelectGui.playSelectedLevel(); MultiplayerLevelSelectGui.playSelectedLevel(levelIndex);
} }
@:rpc(server) public static function setNetworkRNG(rng:Float) { @:rpc(server) public static function setNetworkRNG(rng:Float) {
@ -43,7 +43,7 @@ class NetCommands {
} }
} }
if (allReady && Net.lobbyHostReady) { if (allReady && Net.lobbyHostReady) {
NetCommands.playLevel(); NetCommands.playLevel(MultiplayerLevelSelectGui.currentSelectionStatic);
} }
} }
} }

View file

@ -27,9 +27,6 @@ class NoiseTileMaterial extends hxsl.Shader {
}; };
var calculatedUV:Vec2; var calculatedUV:Vec2;
var pixelColor:Vec4; var pixelColor:Vec4;
var specColor:Vec3;
var specPower:Float;
var noiseUV:Vec2;
@const var useAccurateNoise:Bool; @const var useAccurateNoise:Bool;
@var var outLightVec:Vec4; @var var outLightVec:Vec4;
@var var outPos:Vec3; @var var outPos:Vec3;