mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
some work on join-leaves
This commit is contained in:
parent
afe4969887
commit
208d4df891
9 changed files with 227 additions and 29 deletions
|
|
@ -288,6 +288,9 @@ class MarbleGame {
|
||||||
|
|
||||||
public function quitMission() {
|
public function quitMission() {
|
||||||
Console.log("Quitting mission");
|
Console.log("Quitting mission");
|
||||||
|
if (Net.isMP) {
|
||||||
|
Net.disconnect();
|
||||||
|
}
|
||||||
var watching = world.isWatching;
|
var watching = world.isWatching;
|
||||||
var missionType = world.mission.type;
|
var missionType = world.mission.type;
|
||||||
var isNotCustom = !world.mission.isClaMission && !world.mission.isCustom;
|
var isNotCustom = !world.mission.isClaMission && !world.mission.isCustom;
|
||||||
|
|
|
||||||
|
|
@ -1263,12 +1263,16 @@ class MarbleWorld extends Scheduler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function removePlayer(cc:ClientConnection) {
|
public function removePlayer(cc:GameConnection) {
|
||||||
var otherMarble = this.clientMarbles[cc];
|
var otherMarble = this.clientMarbles[cc];
|
||||||
this.predictions.removeMarbleFromPrediction(otherMarble);
|
if (otherMarble != null) {
|
||||||
this.scene.removeChild(otherMarble);
|
this.predictions.removeMarbleFromPrediction(otherMarble);
|
||||||
this.collisionWorld.removeMarbleEntity(otherMarble.collider);
|
this.scene.removeChild(otherMarble);
|
||||||
otherMarble.dispose();
|
this.collisionWorld.removeMarbleEntity(otherMarble.collider);
|
||||||
|
this.playGui.removePlayer(cc.id);
|
||||||
|
this.clientMarbles.remove(cc);
|
||||||
|
otherMarble.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rollback(t:Float) {
|
public function rollback(t:Float) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package src;
|
package src;
|
||||||
|
|
||||||
|
import net.Net;
|
||||||
import collision.CollisionWorld;
|
import collision.CollisionWorld;
|
||||||
import mis.MissionElement.MissionElementSky;
|
import mis.MissionElement.MissionElementSky;
|
||||||
import shapes.Astrolabe;
|
import shapes.Astrolabe;
|
||||||
|
|
@ -286,6 +287,12 @@ class PreviewWorld extends Scheduler {
|
||||||
}, skyElem);
|
}, skyElem);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (Net.isMP) {
|
||||||
|
// Load the MP sounds
|
||||||
|
worker.loadFile("sound/spawn_alternate.wav");
|
||||||
|
worker.loadFile("sound/infotutorial.wav");
|
||||||
|
}
|
||||||
|
|
||||||
worker.run();
|
worker.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,8 +79,9 @@ class CreateMatchGui extends GuiImage {
|
||||||
maxPlayers = idx + 2;
|
maxPlayers = idx + 2;
|
||||||
return true;
|
return true;
|
||||||
}, 0.5, 118);
|
}, 0.5, 118);
|
||||||
|
playerOpt.setCurrentOption(6);
|
||||||
|
|
||||||
var privateOpt = optionCollection.addOption(1, "Max Players", ["None", "1", "2", "3", "4", "5", "6", "7"], (idx) -> {
|
var privateOpt = optionCollection.addOption(1, "Private Slots", ["None", "1", "2", "3", "4", "5", "6", "7"], (idx) -> {
|
||||||
privateSlots = idx;
|
privateSlots = idx;
|
||||||
return true;
|
return true;
|
||||||
}, 0.5, 118);
|
}, 0.5, 118);
|
||||||
|
|
|
||||||
65
src/gui/MultiplayerLoadingGui.hx
Normal file
65
src/gui/MultiplayerLoadingGui.hx
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
package gui;
|
||||||
|
|
||||||
|
import hxd.res.BitmapFont;
|
||||||
|
import h3d.Vector;
|
||||||
|
import src.ResourceLoader;
|
||||||
|
import src.MarbleGame;
|
||||||
|
import src.Settings;
|
||||||
|
import src.Util;
|
||||||
|
|
||||||
|
class MultiplayerLoadingGui extends GuiImage {
|
||||||
|
var loadText:GuiText;
|
||||||
|
var loadTextBg:GuiText;
|
||||||
|
|
||||||
|
public function new(missionName:String) {
|
||||||
|
var res = ResourceLoader.getImage("data/ui/game/CloudBG.jpg").resource.toTile();
|
||||||
|
super(res);
|
||||||
|
this.position = new Vector();
|
||||||
|
this.extent = new Vector(640, 480);
|
||||||
|
this.horizSizing = Width;
|
||||||
|
this.vertSizing = Height;
|
||||||
|
|
||||||
|
var fadeEdge = new GuiImage(ResourceLoader.getResource("data/ui/xbox/BG_fadeOutSoftEdge.png", ResourceLoader.getImage, this.imageResources).toTile());
|
||||||
|
fadeEdge.position = new Vector(0, 0);
|
||||||
|
fadeEdge.extent = new Vector(640, 480);
|
||||||
|
fadeEdge.vertSizing = Height;
|
||||||
|
fadeEdge.horizSizing = Width;
|
||||||
|
this.addChild(fadeEdge);
|
||||||
|
|
||||||
|
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 21 * Settings.uiScale, h2d.Font.SDFChannel.MultiChannel);
|
||||||
|
|
||||||
|
var loadAnim = new GuiLoadAnim();
|
||||||
|
loadAnim.position = new Vector(610, 253);
|
||||||
|
loadAnim.extent = new Vector(63, 63);
|
||||||
|
loadAnim.horizSizing = Center;
|
||||||
|
loadAnim.vertSizing = Bottom;
|
||||||
|
this.addChild(loadAnim);
|
||||||
|
|
||||||
|
loadTextBg = new GuiText(arial14);
|
||||||
|
loadTextBg.position = new Vector(608, 335);
|
||||||
|
loadTextBg.extent = new Vector(63, 40);
|
||||||
|
loadTextBg.horizSizing = Center;
|
||||||
|
loadTextBg.vertSizing = Bottom;
|
||||||
|
loadTextBg.justify = Center;
|
||||||
|
loadTextBg.text.text = "Loading";
|
||||||
|
loadTextBg.text.textColor = 0;
|
||||||
|
this.addChild(loadTextBg);
|
||||||
|
|
||||||
|
loadText = new GuiText(arial14);
|
||||||
|
loadText.position = new Vector(610, 334);
|
||||||
|
loadText.extent = new Vector(63, 40);
|
||||||
|
loadText.horizSizing = Center;
|
||||||
|
loadText.vertSizing = Bottom;
|
||||||
|
loadText.justify = Center;
|
||||||
|
loadText.text.text = "Loading";
|
||||||
|
this.addChild(loadText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLoadingStatus(str:String) {
|
||||||
|
loadText.text.text = str;
|
||||||
|
loadTextBg.text.text = str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -585,28 +585,52 @@ class HuntMode extends NullMode {
|
||||||
override function onTimeExpire() {
|
override function onTimeExpire() {
|
||||||
if (level.finishTime != null)
|
if (level.finishTime != null)
|
||||||
return;
|
return;
|
||||||
if (this.level.isMultiplayer) {
|
|
||||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/finish.wav', ResourceLoader.getAudio, @:privateAccess level.soundResources));
|
AudioManager.playSound(ResourceLoader.getResource('data/sound/finish.wav', ResourceLoader.getAudio, @:privateAccess level.soundResources));
|
||||||
level.finishTime = level.timeState.clone();
|
level.finishTime = level.timeState.clone();
|
||||||
level.marble.setMode(Start);
|
level.marble.setMode(Start);
|
||||||
level.marble.camera.finish = true;
|
level.marble.camera.finish = true;
|
||||||
level.finishYaw = level.marble.camera.CameraYaw;
|
level.finishYaw = level.marble.camera.CameraYaw;
|
||||||
level.finishPitch = level.marble.camera.CameraPitch;
|
level.finishPitch = level.marble.camera.CameraPitch;
|
||||||
level.displayAlert("Congratulations! You've finished!");
|
level.displayAlert("Congratulations! You've finished!");
|
||||||
level.cancel(@:privateAccess level.oobSchedule);
|
level.cancel(@:privateAccess level.oobSchedule);
|
||||||
level.cancel(@:privateAccess level.marble.oobSchedule);
|
level.cancel(@:privateAccess level.marble.oobSchedule);
|
||||||
if (Net.isHost) {
|
if (!level.isWatching) {
|
||||||
NetCommands.timerRanOut();
|
if (level.isMultiplayer) {
|
||||||
}
|
if (Net.isHost) {
|
||||||
if (!level.isWatching) {
|
for (marble in level.marbles) {
|
||||||
@:privateAccess level.schedule(level.timeState.currentAttemptTime, () -> cast level.showFinishScreen());
|
marble.setMode(Start);
|
||||||
}
|
level.cancel(@:privateAccess marble.oobSchedule);
|
||||||
// Stop the ongoing sounds
|
}
|
||||||
if (@:privateAccess level.timeTravelSound != null) {
|
|
||||||
@:privateAccess level.timeTravelSound.stop();
|
NetCommands.timerRanOut();
|
||||||
@:privateAccess level.timeTravelSound = null;
|
}
|
||||||
|
if (!level.isWatching) {
|
||||||
|
@:privateAccess level.schedule(level.timeState.currentAttemptTime, () -> cast level.showFinishScreen());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var myScore = {
|
||||||
|
name: "Player",
|
||||||
|
time: getFinishScore()
|
||||||
|
};
|
||||||
|
Settings.saveScore(level.mission.path, myScore, getScoreType());
|
||||||
|
var notifies = AchievementsGui.check();
|
||||||
|
var delay = 5.0;
|
||||||
|
var achDelay = 0.0;
|
||||||
|
for (i in 0...9) {
|
||||||
|
if (notifies & (1 << i) > 0)
|
||||||
|
achDelay += 3;
|
||||||
|
}
|
||||||
|
if (notifies > 0)
|
||||||
|
achDelay += 0.5;
|
||||||
|
@:privateAccess level.schedule(level.timeState.currentAttemptTime + Math.max(delay, achDelay), () -> cast level.showFinishScreen());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Stop the ongoing sounds
|
||||||
|
if (@:privateAccess level.timeTravelSound != null) {
|
||||||
|
@:privateAccess level.timeTravelSound.stop();
|
||||||
|
@:privateAccess level.timeTravelSound = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function doTimerRunOut() {
|
public function doTimerRunOut() {
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,13 @@ class MasterServerClient {
|
||||||
onConnect();
|
onConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function disconnectFromMasterServer() {
|
||||||
|
if (instance != null) {
|
||||||
|
instance.ws.close();
|
||||||
|
instance = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function sendServerInfo(serverInfo:ServerInfo) {
|
public function sendServerInfo(serverInfo:ServerInfo) {
|
||||||
ws.send(Json.stringify({
|
ws.send(Json.stringify({
|
||||||
type: "serverInfo",
|
type: "serverInfo",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package net;
|
package net;
|
||||||
|
|
||||||
|
import src.ResourceLoader;
|
||||||
|
import src.AudioManager;
|
||||||
import net.NetPacket.GemPickupPacket;
|
import net.NetPacket.GemPickupPacket;
|
||||||
import net.NetPacket.GemSpawnPacket;
|
import net.NetPacket.GemSpawnPacket;
|
||||||
import net.BitStream.InputBitStream;
|
import net.BitStream.InputBitStream;
|
||||||
|
|
@ -175,6 +177,19 @@ class Net {
|
||||||
clientDatachannel.onMessage = (b) -> {
|
clientDatachannel.onMessage = (b) -> {
|
||||||
onPacketReceived(client, clientDatachannel, new InputBitStream(b));
|
onPacketReceived(client, clientDatachannel, new InputBitStream(b));
|
||||||
}
|
}
|
||||||
|
clientDatachannel.onClosed = () -> {
|
||||||
|
disconnect();
|
||||||
|
if (MarbleGame.instance.world != null) {
|
||||||
|
MarbleGame.instance.quitMission();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clientDatachannel.onError = (msg) -> {
|
||||||
|
Console.log('Errored out due to ${msg}');
|
||||||
|
disconnect();
|
||||||
|
if (MarbleGame.instance.world != null) {
|
||||||
|
MarbleGame.instance.quitMission();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
isMP = true;
|
isMP = true;
|
||||||
isHost = false;
|
isHost = false;
|
||||||
|
|
@ -233,6 +248,32 @@ class Net {
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function disconnect() {
|
||||||
|
if (Net.isClient) {
|
||||||
|
NetCommands.clientLeave(Net.clientId);
|
||||||
|
Net.isMP = false;
|
||||||
|
Net.isClient = false;
|
||||||
|
Net.isHost = false;
|
||||||
|
Net.client.close();
|
||||||
|
Net.client = null;
|
||||||
|
Net.clientId = 0;
|
||||||
|
Net.clientIdMap.clear();
|
||||||
|
Net.clientConnection = null;
|
||||||
|
}
|
||||||
|
if (Net.isHost) {
|
||||||
|
NetCommands.serverClosed();
|
||||||
|
for (client => gc in clients) {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
Net.isMP = false;
|
||||||
|
Net.isClient = false;
|
||||||
|
Net.isHost = false;
|
||||||
|
Net.clients.clear();
|
||||||
|
Net.clientIdMap.clear();
|
||||||
|
MasterServerClient.disconnectFromMasterServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static function onClientConnect(c:RTCPeerConnection, dc:RTCDataChannel) {
|
static function onClientConnect(c:RTCPeerConnection, dc:RTCDataChannel) {
|
||||||
clientId += 1;
|
clientId += 1;
|
||||||
var cc = new ClientConnection(clientId, c, dc);
|
var cc = new ClientConnection(clientId, c, dc);
|
||||||
|
|
@ -242,6 +283,12 @@ class Net {
|
||||||
onPacketReceived(c, dc, new InputBitStream(msgBytes));
|
onPacketReceived(c, dc, new InputBitStream(msgBytes));
|
||||||
}
|
}
|
||||||
dc.onClosed = () -> {
|
dc.onClosed = () -> {
|
||||||
|
clients.remove(c);
|
||||||
|
onClientLeave(cc);
|
||||||
|
}
|
||||||
|
dc.onError = (msg) -> {
|
||||||
|
clients.remove(c);
|
||||||
|
Console.log('Client ${cc.id} errored out due to: ${msg}');
|
||||||
onClientLeave(cc);
|
onClientLeave(cc);
|
||||||
}
|
}
|
||||||
var b = haxe.io.Bytes.alloc(2);
|
var b = haxe.io.Bytes.alloc(2);
|
||||||
|
|
@ -257,6 +304,8 @@ class Net {
|
||||||
dc.sendBytes(b);
|
dc.sendBytes(b);
|
||||||
Console.log("Sending ping packet!");
|
Console.log("Sending ping packet!");
|
||||||
|
|
||||||
|
AudioManager.playSound(ResourceLoader.getAudio("data/sound/spawn_alternate.wav").resource);
|
||||||
|
|
||||||
serverInfo.players++;
|
serverInfo.players++;
|
||||||
MasterServerClient.instance.sendServerInfo(serverInfo); // notify the server of the new player
|
MasterServerClient.instance.sendServerInfo(serverInfo); // notify the server of the new player
|
||||||
}
|
}
|
||||||
|
|
@ -273,8 +322,11 @@ class Net {
|
||||||
}
|
}
|
||||||
|
|
||||||
static function onClientLeave(cc:ClientConnection) {
|
static function onClientLeave(cc:ClientConnection) {
|
||||||
|
if (!Net.isMP)
|
||||||
|
return;
|
||||||
serverInfo.players--;
|
serverInfo.players--;
|
||||||
MasterServerClient.instance.sendServerInfo(serverInfo); // notify the server of the player leave
|
MasterServerClient.instance.sendServerInfo(serverInfo); // notify the server of the player leave
|
||||||
|
NetCommands.clientDisconnected(cc.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function sendPlayerInfosBytes() {
|
static function sendPlayerInfosBytes() {
|
||||||
|
|
@ -290,6 +342,8 @@ class Net {
|
||||||
}
|
}
|
||||||
|
|
||||||
static function onPacketReceived(c:RTCPeerConnection, dc:RTCDataChannel, input:InputBitStream) {
|
static function onPacketReceived(c:RTCPeerConnection, dc:RTCDataChannel, input:InputBitStream) {
|
||||||
|
if (!Net.isMP)
|
||||||
|
return; // only for MP
|
||||||
var packetType = input.readByte();
|
var packetType = input.readByte();
|
||||||
switch (packetType) {
|
switch (packetType) {
|
||||||
case NetCommand:
|
case NetCommand:
|
||||||
|
|
@ -326,7 +380,9 @@ class Net {
|
||||||
Console.log('Got RTT ${conn.rtt} for client ${conn.id}');
|
Console.log('Got RTT ${conn.rtt} for client ${conn.id}');
|
||||||
if (Net.isHost) {
|
if (Net.isHost) {
|
||||||
var b = sendPlayerInfosBytes();
|
var b = sendPlayerInfosBytes();
|
||||||
conn.sendBytes(b);
|
for (cc in clients) {
|
||||||
|
cc.sendBytes(b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -371,13 +427,18 @@ class Net {
|
||||||
|
|
||||||
case PlayerInfo:
|
case PlayerInfo:
|
||||||
var count = input.readByte();
|
var count = input.readByte();
|
||||||
|
var newP = false;
|
||||||
for (i in 0...count) {
|
for (i in 0...count) {
|
||||||
var id = input.readByte();
|
var id = input.readByte();
|
||||||
if (id != 0 && id != Net.clientId && !clientIdMap.exists(id)) {
|
if (id != 0 && id != Net.clientId && !clientIdMap.exists(id)) {
|
||||||
Console.log('Adding ghost connection ${id}');
|
Console.log('Adding ghost connection ${id}');
|
||||||
addGhost(id);
|
addGhost(id);
|
||||||
|
newP = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (newP) {
|
||||||
|
AudioManager.playSound(ResourceLoader.getAudio("sounds/spawn_alternate.wav").resource);
|
||||||
|
}
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
Console.log("unknown command: " + packetType);
|
Console.log("unknown command: " + packetType);
|
||||||
|
|
@ -392,8 +453,10 @@ class Net {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function sendPacketToHost(packetData:OutputBitStream) {
|
public static function sendPacketToHost(packetData:OutputBitStream) {
|
||||||
var bytes = packetData.getBytes();
|
if (clientDatachannel.state == Open) {
|
||||||
clientDatachannel.sendBytes(bytes);
|
var bytes = packetData.getBytes();
|
||||||
|
clientDatachannel.sendBytes(bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function addDummyConnection() {
|
public static function addDummyConnection() {
|
||||||
|
|
|
||||||
|
|
@ -59,4 +59,28 @@ class NetCommands {
|
||||||
huntMode.onTimeExpire();
|
huntMode.onTimeExpire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@:rpc(server) public static function clientDisconnected(clientId:Int) {
|
||||||
|
var conn = Net.clientIdMap.get(clientId);
|
||||||
|
if (MarbleGame.instance.world != null) {
|
||||||
|
MarbleGame.instance.world.removePlayer(conn);
|
||||||
|
}
|
||||||
|
Net.clientIdMap.remove(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:rpc(server) public static function clientJoin(clientId:Int) {}
|
||||||
|
|
||||||
|
@:rpc(client) public static function clientLeave(clientId:Int) {
|
||||||
|
if (Net.isHost) {
|
||||||
|
@:privateAccess Net.onClientLeave(cast Net.clientIdMap[clientId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@:rpc(server) public static function serverClosed() {
|
||||||
|
if (Net.isClient) {
|
||||||
|
if (MarbleGame.instance.world != null) {
|
||||||
|
MarbleGame.instance.quitMission();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue