void IServerPacket.Read(NetIncomingMessage msg) { ServerName = msg.ReadString(); LevelName = msg.ReadString(); LevelType = (MultiplayerLevelType)msg.ReadByte(); AssignedPlayerIndex = msg.ReadByte(); }
public MultiplayerLevelHandler(App root, GameClient client, LevelInitialization data, MultiplayerLevelType levelType, byte playerIndex) : base(root, data) { this.client = client; this.localPlayerIndex = playerIndex; this.levelType = levelType; client.OnUpdateAllActors += OnUpdateAllActors; client.AddCallback <CreateControllablePlayer>(OnPacketCreateControllablePlayer); client.AddCallback <CreateRemoteActor>(OnPacketCreateRemoteActor); client.AddCallback <DestroyRemoteActor>(OnPacketDestroyRemoteActor); client.AddCallback <RefreshActorAnimation>(OnPacketRefreshActorAnimation); client.AddCallback <ShowMessage>(OnPacketShowMessage); client.AddCallback <PlaySound>(OnPacketPlaySound); client.AddCallback <PlayerTakeDamage>(OnPacketPlayerTakeDamage); client.AddCallback <PlayerAddHealth>(OnPacketPlayerAddHealth); client.AddCallback <PlayerActivateForce>(OnPacketPlayerActivateForce); client.AddCallback <PlayerRefreshAmmo>(OnPacketPlayerRefreshAmmo); client.AddCallback <PlayerRefreshWeaponUpgrades>(OnPacketPlayerRefreshWeaponUpgrades); client.AddCallback <PlayerWarpToPosition>(OnPacketPlayerWarpToPosition); client.AddCallback <PlayerSetDizzyTime>(OnPacketPlayerSetDizzyTime); client.AddCallback <PlayerSetModifier>(OnPacketPlayerSetModifier); client.AddCallback <PlayerSetLaps>(OnPacketPlayerSetLaps); client.AddCallback <PlayerSetStats>(OnPacketPlayerSetStats); client.AddCallback <PlayerSetInvulnerability>(OnPacketPlayerSetInvulnerability); client.AddCallback <PlayerSetControllable>(OnPacketPlayerSetControllable); client.AddCallback <AdvanceTileAnimation>(OnPacketAdvanceTileAnimation); client.AddCallback <RevertTileAnimation>(OnPacketRevertTileAnimation); client.AddCallback <SetTrigger>(OnPacketSetTrigger); // Wait 3 frames and then inform server that loading is complete isStillLoading = 3; }
/// <summary> /// Player was requested to load a new level /// </summary> private void OnPacketLoadLevel(ref LoadLevel p) { int i = p.LevelName.IndexOf('/'); if (i == -1) { return; } string serverName = p.ServerName; string episodeName = p.LevelName.Substring(0, i); string levelName = p.LevelName.Substring(i + 1); byte playerIndex = p.AssignedPlayerIndex; MultiplayerLevelType levelType = p.LevelType; Await.NextAfterUpdate().OnCompleted(() => { LevelInitialization levelInit = new LevelInitialization(episodeName, levelName, GameDifficulty.Multiplayer); Scene.Current.Dispose(); Scene.SwitchTo(new MultiplayerLevelHandler(this, client, levelInit, levelType, playerIndex)); GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect(); GC.WaitForPendingFinalizers(); GCSettings.LatencyMode = GCLatencyMode.LowLatency; ControlScheme.IsSuspended = false; UpdateRichPresence(levelInit, serverName); }); }
public void ChangeLevelFromPlaylist(int startIndex) { if (activePlaylist == null) { return; } if (activePlaylistRandom && activePlaylist.Count > 2) { for (int i = 0; i < 3; i++) { int randomIdx = MathF.Rnd.Next(activePlaylist.Count); if (randomIdx == activePlaylistIndex) { continue; } activePlaylistIndex = randomIdx; MultiplayerLevelType levelType = activePlaylist[activePlaylistIndex].LevelType; if (ChangeLevel(activePlaylist[activePlaylistIndex].LevelName, levelType, true)) { int goalCount = activePlaylist[activePlaylistIndex].GoalCount; if (goalCount > 0) { switch (levelType) { case MultiplayerLevelType.Battle: case MultiplayerLevelType.TeamBattle: battleTotalKills = goalCount; break; case MultiplayerLevelType.Race: raceTotalLaps = goalCount; break; case MultiplayerLevelType.TreasureHunt: treasureHuntTotalGems = goalCount; break; } } byte playerHealth = activePlaylist[activePlaylistIndex].PlayerHealth; if (playerHealth > 0) { this.playerHealth = playerHealth; } return; } } } for (int i = 0; i < activePlaylist.Count; i++) { activePlaylistIndex = (startIndex + i) % activePlaylist.Count; MultiplayerLevelType levelType = activePlaylist[activePlaylistIndex].LevelType; if (ChangeLevel(activePlaylist[activePlaylistIndex].LevelName, levelType, true)) { int goalCount = activePlaylist[activePlaylistIndex].GoalCount; if (goalCount > 0) { switch (levelType) { case MultiplayerLevelType.Battle: case MultiplayerLevelType.TeamBattle: battleTotalKills = goalCount; break; case MultiplayerLevelType.Race: raceTotalLaps = goalCount; break; case MultiplayerLevelType.TreasureHunt: treasureHuntTotalGems = goalCount; break; } } byte playerHealth = activePlaylist[activePlaylistIndex].PlayerHealth; if (playerHealth > 0) { this.playerHealth = playerHealth; } break; } } }
public bool ChangeLevel(string levelName, MultiplayerLevelType levelType, bool fromPlaylist = false) { if (!fromPlaylist && activePlaylist != null) { activePlaylist = null; activePlaylistIndex = 0; Log.Write(LogType.Info, "Level was changed by administrator. Playlist mode was turned off."); } string path = Path.Combine(DualityApp.DataDirectory, "Episodes", levelName + ".level"); if (!File.Exists(path)) { return(false); } // This lock will pause main game loop until level is loaded lock (sync) { currentLevel = levelName; currentLevelType = levelType; serverState = ServerState.LevelLoading; levelStartTime = 0; countdown = 600f; countdownNotify = int.MaxValue; raceLastPosition = 1; int idx = currentLevel.IndexOf('/'); if (idx == -1) { levelHandler = new LevelHandler(this, "unknown", currentLevel); } else { levelHandler = new LevelHandler(this, currentLevel.Substring(0, idx), currentLevel.Substring(idx + 1)); } Scene.SwitchTo(levelHandler); // Reset active players and send command to change level to all players foreach (var player in players) { player.Value.State = PlayerState.NotReady; player.Value.ProxyActor = null; player.Value.CurrentLap = 0; player.Value.CurrentLapTime = 0; player.Value.RacePosition = 0; player.Value.StatsDeaths = 0; player.Value.StatsKills = 0; player.Value.StatsHits = 0; } playerConnections.Clear(); // Preload some metadata ContentResolver.Current.PreloadAsync("Interactive/PlayerJazz"); ContentResolver.Current.PreloadAsync("Interactive/PlayerSpaz"); ContentResolver.Current.PreloadAsync("Interactive/PlayerLori"); GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect(); GC.WaitForPendingFinalizers(); // Level is loaded on server, send request to players to load the level too foreach (var player in players) { Send(new LoadLevel { ServerName = serverName, LevelName = currentLevel, LevelType = currentLevelType, AssignedPlayerIndex = player.Value.Index }, 64, player.Key, NetDeliveryMethod.ReliableOrdered, PacketChannels.Main); } serverState = ServerState.LevelReady; } return(true); }
public bool LoadServerConfig(string path) { if (string.IsNullOrEmpty(path) || !File.Exists(path)) { return(false); } Log.Write(LogType.Info, "Loading server configuration \"" + path + "\"..."); Log.PushIndent(); try { ServerConfigJson json; using (Stream s = FileOp.Open(path, FileAccessMode.Read)) { json = ContentResolver.Current.ParseJson <ServerConfigJson>(s); } if (!string.IsNullOrEmpty(json.ServerName)) { this.serverName = json.ServerName; Log.Write(LogType.Verbose, "Server name was set to \"" + this.serverName + "\"."); } if (json.MinPlayers > 0) { this.minPlayers = json.MinPlayers; Log.Write(LogType.Verbose, "Min. number of players was set to " + this.minPlayers + "."); } if (json.MaxPlayers > 0) { if (server == null) { this.maxPlayers = json.MaxPlayers; Log.Write(LogType.Verbose, "Max. number of players was set to " + this.maxPlayers + "."); } else { Log.Write(LogType.Error, "Cannot set max. number of players of running server."); } } if (json.Port > 0) { if (server == null) { this.port = json.Port; Log.Write(LogType.Verbose, "Server port was set to " + this.port + "."); } else { Log.Write(LogType.Error, "Cannot set server port of running server."); } } if (json.Playlist != null && json.Playlist.Count > 0) { List <PlaylistItem> playlist = new List <PlaylistItem>(); for (int i = 0; i < json.Playlist.Count; i++) { string levelName = json.Playlist[i].LevelName; if (string.IsNullOrEmpty(levelName)) { continue; } MultiplayerLevelType levelType = json.Playlist[i].LevelType; int goalCount; switch (levelType) { case MultiplayerLevelType.Battle: case MultiplayerLevelType.TeamBattle: goalCount = json.Playlist[i].TotalKills; break; case MultiplayerLevelType.Race: goalCount = json.Playlist[i].TotalLaps; break; case MultiplayerLevelType.TreasureHunt: goalCount = json.Playlist[i].TotalGems; break; default: { Log.Write(LogType.Warning, "Level type " + levelType + " is not supported yet. Skipping."); continue; } } playlist.Add(new PlaylistItem { LevelName = levelName, LevelType = levelType, GoalCount = goalCount, PlayerHealth = json.Playlist[i].PlayerHealth }); } activePlaylist = playlist; activePlaylistRandom = json.PlaylistRandom; Log.Write(LogType.Info, "Loaded playlist with " + playlist.Count + " levels"); if (server != null) { ChangeLevelFromPlaylist(0); } } Log.PopIndent(); return(true); } catch (Exception ex) { Log.Write(LogType.Error, "Cannot parse server configuration: " + ex); Log.PopIndent(); return(false); } }
public bool ChangeLevel(string levelName, MultiplayerLevelType levelType) { string path = Path.Combine(DualityApp.DataDirectory, "Episodes", levelName + ".level"); if (!File.Exists(path)) { return(false); } IFileSystem levelPackage = new CompressedContent(path); lock (sync) { currentLevel = levelName; currentLevelType = levelType; // Load new level using (Stream s = levelPackage.OpenFile(".res", FileAccessMode.Read)) { // ToDo: Cache parser JsonParser json = new JsonParser(); LevelHandler.LevelConfigJson config = json.Parse <LevelHandler.LevelConfigJson>(s); if (config.Version.LayerFormat > LevelHandler.LayerFormatVersion || config.Version.EventSet > LevelHandler.EventSetVersion) { throw new NotSupportedException("Version not supported"); } currentLevelFriendlyName = BitmapFont.StripFormatting(config.Description.Name); Log.Write(LogType.Info, "Loading level \"" + currentLevelFriendlyName + "\" (" + currentLevelType + ")..."); Point2 tileMapSize; using (Stream s2 = levelPackage.OpenFile("Sprite.layer", FileAccessMode.Read)) using (BinaryReader r = new BinaryReader(s2)) { tileMapSize.X = r.ReadInt32(); tileMapSize.Y = r.ReadInt32(); } levelBounds = new Rect(tileMapSize * /*tileMap.Tileset.TileSize*/ 32); collisions = new DynamicTreeBroadPhase <ICollisionable>(); // Read events eventMap = new ServerEventMap(tileMapSize); if (levelPackage.FileExists("Events.layer")) { using (Stream s2 = levelPackage.OpenFile("Events.layer", FileAccessMode.Read)) { eventMap.ReadEvents(s2, config.Version.LayerFormat); } } } // Send request to change level to all players foreach (KeyValuePair <NetConnection, Player> pair in players) { pair.Value.State = PlayerState.NotReady; } playerConnections.Clear(); foreach (KeyValuePair <NetConnection, Player> pair in players) { Send(new LoadLevel { LevelName = currentLevel, LevelType = currentLevelType, AssignedPlayerIndex = pair.Value.Index }, 64, pair.Key, NetDeliveryMethod.ReliableUnordered, PacketChannels.Main); } } return(true); }