public void ServerRead(IReadMessage incMsg, Client c) { if (!c.HasPermission(Networking.ClientPermissions.ManageSettings)) { return; } NetFlags flags = (NetFlags)incMsg.ReadByte(); bool changed = false; if (flags.HasFlag(NetFlags.Name)) { string serverName = incMsg.ReadString(); if (ServerName != serverName) { changed = true; } ServerName = serverName; } if (flags.HasFlag(NetFlags.Message)) { string serverMessageText = incMsg.ReadString(); if (ServerMessageText != serverMessageText) { changed = true; } ServerMessageText = serverMessageText; } if (flags.HasFlag(NetFlags.Properties)) { changed |= ReadExtraCargo(incMsg); UInt32 count = incMsg.ReadUInt32(); for (int i = 0; i < count; i++) { UInt32 key = incMsg.ReadUInt32(); if (netProperties.ContainsKey(key)) { object prevValue = netProperties[key].Value; netProperties[key].Read(incMsg); if (!netProperties[key].PropEquals(prevValue, netProperties[key])) { GameServer.Log(GameServer.ClientLogName(c) + " changed " + netProperties[key].Name + " to " + netProperties[key].Value.ToString(), ServerLog.MessageType.ServerMessage); } changed = true; } else { UInt32 size = incMsg.ReadVariableUInt32(); incMsg.BitPosition += (int)(8 * size); } } bool changedMonsterSettings = incMsg.ReadBoolean(); incMsg.ReadPadBits(); changed |= changedMonsterSettings; if (changedMonsterSettings) { ReadMonsterEnabled(incMsg); } changed |= BanList.ServerAdminRead(incMsg, c); changed |= Whitelist.ServerAdminRead(incMsg, c); } if (flags.HasFlag(NetFlags.Misc)) { int orBits = incMsg.ReadRangedInteger(0, (int)Barotrauma.MissionType.All) & (int)Barotrauma.MissionType.All; int andBits = incMsg.ReadRangedInteger(0, (int)Barotrauma.MissionType.All) & (int)Barotrauma.MissionType.All; GameMain.NetLobbyScreen.MissionType = (Barotrauma.MissionType)(((int)GameMain.NetLobbyScreen.MissionType | orBits) & andBits); int traitorSetting = (int)TraitorsEnabled + incMsg.ReadByte() - 1; if (traitorSetting < 0) { traitorSetting = 2; } if (traitorSetting > 2) { traitorSetting = 0; } TraitorsEnabled = (YesNoMaybe)traitorSetting; int botCount = BotCount + incMsg.ReadByte() - 1; if (botCount < 0) { botCount = MaxBotCount; } if (botCount > MaxBotCount) { botCount = 0; } BotCount = botCount; int botSpawnMode = (int)BotSpawnMode + incMsg.ReadByte() - 1; if (botSpawnMode < 0) { botSpawnMode = 1; } if (botSpawnMode > 1) { botSpawnMode = 0; } BotSpawnMode = (BotSpawnMode)botSpawnMode; float levelDifficulty = incMsg.ReadSingle(); if (levelDifficulty >= 0.0f) { SelectedLevelDifficulty = levelDifficulty; } UseRespawnShuttle = incMsg.ReadBoolean(); bool changedAutoRestart = incMsg.ReadBoolean(); bool autoRestart = incMsg.ReadBoolean(); if (changedAutoRestart) { AutoRestart = autoRestart; } changed |= true; } if (flags.HasFlag(NetFlags.LevelSeed)) { GameMain.NetLobbyScreen.LevelSeed = incMsg.ReadString(); changed |= true; } if (changed) { if (KarmaPreset == "custom") { GameMain.NetworkMember?.KarmaManager?.SaveCustomPreset(); GameMain.NetworkMember?.KarmaManager?.Save(); } SaveSettings(); GameMain.NetLobbyScreen.LastUpdateID++; } }
public void ServerRead(NetIncomingMessage incMsg, Client c) { if (!c.HasPermission(Networking.ClientPermissions.ManageSettings)) { return; } NetFlags flags = (NetFlags)incMsg.ReadByte(); bool changed = false; if (flags.HasFlag(NetFlags.Name)) { string serverName = incMsg.ReadString(); if (ServerName != serverName) { changed = true; } ServerName = serverName; } if (flags.HasFlag(NetFlags.Message)) { string serverMessageText = incMsg.ReadString(); if (ServerMessageText != serverMessageText) { changed = true; } ServerMessageText = serverMessageText; } if (flags.HasFlag(NetFlags.Properties)) { changed |= ReadExtraCargo(incMsg); UInt32 count = incMsg.ReadUInt32(); for (int i = 0; i < count; i++) { UInt32 key = incMsg.ReadUInt32(); if (netProperties.ContainsKey(key)) { object prevValue = netProperties[key].Value; netProperties[key].Read(incMsg); if (!netProperties[key].PropEquals(prevValue, netProperties[key])) { GameServer.Log(c.Name + " changed " + netProperties[key].Name + " to " + netProperties[key].Value.ToString(), ServerLog.MessageType.ServerMessage); } changed = true; } else { UInt32 size = incMsg.ReadVariableUInt32(); incMsg.Position += 8 * size; } } bool changedMonsterSettings = incMsg.ReadBoolean(); incMsg.ReadPadBits(); changed |= changedMonsterSettings; if (changedMonsterSettings) { ReadMonsterEnabled(incMsg); } changed |= BanList.ServerAdminRead(incMsg, c); changed |= Whitelist.ServerAdminRead(incMsg, c); } if (flags.HasFlag(NetFlags.Misc)) { int missionType = GameMain.NetLobbyScreen.MissionTypeIndex + incMsg.ReadByte() - 1; while (missionType < 0) { missionType += Enum.GetValues(typeof(MissionType)).Length; } while (missionType >= Enum.GetValues(typeof(MissionType)).Length) { missionType -= Enum.GetValues(typeof(MissionType)).Length; } GameMain.NetLobbyScreen.MissionTypeIndex = missionType; int traitorSetting = (int)TraitorsEnabled + incMsg.ReadByte() - 1; if (traitorSetting < 0) { traitorSetting = 2; } if (traitorSetting > 2) { traitorSetting = 0; } TraitorsEnabled = (YesNoMaybe)traitorSetting; int botCount = BotCount + incMsg.ReadByte() - 1; if (botCount < 0) { botCount = MaxBotCount; } if (botCount > MaxBotCount) { botCount = 0; } BotCount = botCount; int botSpawnMode = (int)BotSpawnMode + incMsg.ReadByte() - 1; if (botSpawnMode < 0) { botSpawnMode = 1; } if (botSpawnMode > 1) { botSpawnMode = 0; } BotSpawnMode = (BotSpawnMode)botSpawnMode; float levelDifficulty = incMsg.ReadFloat(); if (levelDifficulty >= 0.0f) { SelectedLevelDifficulty = levelDifficulty; } UseRespawnShuttle = incMsg.ReadBoolean(); bool changedAutoRestart = incMsg.ReadBoolean(); bool autoRestart = incMsg.ReadBoolean(); if (changedAutoRestart) { AutoRestart = autoRestart; } changed |= true; } if (flags.HasFlag(NetFlags.LevelSeed)) { GameMain.NetLobbyScreen.LevelSeed = incMsg.ReadString(); changed |= true; } if (changed) { GameMain.NetLobbyScreen.LastUpdateID++; } }
public void SaveClientPermissions() { //delete old client permission file if (File.Exists("Data/clientpermissions.txt")) { File.Delete("Data/clientpermissions.txt"); } GameServer.Log("Saving client permissions", ServerLog.MessageType.ServerMessage); XDocument doc = new XDocument(new XElement("ClientPermissions")); foreach (SavedClientPermission clientPermission in ClientPermissions) { var matchingPreset = PermissionPreset.List.Find(p => p.MatchesPermissions(clientPermission.Permissions, clientPermission.PermittedCommands)); if (matchingPreset != null && matchingPreset.Name == "None") { continue; } XElement clientElement = new XElement("Client", new XAttribute("name", clientPermission.Name)); if (clientPermission.SteamID > 0) { clientElement.Add(new XAttribute("steamid", clientPermission.SteamID)); } else { clientElement.Add(new XAttribute("endpoint", clientPermission.EndPoint)); } if (matchingPreset == null) { clientElement.Add(new XAttribute("permissions", clientPermission.Permissions.ToString())); if (clientPermission.Permissions.HasFlag(Networking.ClientPermissions.ConsoleCommands)) { foreach (DebugConsole.Command command in clientPermission.PermittedCommands) { clientElement.Add(new XElement("command", new XAttribute("name", command.names[0]))); } } } else { clientElement.Add(new XAttribute("preset", matchingPreset.Name)); } doc.Root.Add(clientElement); } try { System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings(); settings.Indent = true; settings.NewLineOnAttributes = true; using (var writer = XmlWriter.Create(ClientPermissionsFile, settings)) { doc.SaveSafe(writer); } } catch (Exception e) { DebugConsole.ThrowError("Saving client permissions to " + ClientPermissionsFile + " failed", e); } }
private void UpdateReturning(float deltaTime) { //if (shuttleReturnTimer == maxTransportTime && // networkMember.Character != null && // networkMember.Character.Submarine == respawnShuttle) //{ // networkMember.AddChatMessage("The shuttle will automatically return back to the outpost. Please leave the shuttle immediately.", ChatMessageType.Server); //} shuttleReturnTimer -= deltaTime; updateReturnTimer += deltaTime; if (updateReturnTimer > 1.0f) { updateReturnTimer = 0.0f; respawnShuttle.PhysicsBody.FarseerBody.IgnoreCollisionWith(Level.Loaded.ShaftBody); shuttleSteering.SetDestinationLevelStart(); foreach (Door door in shuttleDoors) { if (door.IsOpen) { door.SetState(false, false, true); } } var shuttleGaps = Gap.GapList.FindAll(g => g.Submarine == respawnShuttle && g.ConnectedWall != null); shuttleGaps.ForEach(g => g.Remove()); var dockingPorts = Item.ItemList.FindAll(i => i.Submarine == respawnShuttle && i.GetComponent <DockingPort>() != null); dockingPorts.ForEach(d => d.GetComponent <DockingPort>().Undock()); var server = networkMember as GameServer; if (server == null) { return; } //shuttle has returned if the path has been traversed or the shuttle is close enough to the exit if (!CoroutineManager.IsCoroutineRunning("forcepos")) { if (shuttleSteering.SteeringPath != null && shuttleSteering.SteeringPath.Finished || (respawnShuttle.WorldPosition.Y + respawnShuttle.Borders.Y > Level.Loaded.StartPosition.Y - Level.ShaftHeight && Math.Abs(Level.Loaded.StartPosition.X - respawnShuttle.WorldPosition.X) < 1000.0f)) { CoroutineManager.StopCoroutines("forcepos"); CoroutineManager.StartCoroutine( ForceShuttleToPos(new Vector2(Level.Loaded.StartPosition.X, Level.Loaded.Size.Y + 1000.0f), 100.0f), "forcepos"); } } if (respawnShuttle.WorldPosition.Y > Level.Loaded.Size.Y || shuttleReturnTimer <= 0.0f) { CoroutineManager.StopCoroutines("forcepos"); ResetShuttle(); state = State.Waiting; GameServer.Log("The respawn shuttle has left.", ServerLog.MessageType.Spawning); server.CreateEntityEvent(this); respawnTimer = respawnInterval; CountdownStarted = false; } } }
public void RespawnCharacters() { var server = networkMember as GameServer; if (server == null) { return; } var clients = GetClientsToRespawn(); foreach (Client c in clients) { //all characters are in Team 1 in game modes/missions with only one team. //if at some point we add a game mode with multiple teams where respawning is possible, this needs to be reworked c.TeamID = 1; if (c.characterInfo == null) { c.characterInfo = new CharacterInfo(Character.HumanConfigFile, c.name); } } List <CharacterInfo> characterInfos = clients.Select(c => c.characterInfo).ToList(); if (server.Character != null && server.Character.IsDead) { characterInfos.Add(server.CharacterInfo); } server.AssignJobs(clients, server.Character != null && server.Character.IsDead); foreach (Client c in clients) { c.characterInfo.Job = new Job(c.assignedJob); } //the spawnpoints where the characters will spawn var shuttleSpawnPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, respawnShuttle); //the spawnpoints where they would spawn if they were spawned inside the main sub //(in order to give them appropriate ID card tags) var mainSubSpawnPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub); ItemPrefab divingSuitPrefab = ItemPrefab.list.Find(ip => ip.Name == "Diving Suit") as ItemPrefab; ItemPrefab oxyPrefab = ItemPrefab.list.Find(ip => ip.Name == "Oxygen Tank") as ItemPrefab; ItemPrefab scooterPrefab = ItemPrefab.list.Find(ip => ip.Name == "Underwater Scooter") as ItemPrefab; ItemPrefab batteryPrefab = ItemPrefab.list.Find(ip => ip.Name == "Battery Cell") as ItemPrefab; var cargoSp = WayPoint.WayPointList.Find(wp => wp.Submarine == respawnShuttle && wp.SpawnType == SpawnType.Cargo); for (int i = 0; i < characterInfos.Count; i++) { bool myCharacter = false; #if CLIENT myCharacter = i >= clients.Count; #endif var character = Character.Create(characterInfos[i], shuttleSpawnPoints[i].WorldPosition, !myCharacter, false); character.TeamID = 1; #if CLIENT if (myCharacter) { server.Character = character; Character.Controlled = character; GameMain.LightManager.LosEnabled = true; GameServer.Log(string.Format("Respawning {0} (host) as {1}", character.Name, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning); } else { #endif clients[i].Character = character; GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", clients[i].name, clients[i].Connection?.RemoteEndPoint?.Address, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning); #if CLIENT } #endif Vector2 pos = cargoSp == null ? character.Position : cargoSp.Position; if (divingSuitPrefab != null && oxyPrefab != null) { var divingSuit = new Item(divingSuitPrefab, pos, respawnShuttle); Entity.Spawner.CreateNetworkEvent(divingSuit, false); var oxyTank = new Item(oxyPrefab, pos, respawnShuttle); Entity.Spawner.CreateNetworkEvent(oxyTank, false); divingSuit.Combine(oxyTank); } if (scooterPrefab != null && batteryPrefab != null) { var scooter = new Item(scooterPrefab, pos, respawnShuttle); Entity.Spawner.CreateNetworkEvent(scooter, false); var battery = new Item(batteryPrefab, pos, respawnShuttle); Entity.Spawner.CreateNetworkEvent(battery, false); scooter.Combine(battery); } //give the character the items they would've gotten if they had spawned in the main sub character.GiveJobItems(mainSubSpawnPoints[i]); //add the ID card tags they should've gotten when spawning in the shuttle foreach (Item item in character.Inventory.Items) { if (item == null || item.Prefab.Name != "ID Card") { continue; } foreach (string s in shuttleSpawnPoints[i].IdCardTags) { item.AddTag(s); } } #if CLIENT GameMain.GameSession.CrewManager.characters.Add(character); #endif } }
private void RemoveFromWhiteList(WhiteListedPlayer wlp) { GameServer.Log("Removing " + wlp.Name + " from whitelist", ServerLog.MessageType.ServerMessage); whitelistedPlayers.Remove(wlp); }
private void ReadConnectionInitializationStep(PendingClient pendingClient, IReadMessage inc) { if (netServer == null) { return; } pendingClient.TimeOut = NetworkConnection.TimeoutThreshold; ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte(); //DebugConsole.NewMessage(initializationStep+" "+pendingClient.InitializationStep); if (pendingClient.InitializationStep != initializationStep) { return; } pendingClient.UpdateTime = Timing.TotalTime + Timing.Step; switch (initializationStep) { case ConnectionInitialization.SteamTicketAndVersion: string name = Client.SanitizeName(inc.ReadString()); UInt64 steamId = inc.ReadUInt64(); UInt16 ticketLength = inc.ReadUInt16(); inc.BitPosition += ticketLength * 8; //skip ticket, owner handles steam authentication if (!Client.IsValidName(name, serverSettings)) { RemovePendingClient(pendingClient, DisconnectReason.InvalidName.ToString() + "/ The name \"" + name + "\" is invalid"); return; } string version = inc.ReadString(); bool isCompatibleVersion = NetworkMember.IsCompatible(version, GameMain.Version.ToString()) ?? false; if (!isCompatibleVersion) { RemovePendingClient(pendingClient, $"DisconnectMessage.InvalidVersion~[version]={GameMain.Version.ToString()}~[clientversion]={version}"); GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", ServerLog.MessageType.Error); DebugConsole.NewMessage(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red); return; } int contentPackageCount = (int)inc.ReadVariableUInt32(); List <ClientContentPackage> contentPackages = new List <ClientContentPackage>(); for (int i = 0; i < contentPackageCount; i++) { string packageName = inc.ReadString(); string packageHash = inc.ReadString(); contentPackages.Add(new ClientContentPackage(packageName, packageHash)); } List <ContentPackage> missingPackages = new List <ContentPackage>(); foreach (ContentPackage contentPackage in GameMain.SelectedPackages) { if (!contentPackage.HasMultiplayerIncompatibleContent) { continue; } bool packageFound = false; for (int i = 0; i < (int)contentPackageCount; i++) { if (contentPackages[i].Name == contentPackage.Name && contentPackages[i].Hash == contentPackage.MD5hash.Hash) { packageFound = true; break; } } if (!packageFound) { missingPackages.Add(contentPackage); } } if (missingPackages.Count == 1) { RemovePendingClient(pendingClient, $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}"); GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error); return; } else if (missingPackages.Count > 1) { List <string> packageStrs = new List <string>(); missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp))); RemovePendingClient(pendingClient, $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}"); GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error); return; } if (!pendingClient.AuthSessionStarted) { pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password: ConnectionInitialization.Success; pendingClient.Name = name; pendingClient.AuthSessionStarted = true; } break; case ConnectionInitialization.Password: int pwLength = inc.ReadByte(); byte[] incPassword = inc.ReadBytes(pwLength); if (pendingClient.PasswordSalt == null) { DebugConsole.ThrowError("Received password message from client without salt"); return; } if (serverSettings.IsPasswordCorrect(incPassword, pendingClient.PasswordSalt.Value)) { pendingClient.InitializationStep = ConnectionInitialization.Success; } else { pendingClient.Retries++; if (pendingClient.Retries >= 3) { string banMsg = "Failed to enter correct password too many times"; serverSettings.BanList.BanPlayer(pendingClient.Name, pendingClient.SteamID, banMsg, null); RemovePendingClient(pendingClient, DisconnectReason.Banned.ToString() + "/ " + banMsg); return; } } pendingClient.UpdateTime = Timing.TotalTime; break; } }
partial void RespawnCharactersProjSpecific() { var server = networkMember as GameServer; if (server == null) { return; } var respawnSub = respawnShuttle ?? Submarine.MainSub; var clients = GetClientsToRespawn(); foreach (Client c in clients) { //all characters are in Team 1 in game modes/missions with only one team. //if at some point we add a game mode with multiple teams where respawning is possible, this needs to be reworked c.TeamID = Character.TeamType.Team1; if (c.CharacterInfo == null) { c.CharacterInfo = new CharacterInfo(Character.HumanConfigFile, c.Name); } } List <CharacterInfo> characterInfos = clients.Select(c => c.CharacterInfo).ToList(); var botsToSpawn = GetBotsToRespawn(); characterInfos.AddRange(botsToSpawn); server.AssignJobs(clients); foreach (Client c in clients) { c.CharacterInfo.Job = new Job(c.AssignedJob); } //the spawnpoints where the characters will spawn var shuttleSpawnPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, respawnSub); //the spawnpoints where they would spawn if they were spawned inside the main sub //(in order to give them appropriate ID card tags) var mainSubSpawnPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub); ItemPrefab divingSuitPrefab = MapEntityPrefab.Find(null, "divingsuit") as ItemPrefab; ItemPrefab oxyPrefab = MapEntityPrefab.Find(null, "oxygentank") as ItemPrefab; ItemPrefab scooterPrefab = MapEntityPrefab.Find(null, "underwaterscooter") as ItemPrefab; ItemPrefab batteryPrefab = MapEntityPrefab.Find(null, "batterycell") as ItemPrefab; var cargoSp = WayPoint.WayPointList.Find(wp => wp.Submarine == respawnSub && wp.SpawnType == SpawnType.Cargo); for (int i = 0; i < characterInfos.Count; i++) { bool bot = i >= clients.Count; var character = Character.Create(characterInfos[i], shuttleSpawnPoints[i].WorldPosition, characterInfos[i].Name, !bot, bot); character.TeamID = Character.TeamType.Team1; if (bot) { GameServer.Log(string.Format("Respawning bot {0} as {1}", character.Info.Name, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning); } else { //tell the respawning client they're no longer a traitor if (GameMain.Server.TraitorManager != null && clients[i].Character != null) { if (GameMain.Server.TraitorManager.TraitorList.Any(t => t.Character == clients[i].Character)) { GameMain.Server.SendDirectChatMessage(TextManager.Get("traitorrespawnmessage"), clients[i], ChatMessageType.MessageBox); } } clients[i].Character = character; character.OwnerClientIP = clients[i].Connection.RemoteEndPoint.Address.ToString(); character.OwnerClientName = clients[i].Name; GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", clients[i].Name, clients[i].Connection?.RemoteEndPoint?.Address, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning); } if (divingSuitPrefab != null && oxyPrefab != null && respawnShuttle != null) { Vector2 pos = cargoSp == null ? character.Position : cargoSp.Position; if (divingSuitPrefab != null && oxyPrefab != null) { var divingSuit = new Item(divingSuitPrefab, pos, respawnSub); Spawner.CreateNetworkEvent(divingSuit, false); respawnItems.Add(divingSuit); var oxyTank = new Item(oxyPrefab, pos, respawnSub); Spawner.CreateNetworkEvent(oxyTank, false); divingSuit.Combine(oxyTank); respawnItems.Add(oxyTank); } if (scooterPrefab != null && batteryPrefab != null) { var scooter = new Item(scooterPrefab, pos, respawnSub); Spawner.CreateNetworkEvent(scooter, false); var battery = new Item(batteryPrefab, pos, respawnSub); Spawner.CreateNetworkEvent(battery, false); scooter.Combine(battery); respawnItems.Add(scooter); respawnItems.Add(battery); } } //give the character the items they would've gotten if they had spawned in the main sub character.GiveJobItems(mainSubSpawnPoints[i]); //add the ID card tags they should've gotten when spawning in the shuttle foreach (Item item in character.Inventory.Items) { if (item == null || item.Prefab.Identifier != "idcard") { continue; } foreach (string s in shuttleSpawnPoints[i].IdCardTags) { item.AddTag(s); } if (!string.IsNullOrWhiteSpace(shuttleSpawnPoints[i].IdCardDesc)) { item.Description = shuttleSpawnPoints[i].IdCardDesc; } } } }
public void Update(List<Client> clients) { foreach (BufferedEvent bufferedEvent in bufferedEvents) { if (bufferedEvent.Character == null || bufferedEvent.Character.IsDead) { bufferedEvent.IsProcessed = true; continue; } //delay reading the events until the inputs for the corresponding frame have been processed //UNLESS the character is unconscious, in which case we'll read the messages immediately (because further inputs will be ignored) //atm the "give in" command is the only thing unconscious characters can do, other types of events are ignored if (!bufferedEvent.Character.IsIncapacitated && NetIdUtils.IdMoreRecent(bufferedEvent.CharacterStateID, bufferedEvent.Character.LastProcessedID)) { continue; } try { ReadEvent(bufferedEvent.Data, bufferedEvent.TargetEntity, bufferedEvent.Sender); } catch (Exception e) { string entityName = bufferedEvent.TargetEntity == null ? "null" : bufferedEvent.TargetEntity.ToString(); if (GameSettings.VerboseLogging) { string errorMsg = "Failed to read server event for entity \"" + entityName + "\"!"; GameServer.Log(errorMsg + "\n" + e.StackTrace, ServerLog.MessageType.Error); DebugConsole.ThrowError(errorMsg, e); } GameAnalyticsManager.AddErrorEventOnce("ServerEntityEventManager.Read:ReadFailed" + entityName, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Failed to read server event for entity \"" + entityName + "\"!\n" + e.StackTrace); } bufferedEvent.IsProcessed = true; } var inGameClients = clients.FindAll(c => c.InGame && !c.NeedsMidRoundSync); if (inGameClients.Count > 0) { lastSentToAnyone = inGameClients[0].LastRecvEntityEventID; lastSentToAll = inGameClients[0].LastRecvEntityEventID; if (server.OwnerConnection != null) { var owner = clients.Find(c => c.Connection == server.OwnerConnection); if (owner != null) { lastSentToAll = owner.LastRecvEntityEventID; } } inGameClients.ForEach(c => { if (NetIdUtils.IdMoreRecent(lastSentToAll, c.LastRecvEntityEventID)) { lastSentToAll = c.LastRecvEntityEventID; } if (NetIdUtils.IdMoreRecent(c.LastRecvEntityEventID, lastSentToAnyone)) { lastSentToAnyone = c.LastRecvEntityEventID; } }); lastSentToAnyoneTime = events.Find(e => e.ID == lastSentToAnyone)?.CreateTime ?? Timing.TotalTime; if (Timing.TotalTime - lastWarningTime > 5.0 && Timing.TotalTime - lastSentToAnyoneTime > 10.0 && Timing.TotalTime > GameMain.GameSession.RoundStartTime + NetConfig.RoundStartSyncDuration) { lastWarningTime = Timing.TotalTime; GameServer.Log("WARNING: ServerEntityEventManager is lagging behind! Last sent id: " + lastSentToAnyone.ToString() + ", latest create id: " + ID.ToString(), ServerLog.MessageType.ServerMessage); events.ForEach(e => e.ResetCreateTime()); //TODO: reset clients if this happens, maybe do it if a majority are behind rather than all of them? } clients.Where(c => c.NeedsMidRoundSync).ForEach(c => { if (NetIdUtils.IdMoreRecent(lastSentToAll, c.FirstNewEventID)) lastSentToAll = (ushort)(c.FirstNewEventID - 1); }); ServerEntityEvent firstEventToResend = events.Find(e => e.ID == (ushort)(lastSentToAll + 1)); if (firstEventToResend != null && Timing.TotalTime > GameMain.GameSession.RoundStartTime + NetConfig.RoundStartSyncDuration && ((lastSentToAnyoneTime - firstEventToResend.CreateTime) > NetConfig.OldReceivedEventKickTime || (Timing.TotalTime - firstEventToResend.CreateTime) > NetConfig.OldEventKickTime)) { // This event is 10 seconds older than the last one we've successfully sent, // kick everyone that hasn't received it yet, this is way too old // UNLESS the event was created when the client was still midround syncing, // in which case we'll wait until the timeout runs out before kicking the client List<Client> toKick = inGameClients.FindAll(c => NetIdUtils.IdMoreRecent((UInt16)(lastSentToAll + 1), c.LastRecvEntityEventID) && (firstEventToResend.CreateTime > c.MidRoundSyncTimeOut || lastSentToAnyoneTime > c.MidRoundSyncTimeOut || Timing.TotalTime > c.MidRoundSyncTimeOut + 10.0)); toKick.ForEach(c => { <<<<<<< HEAD DebugConsole.NewMessage(c.Name + " was kicked due to excessive desync (expected old event " + (c.LastRecvEntityEventID + 1).ToString() + ")", Color.Red); GameServer.Log("Disconnecting client " + GameServer.ClientLogName(c) + " due to excessive desync (expected old event " ======= DebugConsole.NewMessage(c.Name + " was kicked because they were expecting a very old network event (" + (c.LastRecvEntityEventID + 1).ToString() + ")", Color.Red); GameServer.Log(GameServer.ClientLogName(c) + " was kicked because they were expecting a very old network event (" >>>>>>> upstream/master + (c.LastRecvEntityEventID + 1).ToString() + " (created " + (Timing.TotalTime - firstEventToResend.CreateTime).ToString("0.##") + " s ago, " + (lastSentToAnyoneTime - firstEventToResend.CreateTime).ToString("0.##") + " s older than last event sent to anyone)" + " Events queued: " + events.Count + ", last sent to all: " + lastSentToAll, ServerLog.MessageType.Error); server.DisconnectClient(c, "", DisconnectReason.ExcessiveDesyncOldEvent + "/ServerMessage.ExcessiveDesyncOldEvent"); }
protected void ReadConnectionInitializationStep(PendingClient pendingClient, IReadMessage inc) { pendingClient.TimeOut = NetworkConnection.TimeoutThreshold; ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte(); if (pendingClient.InitializationStep != initializationStep) { return; } pendingClient.UpdateTime = Timing.TotalTime + Timing.Step; switch (initializationStep) { case ConnectionInitialization.SteamTicketAndVersion: string name = Client.SanitizeName(inc.ReadString()); int ownerKey = inc.ReadInt32(); UInt64 steamId = inc.ReadUInt64(); UInt16 ticketLength = inc.ReadUInt16(); byte[] ticketBytes = inc.ReadBytes(ticketLength); if (!Client.IsValidName(name, serverSettings)) { RemovePendingClient(pendingClient, DisconnectReason.InvalidName, ""); return; } string version = inc.ReadString(); bool isCompatibleVersion = NetworkMember.IsCompatible(version, GameMain.Version.ToString()) ?? false; if (!isCompatibleVersion) { RemovePendingClient(pendingClient, DisconnectReason.InvalidVersion, $"DisconnectMessage.InvalidVersion~[version]={GameMain.Version}~[clientversion]={version}"); GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", ServerLog.MessageType.Error); DebugConsole.NewMessage(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red); return; } string language = inc.ReadString(); pendingClient.Connection.Language = language; Client nameTaken = GameMain.Server.ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), name.ToLower())); if (nameTaken != null) { RemovePendingClient(pendingClient, DisconnectReason.NameTaken, ""); GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (name too similar to the name of the client \"" + nameTaken.Name + "\").", ServerLog.MessageType.Error); return; } if (!pendingClient.AuthSessionStarted) { ProcessAuthTicket(name, ownerKey, steamId, pendingClient, ticketBytes); } break; case ConnectionInitialization.Password: int pwLength = inc.ReadByte(); byte[] incPassword = inc.ReadBytes(pwLength); if (pendingClient.PasswordSalt == null) { DebugConsole.ThrowError("Received password message from client without salt"); return; } if (serverSettings.IsPasswordCorrect(incPassword, pendingClient.PasswordSalt.Value)) { pendingClient.InitializationStep = ConnectionInitialization.ContentPackageOrder; } else { pendingClient.Retries++; if (serverSettings.BanAfterWrongPassword && pendingClient.Retries > serverSettings.MaxPasswordRetriesBeforeBan) { string banMsg = "Failed to enter correct password too many times"; BanPendingClient(pendingClient, banMsg, null); RemovePendingClient(pendingClient, DisconnectReason.Banned, banMsg); return; } } pendingClient.UpdateTime = Timing.TotalTime; break; case ConnectionInitialization.ContentPackageOrder: pendingClient.InitializationStep = ConnectionInitialization.Success; pendingClient.UpdateTime = Timing.TotalTime; break; } }