From ecaa938f957f0e7e90cbe1d777d8c8c90b244e96 Mon Sep 17 00:00:00 2001
From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com>
Date: Sat, 6 Apr 2024 18:31:33 +0530
Subject: [PATCH] work on better lobby and gravity impl start
---
src/Marble.hx | 5 +-
src/MarbleWorld.hx | 16 ++-
src/Settings.hx | 2 +-
src/gui/Canvas.hx | 2 +
src/gui/CreateMatchGui.hx | 2 +-
src/gui/EnterNameDlg.hx | 133 ++++++++++-------------
src/gui/MPServerListGui.hx | 2 +
src/gui/MultiplayerGui.hx | 4 +
src/gui/MultiplayerLevelSelectGui.hx | 157 +++++++++++++++------------
src/gui/MultiplayerLoadingGui.hx | 68 +++++++++++-
src/net/BitStream.hx | 16 +++
src/net/ClientConnection.hx | 17 +++
src/net/MarbleUpdateQueue.hx | 10 ++
src/net/MasterServerClient.hx | 10 +-
src/net/Net.hx | 142 +++++++++++-------------
src/net/NetCommands.hx | 39 ++++++-
src/net/NetPacket.hx | 15 ++-
src/net/RPCMacro.hx | 8 ++
18 files changed, 407 insertions(+), 241 deletions(-)
diff --git a/src/Marble.hx b/src/Marble.hx
index 56839257..fc96d2a2 100644
--- a/src/Marble.hx
+++ b/src/Marble.hx
@@ -1732,6 +1732,7 @@ class Marble extends GameObject {
marbleUpdate.oob = this.outOfBounds;
marbleUpdate.powerUpId = this.heldPowerup != null ? this.heldPowerup.netIndex : 0x1FF;
marbleUpdate.netFlags = this.netFlags;
+ marbleUpdate.gravityDirection = this.currentUp;
this.netFlags = 0;
marbleUpdate.serialize(b);
return b.getBytes();
@@ -1756,6 +1757,8 @@ class Marble extends GameObject {
this.blastUseTick = p.blastTick;
this.helicopterUseTick = p.heliTick;
this.megaMarbleUseTick = p.megaTick;
+ this.currentUp = p.gravityDirection;
+ this.level.setUp(cast this, this.currentUp, this.level.timeState, true);
this.outOfBounds = p.oob;
this.camera.oob = p.oob;
if (p.powerUpId == 0x1FF) {
@@ -2306,7 +2309,7 @@ class Marble extends GameObject {
this.blastTicks = 0;
this.helicopterUseTick = 0;
this.megaMarbleUseTick = 0;
- this.netFlags = MarbleNetFlags.DoBlast | MarbleNetFlags.DoMega | MarbleNetFlags.DoHelicopter | MarbleNetFlags.PickupPowerup;
+ this.netFlags = MarbleNetFlags.DoBlast | MarbleNetFlags.DoMega | MarbleNetFlags.DoHelicopter | MarbleNetFlags.PickupPowerup | MarbleNetFlags.GravityChange;
this.lastContactNormal = new Vector(0, 0, 1);
this.contactEntities = [];
this._firstTick = true;
diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx
index 57a94cb9..c446e6b9 100644
--- a/src/MarbleWorld.hx
+++ b/src/MarbleWorld.hx
@@ -342,12 +342,12 @@ class MarbleWorld extends Scheduler {
if (this.isMultiplayer) {
// Add us
if (Net.isHost) {
- this.playGui.addPlayer(0, 'Player 0', true);
+ this.playGui.addPlayer(0, Settings.highscoreName.substr(0, 15), true);
} else {
- this.playGui.addPlayer(Net.clientId, 'Player ${Net.clientId}', true);
+ this.playGui.addPlayer(Net.clientId, Settings.highscoreName.substr(0, 15), true);
}
for (client in Net.clientIdMap) {
- this.playGui.addPlayer(client.id, 'Player ${client.id}', false);
+ this.playGui.addPlayer(client.id, client.name.substr(0, 15), false);
}
}
@@ -651,6 +651,7 @@ class MarbleWorld extends Scheduler {
if (isMultiplayer) {
marble.megaMarbleUseTick = 0;
marble.helicopterUseTick = 0;
+ marble.collider.radius = marble._radius = 0.3;
} else {
@:privateAccess marble.helicopterEnableTime = -1e8;
@:privateAccess marble.megaMarbleEnableTime = -1e8;
@@ -1204,8 +1205,8 @@ class MarbleWorld extends Scheduler {
// Debug.drawSphere(@:privateAccess marbleToUpdate.newPos, marbleToUpdate._radius);
var distFromUs = @:privateAccess marbleToUpdate.newPos.distance(this.marble.newPos);
- if (distFromUs < 5) // {
- m.calculationTicks = ourQueuedMoves.length;
+ // if (distFromUs < 5) // {
+ m.calculationTicks = ourQueuedMoves.length;
// } else {
// m.calculationTicks = Std.int(Math.max(1, ourQueuedMoves.length - (distFromUs - 5) / 3));
// }
@@ -2058,7 +2059,12 @@ class MarbleWorld extends Scheduler {
}
public function setUp(marble:Marble, vec:Vector, timeState:TimeState, instant:Bool = false) {
+ if (vec == marble.currentUp)
+ return;
marble.currentUp = vec;
+ if (isMultiplayer && Net.isHost) {
+ @:privateAccess marble.netFlags |= MarbleNetFlags.GravityChange;
+ }
if (marble == this.marble) {
var currentQuat = this.getOrientationQuat(timeState.currentAttemptTime);
var oldUp = new Vector(0, 0, 1);
diff --git a/src/Settings.hx b/src/Settings.hx
index b09ef48d..99d6f88b 100644
--- a/src/Settings.hx
+++ b/src/Settings.hx
@@ -200,7 +200,7 @@ class Settings {
public static var achievementProgression:Int;
- public static var highscoreName = "";
+ public static var highscoreName = "Player";
public static var uiScale = 1.0;
diff --git a/src/gui/Canvas.hx b/src/gui/Canvas.hx
index 8a67f2f8..c6ce2f44 100644
--- a/src/gui/Canvas.hx
+++ b/src/gui/Canvas.hx
@@ -11,6 +11,7 @@ import gui.GuiControl.MouseState;
class Canvas extends GuiControl {
var scene2d:Scene;
var marbleGame:MarbleGame;
+ var content:GuiControl;
public function new(scene, marbleGame:MarbleGame) {
super();
@@ -30,6 +31,7 @@ class Canvas extends GuiControl {
public function setContent(content:GuiControl) {
this.dispose();
+ this.content = content;
this.addChild(content);
this.render(scene2d);
}
diff --git a/src/gui/CreateMatchGui.hx b/src/gui/CreateMatchGui.hx
index 5e445b7d..b8f111ed 100644
--- a/src/gui/CreateMatchGui.hx
+++ b/src/gui/CreateMatchGui.hx
@@ -114,8 +114,8 @@ class CreateMatchGui extends GuiImage {
nextButton.gamepadAccelerator = ["A"];
nextButton.accelerators = [hxd.Key.ENTER];
nextButton.pressedAction = (e) -> {
+ Net.hostServer('${Settings.highscoreName}\'s Server', maxPlayers, privateSlots, privateGame);
MarbleGame.canvas.setContent(new MultiplayerLevelSelectGui(true));
- Net.hostServer("My Server", maxPlayers, privateSlots, privateGame);
};
bottomBar.addChild(nextButton);
}
diff --git a/src/gui/EnterNameDlg.hx b/src/gui/EnterNameDlg.hx
index 5b44ea02..0a54a402 100644
--- a/src/gui/EnterNameDlg.hx
+++ b/src/gui/EnterNameDlg.hx
@@ -9,62 +9,53 @@ import h3d.Vector;
import src.ResourceLoader;
import src.MarbleGame;
-class EnterNameDlg extends GuiControl {
- public function new(place:Int, okFunc:String->Void) {
- super();
- this.position = new Vector();
- this.extent = new Vector(640, 480);
+class EnterNameDlg extends GuiImage {
+ public function new() {
+ var res = ResourceLoader.getImage("data/ui/xbox/roundedBG.png").resource.toTile();
+ super(res);
this.horizSizing = Width;
this.vertSizing = Height;
+ this.position = new Vector();
+ this.extent = new Vector(640, 480);
- function loadButtonImages(path:String) {
- var normal = ResourceLoader.getResource('${path}_n.png', ResourceLoader.getImage, this.imageResources).toTile();
- var hover = ResourceLoader.getResource('${path}_h.png', ResourceLoader.getImage, this.imageResources).toTile();
- var pressed = ResourceLoader.getResource('${path}_d.png', ResourceLoader.getImage, this.imageResources).toTile();
- return [normal, hover, pressed];
- }
-
- var arial14fontdata = ResourceLoader.getFileEntry("data/font/arial.fnt");
+ var arial14fontdata = ResourceLoader.getFileEntry("data/font/Arial Bold.fnt");
var arial14b = new BitmapFont(arial14fontdata.entry);
@:privateAccess arial14b.loader = ResourceLoader.loader;
- var arial14 = arial14b.toSdfFont(cast 12 * Settings.uiScale, MultiChannel);
+ var arial14 = arial14b.toSdfFont(cast 21 * Settings.uiScale, h2d.Font.SDFChannel.MultiChannel);
- var domcasual32fontdata = ResourceLoader.getFileEntry("data/font/DomCasualD.fnt");
- var domcasual32b = new BitmapFont(domcasual32fontdata.entry);
- @:privateAccess domcasual32b.loader = ResourceLoader.loader;
- var domcasual32 = domcasual32b.toSdfFont(cast 26 * Settings.uiScale, MultiChannel);
- var domcasual48 = domcasual32b.toSdfFont(cast 42 * Settings.uiScale, MultiChannel);
+ var yesNoFrame = new GuiImage(ResourceLoader.getResource("data/ui/xbox/popupGUI.png", ResourceLoader.getImage, this.imageResources).toTile());
+ yesNoFrame.horizSizing = Center;
+ yesNoFrame.vertSizing = Center;
+ yesNoFrame.position = new Vector(70, 30);
+ yesNoFrame.extent = new Vector(512, 400);
+ this.addChild(yesNoFrame);
- function mlFontLoader(text:String) {
- switch (text) {
- case "DomCasual32":
- return domcasual32;
- case "DomCasual48":
- return domcasual48;
- case "Arial14":
- return arial14;
- default:
- return null;
- }
- }
+ var text = "Enter your name";
- var dlg = new GuiImage(ResourceLoader.getResource("data/ui/endgame/enternamebox.png", ResourceLoader.getImage, this.imageResources).toTile());
- dlg.horizSizing = Center;
- dlg.vertSizing = Center;
- dlg.position = new Vector(110, 112);
- dlg.extent = new Vector(420, 256);
- this.addChild(dlg);
+ var yesNoText = new GuiMLText(arial14, null);
+ yesNoText.position = new Vector(103, 85);
+ yesNoText.extent = new Vector(313, 186);
+ yesNoText.text.text = text;
+ yesNoText.text.textColor = 0xEBEBEB;
+ yesNoFrame.addChild(yesNoText);
- var enterNameEdit = new GuiTextInput(domcasual32);
- enterNameEdit.text.textColor = 0;
- enterNameEdit.text.selectionColor.setColor(0xFFFFFFFF);
- enterNameEdit.text.selectionTile = h2d.Tile.fromColor(0x808080, 0, hxd.Math.ceil(enterNameEdit.text.font.lineHeight));
- enterNameEdit.position = new Vector(28, 130);
- enterNameEdit.extent = new Vector(363, 38);
- enterNameEdit.text.text = Settings.highscoreName;
- haxe.Timer.delay(() -> {
- enterNameEdit.text.focus();
- }, 5);
+ var textFrame = new GuiControl();
+ textFrame.position = new Vector(33, 107);
+ textFrame.extent = new Vector(232, 40);
+ textFrame.horizSizing = Center;
+ yesNoFrame.addChild(textFrame);
+
+ var textInput = new GuiTextInput(arial14);
+ textInput.position = new Vector(6, 5);
+ textInput.extent = new Vector(216, 40);
+ textInput.horizSizing = Width;
+ textInput.vertSizing = Height;
+ textInput.text.textColor = 0xEBEBEB;
+ textInput.text.selectionColor.setColor(0x8DFF8D);
+ textInput.text.selectionTile = h2d.Tile.fromColor(0x88BCEE, 0, hxd.Math.ceil(textInput.text.font.lineHeight));
+ textFrame.addChild(textInput);
+
+ textInput.text.text = Settings.highscoreName;
enterNameEdit.text.onFocus = (e) -> {
dlg.vertSizing = Bottom;
dlg.position = new Vector(110, 56);
@@ -76,34 +67,28 @@ class EnterNameDlg extends GuiControl {
dlg.render(MarbleGame.canvas.scene2d);
}
- var okbutton = new GuiButton(loadButtonImages("data/ui/endgame/ok"));
- okbutton.position = new Vector(151, 184);
- okbutton.extent = new Vector(110, 55);
- okbutton.accelerator = hxd.Key.ENTER;
- okbutton.gamepadAccelerator = ["A"];
- okbutton.pressedAction = (sender) -> {
- MarbleGame.canvas.popDialog(this);
- Settings.highscoreName = enterNameEdit.text.text;
- okFunc(enterNameEdit.text.text);
+ var okButton = new GuiXboxButton("Ok", 120);
+ okButton.position = new Vector(211, 248);
+ okButton.extent = new Vector(120, 94);
+ okButton.vertSizing = Top;
+ okButton.accelerators = [hxd.Key.ENTER];
+ okButton.gamepadAccelerator = ["A"];
+ okButton.pressedAction = (sender) -> {
+ Settings.highscoreName = textInput.text.text.substr(0, 15); // Max 15 pls
+ Settings.save();
+ MarbleGame.canvas.setContent(new MultiplayerGui());
}
- dlg.addChild(okbutton);
+ yesNoFrame.addChild(okButton);
- var wnd = new GuiImage(ResourceLoader.getResource("data/ui/endgame/window.png", ResourceLoader.getImage, this.imageResources).toTile());
- wnd.horizSizing = Width;
- wnd.vertSizing = Height;
- wnd.position = new Vector(16, 119);
- wnd.extent = new Vector(388, 56);
- dlg.addChild(wnd);
-
- var enterNameText = new GuiMLText(domcasual32, mlFontLoader);
- enterNameText.text.textColor = 0xFFFFFF;
- enterNameText.text.filter = new DropShadow(1.414, 0.785, 0x7777777F, 1, 0, 0.4, 1, true);
- enterNameText.position = new Vector(37, 23);
- enterNameText.extent = new Vector(345, 85);
- // enterNameText.justify = Center;
- enterNameText.text.text = '
Well Done!
You have the${["", " second", " third", " fourth", " fifth"][place]} top time!
';
- dlg.addChild(enterNameText);
-
- dlg.addChild(enterNameEdit);
+ var cancelButton = new GuiXboxButton("Cancel", 120);
+ cancelButton.position = new Vector(321, 248);
+ cancelButton.extent = new Vector(120, 94);
+ cancelButton.vertSizing = Top;
+ cancelButton.accelerators = [hxd.Key.ENTER];
+ cancelButton.gamepadAccelerator = ["A"];
+ cancelButton.pressedAction = (sender) -> {
+ MarbleGame.canvas.setContent(new MultiplayerGui());
+ }
+ yesNoFrame.addChild(cancelButton);
}
}
diff --git a/src/gui/MPServerListGui.hx b/src/gui/MPServerListGui.hx
index e7dabf54..05e55ca9 100644
--- a/src/gui/MPServerListGui.hx
+++ b/src/gui/MPServerListGui.hx
@@ -120,8 +120,10 @@ class MPServerListGui extends GuiImage {
nextButton.accelerators = [hxd.Key.ENTER];
nextButton.gamepadAccelerator = ["X"];
nextButton.pressedAction = (e) -> {
+ MarbleGame.canvas.setContent(new MultiplayerLoadingGui("Connecting"));
Net.joinServer(ourServerList[curSelection].name, () -> {
MarbleGame.canvas.setContent(new MultiplayerLevelSelectGui(false));
+ Net.remoteServerInfo = ourServerList[curSelection];
});
};
bottomBar.addChild(nextButton);
diff --git a/src/gui/MultiplayerGui.hx b/src/gui/MultiplayerGui.hx
index f63547a4..c9b0bc5e 100644
--- a/src/gui/MultiplayerGui.hx
+++ b/src/gui/MultiplayerGui.hx
@@ -78,6 +78,10 @@ class MultiplayerGui extends GuiImage {
// });
});
+ btnList.addButton(5, 'Change Display Name', (e) -> {
+ MarbleGame.canvas.setContent(new EnterNameDlg());
+ });
+
var bottomBar = new GuiControl();
bottomBar.position = new Vector(0, 590);
bottomBar.extent = new Vector(640, 200);
diff --git a/src/gui/MultiplayerLevelSelectGui.hx b/src/gui/MultiplayerLevelSelectGui.hx
index 6dec7aef..817527a0 100644
--- a/src/gui/MultiplayerLevelSelectGui.hx
+++ b/src/gui/MultiplayerLevelSelectGui.hx
@@ -1,5 +1,6 @@
package gui;
+import net.Net;
import net.NetCommands;
import modes.GameMode.ScoreType;
import src.Util;
@@ -19,6 +20,8 @@ class MultiplayerLevelSelectGui extends GuiImage {
static var setLevelFn:Int->Void;
static var playSelectedLevel:Void->Void;
+ var playerList:GuiMLTextListCtrl;
+ var updatePlayerCountFn:(Int, Int, Int, Int) -> Void;
var innerCtrl:GuiControl;
public function new(isHost:Bool) {
@@ -29,8 +32,15 @@ class MultiplayerLevelSelectGui extends GuiImage {
var arial14b = new BitmapFont(arial14fontdata.entry);
@:privateAccess arial14b.loader = ResourceLoader.loader;
var arial14 = arial14b.toSdfFont(cast 21 * Settings.uiScale, h2d.Font.SDFChannel.MultiChannel);
+ var arial12 = arial14b.toSdfFont(cast 16 * Settings.uiScale, h2d.Font.SDFChannel.MultiChannel);
function mlFontLoader(text:String) {
- return arial14;
+ switch (text) {
+ case "arial14":
+ return arial14;
+ case "arial12":
+ return arial12;
+ }
+ return null;
}
MarbleGame.instance.toRecord = false;
@@ -127,11 +137,34 @@ class MultiplayerLevelSelectGui extends GuiImage {
rootTitle.position = new Vector(100, 30);
rootTitle.extent = new Vector(1120, 80);
rootTitle.text.textColor = 0xFFFFFF;
- rootTitle.text.text = "SELECT LEVEL";
+ rootTitle.text.text = "LOBBY";
rootTitle.text.alpha = 0.5;
innerCtrl.addChild(rootTitle);
- var bottomBar = new GuiControl();
+ var playerWnd = new GuiImage(ResourceLoader.getResource("data/ui/xbox/achievementWindow.png", ResourceLoader.getImage, this.imageResources).toTile());
+ playerWnd.horizSizing = Right;
+ playerWnd.vertSizing = Bottom;
+ playerWnd.position = new Vector(330, 58);
+ playerWnd.extent = new Vector(640, 480);
+ innerCtrl.addChild(playerWnd);
+
+ var playerListArr = [Settings.highscoreName];
+ if (Net.isClient) {
+ for (c => v in Net.clientIdMap) {
+ playerListArr.push(v.getName());
+ }
+ }
+
+ playerList = new GuiMLTextListCtrl(arial14, playerListArr, null);
+ playerList.selectedColor = 0xF29515;
+ playerList.selectedFillColor = 0xEBEBEB;
+ playerList.position = new Vector(25, 22);
+ playerList.extent = new Vector(550, 480);
+ playerList.scrollable = true;
+ playerList.onSelectedFunc = (sel) -> {}
+ playerWnd.addChild(playerList);
+
+ var bottomBar = new GuiControl();
bottomBar.position = new Vector(0, 590);
bottomBar.extent = new Vector(640, 200);
bottomBar.horizSizing = Width;
@@ -144,7 +177,10 @@ class MultiplayerLevelSelectGui extends GuiImage {
backButton.horizSizing = Right;
backButton.gamepadAccelerator = ["B"];
backButton.accelerators = [hxd.Key.ESCAPE, hxd.Key.BACKSPACE];
- backButton.pressedAction = (e) -> MarbleGame.canvas.setContent(new DifficultySelectGui());
+ backButton.pressedAction = (e) -> {
+ Net.disconnect();
+ MarbleGame.canvas.setContent(new CreateMatchGui());
+ }
bottomBar.addChild(backButton);
// var lbButton = new GuiXboxButton("Leaderboard", 220);
@@ -153,18 +189,17 @@ class MultiplayerLevelSelectGui extends GuiImage {
// lbButton.horizSizing = Right;
// bottomBar.addChild(lbButton);
- if (isHost) {
- var nextButton = new GuiXboxButton("Play", 160);
- nextButton.position = new Vector(960, 0);
- nextButton.vertSizing = Bottom;
- nextButton.horizSizing = Right;
- nextButton.gamepadAccelerator = ["A"];
- nextButton.accelerators = [hxd.Key.ENTER];
- nextButton.pressedAction = (e) -> {
- NetCommands.playLevel();
- };
- bottomBar.addChild(nextButton);
- }
+ var nextButton = new GuiXboxButton("Ready", 160);
+ nextButton.position = new Vector(960, 0);
+ nextButton.vertSizing = Bottom;
+ nextButton.horizSizing = Right;
+ nextButton.gamepadAccelerator = ["A"];
+ nextButton.accelerators = [hxd.Key.ENTER];
+ nextButton.pressedAction = (e) -> {
+ NetCommands.toggleReadiness(Net.isClient ? Net.clientId : 0);
+ };
+ bottomBar.addChild(nextButton);
+
playSelectedLevel = () -> {
MarbleGame.instance.playMission(curMission, true);
}
@@ -176,42 +211,19 @@ class MultiplayerLevelSelectGui extends GuiImage {
levelWnd.horizSizing = Right;
innerCtrl.addChild(levelWnd);
- var statIcon = new GuiImage(ResourceLoader.getResource("data/ui/xbox/statIcon.png", ResourceLoader.getImage, this.imageResources).toTile());
- statIcon.position = new Vector(29, 54);
- statIcon.extent = new Vector(20, 20);
- levelWnd.addChild(statIcon);
-
- var eggIcon = new GuiImage(ResourceLoader.getResource("data/ui/xbox/eggIcon.png", ResourceLoader.getImage, this.imageResources).toTile());
- eggIcon.position = new Vector(29, 79);
- eggIcon.extent = new Vector(20, 20);
- levelWnd.addChild(eggIcon);
-
var c0 = 0xEBEBEB;
var c1 = 0x8DFF8D;
var c2 = 0x88BCEE;
var c3 = 0xFF7575;
var levelInfoLeft = new GuiMLText(arial14, mlFontLoader);
- levelInfoLeft.position = new Vector(69, 54);
- levelInfoLeft.extent = new Vector(180, 100);
- levelInfoLeft.text.text = 'My Best Time:
Par Time:
';
- levelInfoLeft.text.lineSpacing = 6;
+ levelInfoLeft.position = new Vector(33, 40);
+ levelInfoLeft.extent = new Vector(480, 100);
+ levelInfoLeft.text.text = '';
+ levelInfoLeft.text.lineSpacing = 0;
+ levelInfoLeft.text.filter = new h2d.filter.DropShadow(2, 0.785, 0x000000, 1, 0, 0.4, 1, true);
levelWnd.addChild(levelInfoLeft);
- var levelInfoMid = new GuiMLText(arial14, mlFontLoader);
- levelInfoMid.position = new Vector(269, 54);
- levelInfoMid.extent = new Vector(180, 100);
- levelInfoMid.text.text = 'None
99:59:99
';
- levelInfoMid.text.lineSpacing = 6;
- levelWnd.addChild(levelInfoMid);
-
- var levelInfoRight = new GuiMLText(arial14, mlFontLoader);
- levelInfoRight.position = new Vector(379, 54);
- levelInfoRight.extent = new Vector(180, 100);
- levelInfoRight.text.text = 'Level 1
Difficulty 1
';
- levelInfoRight.text.lineSpacing = 6;
- levelWnd.addChild(levelInfoRight);
-
var levelNames = difficultyMissions.map(x -> x.title);
var levelSelectOpts = new GuiXboxOptionsList(6, "Level", levelNames);
@@ -230,10 +242,6 @@ class MultiplayerLevelSelectGui extends GuiImage {
var misFile = Path.withoutExtension(Path.withoutDirectory(curMission.path));
var mis = difficultyMissions[idx];
var requestToken = currentToken;
- if (Settings.easterEggs.exists(mis.path))
- eggIcon.bmp.visible = true;
- else
- eggIcon.bmp.visible = false;
MarbleGame.instance.setPreviewMission(misFile, () -> {
lock = false;
if (requestToken != currentToken)
@@ -243,34 +251,31 @@ class MultiplayerLevelSelectGui extends GuiImage {
loadText.text.visible = false;
loadTextBg.text.visible = false;
});
-
- var scoreType = mis.missionInfo.gamemode != null
- && mis.missionInfo.gamemode.toLowerCase() == 'scrum' ? ScoreType.Score : ScoreType.Time;
-
- var myScore = Settings.getScores(mis.path);
- var scoreDisp = "None";
- if (myScore.length != 0)
- scoreDisp = scoreType == Time ? Util.formatTime(myScore[0].time) : Util.formatScore(myScore[0].time);
- var isPar = myScore.length != 0 && myScore[0].time < mis.qualifyTime;
- var scoreColor = "#EBEBEB";
- if (isPar)
- scoreColor = "#8DFF8D";
- if (scoreType == Score && myScore.length == 0)
- scoreColor = "#EBEBEB";
- if (scoreType == Time) {
- levelInfoLeft.text.text = 'My Best Time:
Par Time:
';
- levelInfoMid.text.text = '${scoreDisp}
${Util.formatTime(mis.qualifyTime)}
';
+ var hostName = Settings.highscoreName;
+ if (!Net.isHost) {
+ hostName = Net.clientIdMap[0].getName();
}
- if (scoreType == Score) {
- levelInfoLeft.text.text = 'My Best Score:
';
- levelInfoMid.text.text = '${scoreDisp}
';
+
+ if (Net.isHost) {
+ updatePlayerCountFn = (pub:Int, priv:Int, publicTotal:Int, privateTotal:Int) -> {
+ levelInfoLeft.text.text = 'Host: ${hostName}
'
+ + 'Level: ${mis.title}
'
+ + 'Private Slots: ${pub}/${publicTotal}, Public Slots: ${priv}/${privateTotal}
';
+ }
+
+ updatePlayerCountFn(0, 0, Net.serverInfo.maxPlayers - Net.serverInfo.privateSlots, Net.serverInfo.privateSlots);
+ }
+ if (Net.isClient) {
+ updatePlayerCountFn = (pub:Int, priv:Int, publicTotal:Int, privateTotal:Int) -> {
+ levelInfoLeft.text.text = 'Host: ${hostName}
' + 'Level: ${mis.title}
';
+ }
+ updatePlayerCountFn(0, 0, 0, 0);
}
- levelInfoRight.text.text = 'Level ${mis.missionInfo.level}
Difficulty ${mis.missionInfo.difficulty == null ? "" : mis.missionInfo.difficulty}
';
return true;
}
setLevelFn = setLevel;
- levelSelectOpts.position = new Vector(380, 435);
+ levelSelectOpts.position = new Vector(380, 430);
levelSelectOpts.extent = new Vector(815, 94);
levelSelectOpts.vertSizing = Bottom;
levelSelectOpts.horizSizing = Right;
@@ -295,4 +300,16 @@ class MultiplayerLevelSelectGui extends GuiImage {
super.onResize(width, height);
}
+
+ public function updateLobbyNames() {
+ var names = [Settings.highscoreName];
+ for (id => c in Net.clientIdMap) {
+ names.push(c.getName());
+ }
+ playerList.setTexts(names);
+ }
+
+ public function updatePlayerCount(pub:Int, priv:Int, publicTotal:Int, privateTotal:Int) {
+ updatePlayerCountFn(pub, priv, publicTotal, privateTotal);
+ }
}
diff --git a/src/gui/MultiplayerLoadingGui.hx b/src/gui/MultiplayerLoadingGui.hx
index 9f06fd66..485b297b 100644
--- a/src/gui/MultiplayerLoadingGui.hx
+++ b/src/gui/MultiplayerLoadingGui.hx
@@ -10,8 +10,11 @@ import src.Util;
class MultiplayerLoadingGui extends GuiImage {
var loadText:GuiText;
var loadTextBg:GuiText;
+ var loadAnim:GuiLoadAnim;
+ var bottomBar:GuiControl;
+ var innerCtrl:GuiControl;
- public function new(missionName:String) {
+ public function new(initialStatus:String) {
var res = ResourceLoader.getImage("data/ui/game/CloudBG.jpg").resource.toTile();
super(res);
this.position = new Vector();
@@ -31,7 +34,7 @@ class MultiplayerLoadingGui extends GuiImage {
@:privateAccess arial14b.loader = ResourceLoader.loader;
var arial14 = arial14b.toSdfFont(cast 21 * Settings.uiScale, h2d.Font.SDFChannel.MultiChannel);
- var loadAnim = new GuiLoadAnim();
+ loadAnim = new GuiLoadAnim();
loadAnim.position = new Vector(610, 253);
loadAnim.extent = new Vector(63, 63);
loadAnim.horizSizing = Center;
@@ -44,7 +47,7 @@ class MultiplayerLoadingGui extends GuiImage {
loadTextBg.horizSizing = Center;
loadTextBg.vertSizing = Bottom;
loadTextBg.justify = Center;
- loadTextBg.text.text = "Loading";
+ loadTextBg.text.text = initialStatus;
loadTextBg.text.textColor = 0;
this.addChild(loadTextBg);
@@ -54,12 +57,69 @@ class MultiplayerLoadingGui extends GuiImage {
loadText.horizSizing = Center;
loadText.vertSizing = Bottom;
loadText.justify = Center;
- loadText.text.text = "Loading";
+ loadText.text.text = initialStatus;
this.addChild(loadText);
+
+ #if hl
+ var scene2d = hxd.Window.getInstance();
+ #end
+ #if js
+ var scene2d = MarbleGame.instance.scene2d;
+ #end
+
+ var offsetX = (scene2d.width - 1280) / 2;
+ var offsetY = (scene2d.height - 720) / 2;
+
+ var subX = 640 - (scene2d.width - offsetX) * 640 / scene2d.width;
+ var subY = 480 - (scene2d.height - offsetY) * 480 / scene2d.height;
+
+ innerCtrl = new GuiControl();
+ innerCtrl.position = new Vector(offsetX, offsetY);
+ innerCtrl.extent = new Vector(640 - subX, 480 - subY);
+ innerCtrl.horizSizing = Width;
+ innerCtrl.vertSizing = Height;
+ this.addChild(innerCtrl);
+
+ bottomBar = new GuiControl();
+ bottomBar.position = new Vector(0, 590);
+ bottomBar.extent = new Vector(640, 200);
+ bottomBar.horizSizing = Width;
+ bottomBar.vertSizing = Bottom;
+ innerCtrl.addChild(bottomBar);
}
public function setLoadingStatus(str:String) {
loadText.text.text = str;
loadTextBg.text.text = str;
}
+
+ public function setErrorStatus(str:String) {
+ loadText.text.text = str;
+ loadTextBg.text.text = str;
+ loadAnim.anim.visible = false;
+
+ var backButton = new GuiXboxButton("Ok", 160);
+ backButton.position = new Vector(960, 0);
+ backButton.vertSizing = Bottom;
+ backButton.horizSizing = Right;
+ backButton.gamepadAccelerator = ["A"];
+ backButton.accelerators = [hxd.Key.ENTER];
+ backButton.pressedAction = (e) -> {
+ MarbleGame.canvas.setContent(new MultiplayerGui());
+ };
+ bottomBar.addChild(backButton);
+ MarbleGame.canvas.render(MarbleGame.canvas.scene2d);
+ }
+
+ override function onResize(width:Int, height:Int) {
+ var offsetX = (width - 1280) / 2;
+ var offsetY = (height - 720) / 2;
+
+ var subX = 640 - (width - offsetX) * 640 / width;
+ var subY = 480 - (height - offsetY) * 480 / height;
+ innerCtrl.position = new Vector(offsetX, offsetY);
+ innerCtrl.extent = new Vector(640 - subX, 480 - subY);
+
+ super.onResize(width, height);
+ }
}
diff --git a/src/net/BitStream.hx b/src/net/BitStream.hx
index 15da901e..63f6849f 100644
--- a/src/net/BitStream.hx
+++ b/src/net/BitStream.hx
@@ -67,6 +67,15 @@ class InputBitStream {
public function readFloat() {
return FPHelper.i32ToFloat(readInt32());
}
+
+ public function readString() {
+ var length = readByte();
+ var str = "";
+ for (i in 0...length) {
+ str += String.fromCharCode(readByte());
+ }
+ return str;
+ }
}
class OutputBitStream {
@@ -135,4 +144,11 @@ class OutputBitStream {
public function writeFloat(value:Float) {
writeInt(FPHelper.floatToI32(value), 32);
}
+
+ public function writeString(value:String) {
+ writeByte(value.length);
+ for (i in 0...value.length) {
+ writeByte(StringTools.fastCodeAt(value, i));
+ }
+ }
}
diff --git a/src/net/ClientConnection.hx b/src/net/ClientConnection.hx
index 664e2750..3f17aa12 100644
--- a/src/net/ClientConnection.hx
+++ b/src/net/ClientConnection.hx
@@ -26,6 +26,7 @@ class ClientConnection extends GameConnection {
this.datachannel = datachannel;
this.state = GameplayState.LOBBY;
this.rtt = 0;
+ this.name = "Unknown";
}
override function sendBytes(b:Bytes) {
@@ -38,6 +39,7 @@ class DummyConnection extends GameConnection {
public function new(id:Int) {
super(id);
this.state = GameplayState.GAME;
+ this.lobbyReady = true;
}
}
@@ -46,16 +48,23 @@ abstract class GameConnection {
var id:Int;
var state:GameplayState;
var moveManager:MoveManager;
+ var name:String;
+ var lobbyReady:Bool;
public function new(id:Int) {
this.id = id;
this.moveManager = new MoveManager(this);
+ this.lobbyReady = false;
}
public function ready() {
state = GameplayState.GAME;
}
+ public function toggleLobbyReady() {
+ lobbyReady = !lobbyReady;
+ }
+
public function queueMove(m:NetMove) {
moveManager.queueMove(m);
}
@@ -81,4 +90,12 @@ abstract class GameConnection {
}
public function sendBytes(b:haxe.io.Bytes) {}
+
+ public inline function getName() {
+ return name;
+ }
+
+ public inline function setName(value:String) {
+ name = value;
+ }
}
diff --git a/src/net/MarbleUpdateQueue.hx b/src/net/MarbleUpdateQueue.hx
index 42c9a18c..44f8e35a 100644
--- a/src/net/MarbleUpdateQueue.hx
+++ b/src/net/MarbleUpdateQueue.hx
@@ -1,5 +1,6 @@
package net;
+import h3d.Vector;
import net.NetPacket.MarbleNetFlags;
import net.NetPacket.MarbleUpdatePacket;
import net.Net;
@@ -11,6 +12,7 @@ class OtherMarbleUpdate {
var lastHeliTick:Int;
var lastMegaTick:Int;
var lastPowerUpId:Int;
+ var lastGravityUp:Vector;
public function new() {}
}
@@ -48,6 +50,10 @@ class MarbleUpdateQueue {
update.powerUpId = otherUpdate.lastPowerUpId;
else
otherUpdate.lastPowerUpId = update.powerUpId;
+ if (update.netFlags & MarbleNetFlags.GravityChange == 0)
+ update.gravityDirection = otherUpdate.lastGravityUp;
+ else
+ otherUpdate.lastGravityUp = update.gravityDirection;
ourList.push(update);
} else {
var otherUpdate = new OtherMarbleUpdate();
@@ -61,6 +67,8 @@ class MarbleUpdateQueue {
otherUpdate.lastMegaTick = update.megaTick;
if (update.netFlags & MarbleNetFlags.PickupPowerup != 0)
otherUpdate.lastPowerUpId = update.powerUpId;
+ if (update.netFlags & MarbleNetFlags.GravityChange != 0)
+ otherUpdate.lastGravityUp = update.gravityDirection;
otherMarbleUpdates[cc] = otherUpdate;
}
} else {
@@ -75,6 +83,8 @@ class MarbleUpdateQueue {
update.megaTick = myMarbleUpdate.megaTick;
if (update.netFlags & MarbleNetFlags.PickupPowerup == 0)
update.powerUpId = myMarbleUpdate.powerUpId;
+ if (update.netFlags & MarbleNetFlags.GravityChange == 0)
+ update.gravityDirection = myMarbleUpdate.gravityDirection;
}
myMarbleUpdate = update;
ourMoveApplied = false;
diff --git a/src/net/MasterServerClient.hx b/src/net/MasterServerClient.hx
index 29e6b370..cafffe52 100644
--- a/src/net/MasterServerClient.hx
+++ b/src/net/MasterServerClient.hx
@@ -7,6 +7,7 @@ import net.Net.ServerInfo;
import hx.ws.WebSocket;
import src.Console;
import hx.ws.Types.MessageType;
+import gui.MultiplayerLoadingGui;
typedef RemoteServerInfo = {
name:String,
@@ -93,7 +94,7 @@ class MasterServerClient {
if (conts.type == "connect") {
if (!Net.isHost) {
ws.send(Json.stringify({
- type: "connectResponse",
+ type: "connectFailed",
success: false,
reason: "The server has shut down"
}));
@@ -101,7 +102,7 @@ class MasterServerClient {
}
if (Net.serverInfo.players >= Net.serverInfo.maxPlayers) {
ws.send(Json.stringify({
- type: "connectResponse",
+ type: "connectFailed",
success: false,
reason: "The server is full"
}));
@@ -122,7 +123,10 @@ class MasterServerClient {
@:privateAccess Net.client.setRemoteDescription(sdpObj.sdp, sdpObj.type);
}
if (conts.type == "connectFailed") {
- MarbleGame.canvas.pushDialog(new MessageBoxOkDlg(conts.reason));
+ var loadGui:MultiplayerLoadingGui = cast MarbleGame.canvas.content;
+ if (loadGui != null) {
+ loadGui.setErrorStatus(conts.reason);
+ }
}
}
}
diff --git a/src/net/Net.hx b/src/net/Net.hx
index 7bbbc22d..6ef35821 100644
--- a/src/net/Net.hx
+++ b/src/net/Net.hx
@@ -1,5 +1,9 @@
package net;
+import gui.MultiplayerLevelSelectGui;
+import gui.Canvas;
+import net.MasterServerClient.RemoteServerInfo;
+import gui.MultiplayerLoadingGui;
import src.ResourceLoader;
import src.AudioManager;
import net.NetPacket.GemPickupPacket;
@@ -18,6 +22,7 @@ import src.Console;
import net.NetCommands;
import src.MarbleGame;
import hx.ws.Types.MessageType;
+import src.Settings;
enum abstract NetPacketType(Int) from Int to Int {
var NullPacket;
@@ -60,13 +65,11 @@ class Net {
static var client:RTCPeerConnection;
static var clientDatachannel:RTCDataChannel;
- static var masterWs:WebSocket;
-
public static var isMP:Bool;
public static var isHost:Bool;
public static var isClient:Bool;
- public static var startMP:Bool;
+ public static var lobbyHostReady:Bool;
public static var clientId:Int;
public static var networkRNG:Float;
@@ -74,6 +77,7 @@ class Net {
public static var clientIdMap:Map = [];
public static var clientConnection:ClientConnection;
public static var serverInfo:ServerInfo;
+ public static var remoteServerInfo:RemoteServerInfo;
public static function hostServer(name:String, maxPlayers:Int, privateSlots:Int, privateServer:Bool) {
serverInfo = new ServerInfo(name, 1, maxPlayers, privateSlots, privateServer, Std.int(999999 * Math.random()), "Lobby", getPlatform());
@@ -84,30 +88,6 @@ class Net {
isMP = true;
MasterServerClient.instance.sendServerInfo(serverInfo);
});
-
- // host = new RTCPeerConnection(["stun.l.google.com:19302"], "0.0.0.0");
- // host.bind("127.0.0.1", 28000, (c) -> {
- // onClientConnect(c);
- // isMP = true;
- // });
- // isHost = true;
- // isClient = false;
- // clientId = 0;
- // masterWs = new WebSocket("ws://localhost:8080");
-
- // masterWs.onmessage = (m) -> {
- // switch (m) {
- // case StrMessage(content):
- // var conts = Json.parse(content);
- // var peer = new RTCPeerConnection(["stun:stun.l.google.com:19302"], "0.0.0.0");
- // peer.setRemoteDescription(conts.sdp, conts.type);
- // addClient(peer);
-
- // case BytesMessage(content): {}
- // }
- // }
-
- // isMP = true;
}
public static function addClientFromSdp(sdpString:String, onFinishSdp:String->Void) {
@@ -167,6 +147,10 @@ class Net {
clientDatachannel = client.createDatachannel("mp");
clientDatachannel.onOpen = (n) -> {
+ var loadGui:MultiplayerLoadingGui = cast MarbleGame.canvas.content;
+ if (loadGui != null) {
+ loadGui.setLoadingStatus("Handshaking");
+ }
Console.log("Successfully connected!");
clients.set(client, new ClientConnection(0, client, clientDatachannel)); // host is always 0
clientIdMap[0] = clients[client];
@@ -182,6 +166,11 @@ class Net {
if (MarbleGame.instance.world != null) {
MarbleGame.instance.quitMission();
}
+ if (!(MarbleGame.canvas.content is MultiplayerLoadingGui)) {
+ var loadGui = new MultiplayerLoadingGui("Server closed");
+ MarbleGame.canvas.setContent(loadGui);
+ loadGui.setErrorStatus("Server closed");
+ }
}
clientDatachannel.onError = (msg) -> {
Console.log('Errored out due to ${msg}');
@@ -189,63 +178,15 @@ class Net {
if (MarbleGame.instance.world != null) {
MarbleGame.instance.quitMission();
}
+ var loadGui = new MultiplayerLoadingGui("Connection error");
+ MarbleGame.canvas.setContent(loadGui);
+ loadGui.setErrorStatus("Connection error");
}
isMP = true;
isHost = false;
isClient = true;
});
- // masterWs = new WebSocket("ws://localhost:8080");
- // masterWs.onopen = () -> {
- // client = new RTCPeerConnection(["stun:stun.l.google.com:19302"], "0.0.0.0");
- // var candidates = [];
-
- // client.onLocalCandidate = (c) -> {
- // if (c != "")
- // candidates.push('a=${c}');
- // }
- // client.onGatheringStateChange = (s) -> {
- // if (s == RTC_GATHERING_COMPLETE) {
- // Console.log("Local Description Set!");
- // var sdpObj = StringTools.trim(client.localDescription);
- // sdpObj = sdpObj + '\r\n' + candidates.join('\r\n') + '\r\n';
- // masterWs.send(Json.stringify({
- // type: "connect",
- // sdpObj: {
- // sdp: sdpObj,
- // type: "offer"
- // }
- // }));
- // }
- // }
-
- // masterWs.onmessage = (m) -> {
- // switch (m) {
- // case StrMessage(content):
- // Console.log("Remote Description Received!");
- // var conts = Json.parse(content);
- // client.setRemoteDescription(conts.sdp, conts.type);
- // case _: {}
- // }
- // }
-
- // clientDatachannel = client.createDatachannel("mp");
- // clientDatachannel.onOpen = (n) -> {
- // Console.log("Successfully connected!");
- // clients.set(client, new ClientConnection(0, client, clientDatachannel)); // host is always 0
- // clientIdMap[0] = clients[client];
- // clientConnection = cast clients[client];
- // onConnectedToServer();
- // haxe.Timer.delay(() -> connectedCb(), 1500); // 1.5 second delay to do the RTT calculation
- // }
- // clientDatachannel.onMessage = (b) -> {
- // onPacketReceived(client, clientDatachannel, new InputBitStream(b));
- // }
-
- // isMP = true;
- // isHost = false;
- // isClient = true;
- // }
}
public static function disconnect() {
@@ -259,6 +200,9 @@ class Net {
Net.clientId = 0;
Net.clientIdMap.clear();
Net.clientConnection = null;
+ Net.serverInfo = null;
+ Net.remoteServerInfo = null;
+ Net.lobbyHostReady = false;
}
if (Net.isHost) {
NetCommands.serverClosed();
@@ -271,6 +215,9 @@ class Net {
Net.clients.clear();
Net.clientIdMap.clear();
MasterServerClient.disconnectFromMasterServer();
+ Net.serverInfo = null;
+ Net.remoteServerInfo = null;
+ Net.lobbyHostReady = false;
}
}
@@ -308,6 +255,10 @@ class Net {
serverInfo.players++;
MasterServerClient.instance.sendServerInfo(serverInfo); // notify the server of the new player
+
+ if (MarbleGame.canvas.content is MultiplayerLevelSelectGui) {
+ cast(MarbleGame.canvas.content, MultiplayerLevelSelectGui).updateLobbyNames();
+ }
}
static function onConnectedToServer() {
@@ -327,6 +278,12 @@ class Net {
serverInfo.players--;
MasterServerClient.instance.sendServerInfo(serverInfo); // notify the server of the player leave
NetCommands.clientDisconnected(cc.id);
+
+ AudioManager.playSound(ResourceLoader.getAudio("data/sound/infotutorial.wav").resource);
+
+ if (MarbleGame.canvas.content is MultiplayerLevelSelectGui) {
+ cast(MarbleGame.canvas.content, MultiplayerLevelSelectGui).updateLobbyNames();
+ }
}
static function sendPlayerInfosBytes() {
@@ -335,9 +292,22 @@ class Net {
var cnt = 0;
for (c in clientIdMap)
cnt++;
- b.writeByte(cnt);
- for (c => v in clientIdMap)
+ b.writeByte(cnt + 1); // all + host
+ for (c => v in clientIdMap) {
b.writeByte(c);
+ var name = v.getName();
+ b.writeByte(name.length);
+ for (i in 0...name.length) {
+ b.writeByte(StringTools.fastCodeAt(name, i));
+ }
+ }
+ // Write host data
+ b.writeByte(0);
+ var name = Settings.highscoreName;
+ b.writeByte(name.length);
+ for (i in 0...name.length) {
+ b.writeByte(StringTools.fastCodeAt(name, i));
+ }
return b.getBytes();
}
@@ -352,6 +322,7 @@ class Net {
case ClientIdAssign:
clientId = input.readByte(); // 8 bit client id, hopefully we don't exceed this
Console.log('Client ID set to ${clientId}');
+ NetCommands.setPlayerName(clientId, Settings.highscoreName); // Send our player name to the server
case Ping:
var pingLeft = input.readByte();
@@ -435,10 +406,21 @@ class Net {
addGhost(id);
newP = true;
}
+ var nameLength = input.readByte();
+ var name = "";
+ for (j in 0...nameLength) {
+ name += String.fromCharCode(input.readByte());
+ }
+ if (clientIdMap.exists(id)) {
+ clientIdMap[id].setName(name);
+ }
}
if (newP) {
AudioManager.playSound(ResourceLoader.getAudio("sounds/spawn_alternate.wav").resource);
}
+ if (MarbleGame.canvas.content is MultiplayerLevelSelectGui) {
+ cast(MarbleGame.canvas.content, MultiplayerLevelSelectGui).updateLobbyNames();
+ }
case _:
Console.log("unknown command: " + packetType);
diff --git a/src/net/NetCommands.hx b/src/net/NetCommands.hx
index 3ecd71aa..d315b5fb 100644
--- a/src/net/NetCommands.hx
+++ b/src/net/NetCommands.hx
@@ -5,6 +5,7 @@ import net.ClientConnection.GameplayState;
import net.Net.NetPacketType;
import gui.MultiplayerLevelSelectGui;
import src.MarbleGame;
+import gui.MultiplayerLoadingGui;
@:build(net.RPCMacro.build())
class NetCommands {
@@ -28,13 +29,34 @@ class NetCommands {
}
}
+ @:rpc(client) public static function toggleReadiness(clientId:Int) {
+ if (Net.isHost) {
+ if (clientId == 0)
+ Net.lobbyHostReady = !Net.lobbyHostReady;
+ else
+ Net.clientIdMap[clientId].toggleLobbyReady();
+ var allReady = true;
+ for (id => client in Net.clientIdMap) {
+ if (!client.lobbyReady) {
+ allReady = false;
+ break;
+ }
+ }
+ if (allReady && Net.lobbyHostReady) {
+ NetCommands.playLevel();
+ }
+ }
+ }
+
@:rpc(client) public static function clientIsReady(clientId:Int) {
if (Net.isHost) {
Net.clientIdMap[clientId].ready();
var allReady = true;
for (id => client in Net.clientIdMap) {
- if (client.state != GameplayState.GAME)
+ if (client.state != GameplayState.GAME) {
allReady = false;
+ break;
+ }
}
if (allReady) {
if (MarbleGame.instance.world != null) {
@@ -66,6 +88,9 @@ class NetCommands {
MarbleGame.instance.world.removePlayer(conn);
}
Net.clientIdMap.remove(clientId);
+ if (MarbleGame.canvas.content is MultiplayerLevelSelectGui) {
+ cast(MarbleGame.canvas.content, MultiplayerLevelSelectGui).updateLobbyNames();
+ }
}
@:rpc(server) public static function clientJoin(clientId:Int) {}
@@ -81,6 +106,18 @@ class NetCommands {
if (MarbleGame.instance.world != null) {
MarbleGame.instance.quitMission();
}
+ var loadGui = new MultiplayerLoadingGui("Server closed");
+ MarbleGame.canvas.setContent(loadGui);
+ loadGui.setErrorStatus("Server closed");
+ }
+ }
+
+ @:rpc(client) public static function setPlayerName(clientId:Int, name:String) {
+ if (Net.isHost) {
+ Net.clientIdMap[clientId].setName(name);
+ if (MarbleGame.canvas.content is MultiplayerLevelSelectGui) {
+ cast(MarbleGame.canvas.content, MultiplayerLevelSelectGui).updateLobbyNames();
+ }
}
}
}
diff --git a/src/net/NetPacket.hx b/src/net/NetPacket.hx
index 1404a161..d194a474 100644
--- a/src/net/NetPacket.hx
+++ b/src/net/NetPacket.hx
@@ -37,6 +37,7 @@ enum abstract MarbleNetFlags(Int) from Int to Int {
var DoHelicopter = 1 << 1;
var DoMega = 1 << 2;
var PickupPowerup = 1 << 3;
+ var GravityChange = 1 << 4;
}
@:publicFields
@@ -52,6 +53,7 @@ class MarbleUpdatePacket implements NetPacket {
var blastTick:Int;
var megaTick:Int;
var heliTick:Int;
+ var gravityDirection:Vector;
var oob:Bool;
var powerUpId:Int;
var moveQueueSize:Int;
@@ -99,6 +101,14 @@ class MarbleUpdatePacket implements NetPacket {
} else {
b.writeFlag(false);
}
+ if (netFlags & MarbleNetFlags.GravityChange > 0) {
+ b.writeFlag(true);
+ b.writeFloat(gravityDirection.x);
+ b.writeFloat(gravityDirection.y);
+ b.writeFloat(gravityDirection.z);
+ } else {
+ b.writeFlag(false);
+ }
}
public inline function deserialize(b:InputBitStream) {
@@ -126,9 +136,12 @@ class MarbleUpdatePacket implements NetPacket {
oob = b.readFlag();
if (b.readFlag()) {
powerUpId = b.readInt(9);
- trace('pickup: ${powerUpId}');
this.netFlags |= MarbleNetFlags.PickupPowerup;
}
+ if (b.readFlag()) {
+ gravityDirection = new Vector(b.readFloat(), b.readFloat(), b.readFloat());
+ this.netFlags |= MarbleNetFlags.GravityChange;
+ }
}
}
diff --git a/src/net/RPCMacro.hx b/src/net/RPCMacro.hx
index f043ac5c..b9643f48 100644
--- a/src/net/RPCMacro.hx
+++ b/src/net/RPCMacro.hx
@@ -42,6 +42,14 @@ class RPCMacro {
serializeFns.push(macro stream.writeFloat($i{argName}));
}
+ case TPath({
+ name: 'String'
+ }): {
+ deserializeFns.push(macro var $argName = stream.readString());
+ callExprs.push(macro $i{argName});
+ serializeFns.push(macro stream.writeString($i{argName}));
+ }
+
case _: {}
}
}