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() {
|
||||
Console.log("Quitting mission");
|
||||
if (Net.isMP) {
|
||||
Net.disconnect();
|
||||
}
|
||||
var watching = world.isWatching;
|
||||
var missionType = world.mission.type;
|
||||
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];
|
||||
this.predictions.removeMarbleFromPrediction(otherMarble);
|
||||
this.scene.removeChild(otherMarble);
|
||||
this.collisionWorld.removeMarbleEntity(otherMarble.collider);
|
||||
otherMarble.dispose();
|
||||
if (otherMarble != null) {
|
||||
this.predictions.removeMarbleFromPrediction(otherMarble);
|
||||
this.scene.removeChild(otherMarble);
|
||||
this.collisionWorld.removeMarbleEntity(otherMarble.collider);
|
||||
this.playGui.removePlayer(cc.id);
|
||||
this.clientMarbles.remove(cc);
|
||||
otherMarble.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public function rollback(t:Float) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package src;
|
||||
|
||||
import net.Net;
|
||||
import collision.CollisionWorld;
|
||||
import mis.MissionElement.MissionElementSky;
|
||||
import shapes.Astrolabe;
|
||||
|
|
@ -286,6 +287,12 @@ class PreviewWorld extends Scheduler {
|
|||
}, skyElem);
|
||||
});
|
||||
|
||||
if (Net.isMP) {
|
||||
// Load the MP sounds
|
||||
worker.loadFile("sound/spawn_alternate.wav");
|
||||
worker.loadFile("sound/infotutorial.wav");
|
||||
}
|
||||
|
||||
worker.run();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,8 +79,9 @@ class CreateMatchGui extends GuiImage {
|
|||
maxPlayers = idx + 2;
|
||||
return true;
|
||||
}, 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;
|
||||
return true;
|
||||
}, 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() {
|
||||
if (level.finishTime != null)
|
||||
return;
|
||||
if (this.level.isMultiplayer) {
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/finish.wav', ResourceLoader.getAudio, @:privateAccess level.soundResources));
|
||||
level.finishTime = level.timeState.clone();
|
||||
level.marble.setMode(Start);
|
||||
level.marble.camera.finish = true;
|
||||
level.finishYaw = level.marble.camera.CameraYaw;
|
||||
level.finishPitch = level.marble.camera.CameraPitch;
|
||||
level.displayAlert("Congratulations! You've finished!");
|
||||
level.cancel(@:privateAccess level.oobSchedule);
|
||||
level.cancel(@:privateAccess level.marble.oobSchedule);
|
||||
if (Net.isHost) {
|
||||
NetCommands.timerRanOut();
|
||||
}
|
||||
if (!level.isWatching) {
|
||||
@:privateAccess level.schedule(level.timeState.currentAttemptTime, () -> cast level.showFinishScreen());
|
||||
}
|
||||
// Stop the ongoing sounds
|
||||
if (@:privateAccess level.timeTravelSound != null) {
|
||||
@:privateAccess level.timeTravelSound.stop();
|
||||
@:privateAccess level.timeTravelSound = null;
|
||||
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/finish.wav', ResourceLoader.getAudio, @:privateAccess level.soundResources));
|
||||
level.finishTime = level.timeState.clone();
|
||||
level.marble.setMode(Start);
|
||||
level.marble.camera.finish = true;
|
||||
level.finishYaw = level.marble.camera.CameraYaw;
|
||||
level.finishPitch = level.marble.camera.CameraPitch;
|
||||
level.displayAlert("Congratulations! You've finished!");
|
||||
level.cancel(@:privateAccess level.oobSchedule);
|
||||
level.cancel(@:privateAccess level.marble.oobSchedule);
|
||||
if (!level.isWatching) {
|
||||
if (level.isMultiplayer) {
|
||||
if (Net.isHost) {
|
||||
for (marble in level.marbles) {
|
||||
marble.setMode(Start);
|
||||
level.cancel(@:privateAccess marble.oobSchedule);
|
||||
}
|
||||
|
||||
NetCommands.timerRanOut();
|
||||
}
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,13 @@ class MasterServerClient {
|
|||
onConnect();
|
||||
}
|
||||
|
||||
public static function disconnectFromMasterServer() {
|
||||
if (instance != null) {
|
||||
instance.ws.close();
|
||||
instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function sendServerInfo(serverInfo:ServerInfo) {
|
||||
ws.send(Json.stringify({
|
||||
type: "serverInfo",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package net;
|
||||
|
||||
import src.ResourceLoader;
|
||||
import src.AudioManager;
|
||||
import net.NetPacket.GemPickupPacket;
|
||||
import net.NetPacket.GemSpawnPacket;
|
||||
import net.BitStream.InputBitStream;
|
||||
|
|
@ -175,6 +177,19 @@ class Net {
|
|||
clientDatachannel.onMessage = (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;
|
||||
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) {
|
||||
clientId += 1;
|
||||
var cc = new ClientConnection(clientId, c, dc);
|
||||
|
|
@ -242,6 +283,12 @@ class Net {
|
|||
onPacketReceived(c, dc, new InputBitStream(msgBytes));
|
||||
}
|
||||
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);
|
||||
}
|
||||
var b = haxe.io.Bytes.alloc(2);
|
||||
|
|
@ -257,6 +304,8 @@ class Net {
|
|||
dc.sendBytes(b);
|
||||
Console.log("Sending ping packet!");
|
||||
|
||||
AudioManager.playSound(ResourceLoader.getAudio("data/sound/spawn_alternate.wav").resource);
|
||||
|
||||
serverInfo.players++;
|
||||
MasterServerClient.instance.sendServerInfo(serverInfo); // notify the server of the new player
|
||||
}
|
||||
|
|
@ -273,8 +322,11 @@ class Net {
|
|||
}
|
||||
|
||||
static function onClientLeave(cc:ClientConnection) {
|
||||
if (!Net.isMP)
|
||||
return;
|
||||
serverInfo.players--;
|
||||
MasterServerClient.instance.sendServerInfo(serverInfo); // notify the server of the player leave
|
||||
NetCommands.clientDisconnected(cc.id);
|
||||
}
|
||||
|
||||
static function sendPlayerInfosBytes() {
|
||||
|
|
@ -290,6 +342,8 @@ class Net {
|
|||
}
|
||||
|
||||
static function onPacketReceived(c:RTCPeerConnection, dc:RTCDataChannel, input:InputBitStream) {
|
||||
if (!Net.isMP)
|
||||
return; // only for MP
|
||||
var packetType = input.readByte();
|
||||
switch (packetType) {
|
||||
case NetCommand:
|
||||
|
|
@ -326,7 +380,9 @@ class Net {
|
|||
Console.log('Got RTT ${conn.rtt} for client ${conn.id}');
|
||||
if (Net.isHost) {
|
||||
var b = sendPlayerInfosBytes();
|
||||
conn.sendBytes(b);
|
||||
for (cc in clients) {
|
||||
cc.sendBytes(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -371,13 +427,18 @@ class Net {
|
|||
|
||||
case PlayerInfo:
|
||||
var count = input.readByte();
|
||||
var newP = false;
|
||||
for (i in 0...count) {
|
||||
var id = input.readByte();
|
||||
if (id != 0 && id != Net.clientId && !clientIdMap.exists(id)) {
|
||||
Console.log('Adding ghost connection ${id}');
|
||||
addGhost(id);
|
||||
newP = true;
|
||||
}
|
||||
}
|
||||
if (newP) {
|
||||
AudioManager.playSound(ResourceLoader.getAudio("sounds/spawn_alternate.wav").resource);
|
||||
}
|
||||
|
||||
case _:
|
||||
Console.log("unknown command: " + packetType);
|
||||
|
|
@ -392,8 +453,10 @@ class Net {
|
|||
}
|
||||
|
||||
public static function sendPacketToHost(packetData:OutputBitStream) {
|
||||
var bytes = packetData.getBytes();
|
||||
clientDatachannel.sendBytes(bytes);
|
||||
if (clientDatachannel.state == Open) {
|
||||
var bytes = packetData.getBytes();
|
||||
clientDatachannel.sendBytes(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
public static function addDummyConnection() {
|
||||
|
|
|
|||
|
|
@ -59,4 +59,28 @@ class NetCommands {
|
|||
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