some work on join-leaves

This commit is contained in:
RandomityGuy 2024-04-05 00:26:39 +05:30
parent afe4969887
commit 208d4df891
9 changed files with 227 additions and 29 deletions

View file

@ -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;

View file

@ -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) {

View file

@ -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();
}

View file

@ -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);

View 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;
}
}

View file

@ -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() {

View file

@ -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",

View file

@ -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() {

View file

@ -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();
}
}
}
}