public bool ReadExtraCargo(IReadMessage msg) { bool changed = false; UInt32 count = msg.ReadUInt32(); if (ExtraCargo == null || count != ExtraCargo.Count) { changed = true; } Dictionary <ItemPrefab, int> extraCargo = new Dictionary <ItemPrefab, int>(); for (int i = 0; i < count; i++) { string prefabIdentifier = msg.ReadString(); byte amount = msg.ReadByte(); var itemPrefab = MapEntityPrefab.Find(null, prefabIdentifier, showErrorMessages: false) as ItemPrefab; if (itemPrefab != null && amount > 0) { if (changed || !ExtraCargo.ContainsKey(itemPrefab) || ExtraCargo[itemPrefab] != amount) { changed = true; } extraCargo.Add(itemPrefab, amount); } } if (changed) { ExtraCargo = extraCargo; } return(changed); }
public void ServerRead(IReadMessage inc, Client sender) { UInt16 actionId = inc.ReadUInt16(); byte selectedOption = inc.ReadByte(); foreach (Event ev in activeEvents) { if (!(ev is ScriptedEvent scriptedEvent)) { continue; } var actions = FindActions(scriptedEvent); foreach (EventAction action in actions.Select(a => a.Item2)) { if (!(action is ConversationAction convAction) || convAction.Identifier != actionId) { continue; } if (!convAction.TargetClients.Contains(sender)) { #if DEBUG || UNSTABLE DebugConsole.ThrowError($"Client \"{sender.Name}\" tried to respond to a ConversationAction that was not targeted to them."); #endif continue; } convAction.SelectedOption = selectedOption; return; } } }
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime) { byte sectionCount = msg.ReadByte(); bool invalidMessage = false; if (type != ServerNetObject.ENTITY_EVENT && type != ServerNetObject.ENTITY_EVENT_INITIAL) { DebugConsole.NewMessage($"Error while reading a network event for the structure \"{Name} ({ID})\". Invalid event type ({type}).", Color.Red); return; } else if (sectionCount != Sections.Length) { invalidMessage = true; string errorMsg = $"Error while reading a network event for the structure \"{Name} ({ID})\". Section count does not match (server: {sectionCount} client: {Sections.Length})"; DebugConsole.NewMessage(errorMsg, Color.Red); GameAnalyticsManager.AddErrorEventOnce("Structure.ClientRead:SectionCountMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); } for (int i = 0; i < sectionCount; i++) { float damage = msg.ReadRangedSingle(0.0f, 1.0f, 8) * MaxHealth; if (!invalidMessage && i < Sections.Length) { SetDamage(i, damage); } } }
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime) { bool isGlobalUpdate = msg.ReadBoolean(); if (isGlobalUpdate) { foreach (LevelWall levelWall in ExtraWalls) { if (levelWall.Body.BodyType == BodyType.Static) { continue; } Vector2 bodyPos = new Vector2( msg.ReadSingle(), msg.ReadSingle()); levelWall.MoveState = msg.ReadRangedSingle(0.0f, MathHelper.TwoPi, 16); DestructibleLevelWall destructibleWall = levelWall as DestructibleLevelWall; if (Vector2.DistanceSquared(bodyPos, levelWall.Body.Position) > 0.5f && (destructibleWall == null || !destructibleWall.Destroyed)) { levelWall.Body.SetTransformIgnoreContacts(ref bodyPos, levelWall.Body.Rotation); } } } else { int index = msg.ReadUInt16(); byte damageByte = msg.ReadByte(); if (index < ExtraWalls.Count && ExtraWalls[index] is DestructibleLevelWall destructibleWall) { destructibleWall.SetDamage(destructibleWall.MaxHealth * damageByte / 255.0f); } } }
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime) { FabricatorState newState = (FabricatorState)msg.ReadByte(); float newTimeUntilReady = msg.ReadSingle(); int itemIndex = msg.ReadRangedInteger(-1, fabricationRecipes.Count - 1); UInt16 userID = msg.ReadUInt16(); Character user = Entity.FindEntityByID(userID) as Character; State = newState; timeUntilReady = newTimeUntilReady; if (newState == FabricatorState.Stopped || itemIndex == -1) { CancelFabricating(); } else if (newState == FabricatorState.Active || newState == FabricatorState.Paused) { //if already fabricating the selected item, return if (fabricatedItem != null && fabricationRecipes.IndexOf(fabricatedItem) == itemIndex) { return; } if (itemIndex < 0 || itemIndex >= fabricationRecipes.Count) { return; } SelectItem(user, fabricationRecipes[itemIndex]); StartFabricating(fabricationRecipes[itemIndex], user); } }
public void ClientRead(IReadMessage inc) { AllowSubVoting = inc.ReadBoolean(); if (allowSubVoting) { UpdateVoteTexts(null, VoteType.Sub); int votableCount = inc.ReadByte(); for (int i = 0; i < votableCount; i++) { int votes = inc.ReadByte(); string subName = inc.ReadString(); List <Submarine> serversubs = new List <Submarine>(); foreach (GUIComponent item in GameMain.NetLobbyScreen?.SubList?.Content?.Children) { if (item.UserData != null && item.UserData is Submarine) { serversubs.Add(item.UserData as Submarine); } } Submarine sub = serversubs.FirstOrDefault(sm => sm.Name == subName); SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes); } } AllowModeVoting = inc.ReadBoolean(); if (allowModeVoting) { UpdateVoteTexts(null, VoteType.Mode); int votableCount = inc.ReadByte(); for (int i = 0; i < votableCount; i++) { int votes = inc.ReadByte(); string modeIdentifier = inc.ReadString(); GameModePreset mode = GameModePreset.List.Find(m => m.Identifier == modeIdentifier); SetVoteText(GameMain.NetLobbyScreen.ModeList, mode, votes); } } AllowEndVoting = inc.ReadBoolean(); if (AllowEndVoting) { GameMain.NetworkMember.EndVoteCount = inc.ReadByte(); GameMain.NetworkMember.EndVoteMax = inc.ReadByte(); } AllowVoteKick = inc.ReadBoolean(); GameMain.NetworkMember.ConnectedClients.ForEach(c => c.SetVote(VoteType.StartRound, false)); byte readyClientCount = inc.ReadByte(); for (int i = 0; i < readyClientCount; i++) { byte clientID = inc.ReadByte(); var matchingClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == clientID); matchingClient?.SetVote(VoteType.StartRound, true); } UpdateVoteTexts(GameMain.NetworkMember.ConnectedClients, VoteType.StartRound); inc.ReadPadBits(); }
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime) { Health = msg.ReadRangedSingle(0, MaxHealth, 8); int startOffset = msg.ReadRangedInteger(-1, MaximumVines); if (startOffset > -1) { int vineCount = msg.ReadRangedInteger(0, VineChunkSize); List <VineTile> tiles = new List <VineTile>(); for (int i = 0; i < vineCount; i++) { VineTileType vineType = (VineTileType)msg.ReadRangedInteger(0b0000, 0b1111); int flowerConfig = msg.ReadRangedInteger(0, 0xFFF); int leafConfig = msg.ReadRangedInteger(0, 0xFFF); sbyte posX = (sbyte)msg.ReadByte(), posY = (sbyte)msg.ReadByte(); Vector2 pos = new Vector2(posX * VineTile.Size, posY * VineTile.Size); tiles.Add(new VineTile(this, pos, vineType, FoliageConfig.Deserialize(flowerConfig), FoliageConfig.Deserialize(leafConfig))); } // is this even needed?? lock (mutex) { for (var i = 0; i < vineCount; i++) { int index = i + startOffset; if (index >= Vines.Count) { Vines.Add(tiles[i]); continue; } VineTile oldVine = Vines[index]; VineTile newVine = tiles[i]; newVine.GrowthStep = oldVine.GrowthStep; Vines[index] = newVine; } } } UpdateBranchHealth(); ResetPlanterSize(); }
public static CharacterInfo ClientRead(string speciesName, IReadMessage inc) { ushort infoID = inc.ReadUInt16(); string newName = inc.ReadString(); int gender = inc.ReadByte(); int race = inc.ReadByte(); int headSpriteID = inc.ReadByte(); int hairIndex = inc.ReadByte(); int beardIndex = inc.ReadByte(); int moustacheIndex = inc.ReadByte(); int faceAttachmentIndex = inc.ReadByte(); string ragdollFile = inc.ReadString(); string jobIdentifier = inc.ReadString(); JobPrefab jobPrefab = null; Dictionary <string, float> skillLevels = new Dictionary <string, float>(); if (!string.IsNullOrEmpty(jobIdentifier)) { jobPrefab = JobPrefab.Get(jobIdentifier); byte skillCount = inc.ReadByte(); for (int i = 0; i < skillCount; i++) { string skillIdentifier = inc.ReadString(); float skillLevel = inc.ReadSingle(); skillLevels.Add(skillIdentifier, skillLevel); } } // TODO: animations CharacterInfo ch = new CharacterInfo(speciesName, newName, jobPrefab, ragdollFile) { ID = infoID, }; ch.RecreateHead(headSpriteID, (Race)race, (Gender)gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex); if (ch.Job != null) { foreach (KeyValuePair <string, float> skill in skillLevels) { Skill matchingSkill = ch.Job.Skills.Find(s => s.Identifier == skill.Key); if (matchingSkill == null) { ch.Job.Skills.Add(new Skill(skill.Key, skill.Value)); continue; } matchingSkill.Level = skill.Value; } ch.Job.Skills.RemoveAll(s => !skillLevels.ContainsKey(s.Identifier)); } return(ch); }
public override void ClientReadInitial(IReadMessage msg) { base.ClientReadInitial(msg); ushort targetItemCount = msg.ReadUInt16(); for (int i = 0; i < targetItemCount; i++) { var item = Item.ReadSpawnData(msg); items.Add(item); } byte characterCount = msg.ReadByte(); for (int i = 0; i < characterCount; i++) { Character character = Character.ReadSpawnData(msg); characters.Add(character); if (msg.ReadBoolean()) { requireKill.Add(character); } if (msg.ReadBoolean()) { requireRescue.Add(character); #if CLIENT GameMain.GameSession.CrewManager.AddCharacterToCrewList(character); #endif } ushort itemCount = msg.ReadUInt16(); for (int j = 0; j < itemCount; j++) { Item.ReadSpawnData(msg); } if (character.Submarine != null && character.AIController is EnemyAIController enemyAi) { enemyAi.UnattackableSubmarines.Add(character.Submarine); enemyAi.UnattackableSubmarines.Add(Submarine.MainSub); foreach (Submarine sub in Submarine.MainSub.DockedTo) { enemyAi.UnattackableSubmarines.Add(sub); } } } if (characters.Contains(null)) { throw new System.Exception("Error in AbandonedOutpostMission.ClientReadInitial: character list contains null (mission: " + Prefab.Identifier + ")"); } if (characters.Count != characterCount) { throw new System.Exception("Error in AbandonedOutpostMission.ClientReadInitial: character count does not match the server count (" + characters + " != " + characters.Count + "mission: " + Prefab.Identifier + ")"); } }
private void ClientReadScanTargetStatus(IReadMessage msg) { scanTargets.Clear(); byte targetsToScan = msg.ReadByte(); for (int i = 0; i < targetsToScan; i++) { ushort id = msg.ReadUInt16(); bool scanned = msg.ReadBoolean(); Entity entity = Entity.FindEntityByID(id); scanTargets.Add(entity as WayPoint, scanned); } }
public override void ClientReadInitial(IReadMessage msg) { base.ClientReadInitial(msg); bool usedExistingItem = msg.ReadBoolean(); if (usedExistingItem) { ushort id = msg.ReadUInt16(); item = Entity.FindEntityByID(id) as Item; if (item == null) { throw new System.Exception("Error in SalvageMission.ClientReadInitial: failed to find item " + id + " (mission: " + Prefab.Identifier + ")"); } } else { item = Item.ReadSpawnData(msg); if (item == null) { throw new System.Exception("Error in SalvageMission.ClientReadInitial: spawned item was null (mission: " + Prefab.Identifier + ")"); } } int executedEffectCount = msg.ReadByte(); for (int i = 0; i < executedEffectCount; i++) { int index1 = msg.ReadByte(); int index2 = msg.ReadByte(); var selectedEffect = statusEffects[index1][index2]; item.ApplyStatusEffect(selectedEffect, selectedEffect.type, deltaTime: 1.0f, worldPosition: item.Position); } if (item.body != null) { item.body.FarseerBody.BodyType = BodyType.Kinematic; } }
public virtual bool Read(IReadMessage msg, bool discardData = false) { if (!CanReceive) { throw new Exception("Called Read on a VoipQueue not set up for receiving"); } UInt16 incLatestBufferID = msg.ReadUInt16(); if ((firstRead || NetIdUtils.IdMoreRecent(incLatestBufferID, LatestBufferID)) && !discardData) { ForceLocal = msg.ReadBoolean(); msg.ReadPadBits(); firstRead = false; lock (buffers) { for (int i = 0; i < BUFFER_COUNT; i++) { bufferLengths[i] = msg.ReadByte(); buffers[i] = msg.ReadBytes(bufferLengths[i]); } } newestBufferInd = BUFFER_COUNT - 1; LatestBufferID = incLatestBufferID; LastReadTime = DateTime.Now; return(true); } else { msg.ReadBoolean(); msg.ReadPadBits(); for (int i = 0; i < BUFFER_COUNT; i++) { byte len = msg.ReadByte(); msg.BitPosition += len * 8; } return(false); } }
public static void ServerRead(IReadMessage inc, Client client) { ReadyCheckState state = (ReadyCheckState)inc.ReadByte(); ReadyCheck? readyCheck = GameMain.GameSession?.CrewManager?.ActiveReadyCheck; switch (state) { case ReadyCheckState.Start when readyCheck == null: StartReadyCheck(client.Name, client); break; case ReadyCheckState.Update when readyCheck != null: ReadyStatus status = (ReadyStatus)inc.ReadByte(); if (!readyCheck.Clients.ContainsKey(client.ID)) { return; } readyCheck.Clients[client.ID] = status; readyCheck.UpdateReadyCheck(client.ID, status); break; } }
public TraitorMissionResult(IReadMessage inc) { MissionIdentifier = inc.ReadString(); EndMessage = inc.ReadString(); Success = inc.ReadBoolean(); byte characterCount = inc.ReadByte(); for (int i = 0; i < characterCount; i++) { UInt16 characterID = inc.ReadUInt16(); var character = Entity.FindEntityByID(characterID) as Character; if (character != null) { Characters.Add(character); } } }
public override void ClientReadInitial(IReadMessage msg) { byte monsterCount = msg.ReadByte(); for (int i = 0; i < monsterCount; i++) { monsters.Add(Character.ReadSpawnData(msg)); } if (monsters.Contains(null)) { throw new System.Exception("Error in MonsterMission.ClientReadInitial: monster list contains null (mission: " + Prefab.Identifier + ")"); } if (monsters.Count != monsterCount) { throw new System.Exception("Error in MonsterMission.ClientReadInitial: monster count does not match the server count (" + monsterCount + " != " + monsters.Count + "mission: " + Prefab.Identifier + ")"); } InitializeMonsters(monsters); }
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime) { byte sectionCount = msg.ReadByte(); if (sectionCount != Sections.Length) { string errorMsg = $"Error while reading a network event for the structure \"{Name}\". Section count does not match (server: {sectionCount} client: {Sections.Length})"; DebugConsole.NewMessage(errorMsg, Color.Red); GameAnalyticsManager.AddErrorEventOnce("Structure.ClientRead:SectionCountMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); } for (int i = 0; i < sectionCount; i++) { float damage = msg.ReadRangedSingle(0.0f, 1.0f, 8) * Health; if (i < Sections.Length) { SetDamage(i, damage); } } }
public void ClientRead(IReadMessage incMsg) { ServerName = incMsg.ReadString(); ServerMessageText = incMsg.ReadString(); MaxPlayers = incMsg.ReadByte(); HasPassword = incMsg.ReadBoolean(); isPublic = incMsg.ReadBoolean(); incMsg.ReadPadBits(); TickRate = incMsg.ReadRangedInteger(1, 60); GameMain.NetworkMember.TickRate = TickRate; ReadExtraCargo(incMsg); Voting.ClientRead(incMsg); bool isAdmin = incMsg.ReadBoolean(); incMsg.ReadPadBits(); if (isAdmin) { ClientAdminRead(incMsg); } }
public void ClientRead(ServerNetObject type, IReadMessage message, float sendingTime) { bool remove = message.ReadBoolean(); if (remove) { ushort entityId = message.ReadUInt16(); var entity = FindEntityByID(entityId); if (entity != null) { DebugConsole.Log("Received entity removal message for \"" + entity.ToString() + "\"."); entity.Remove(); } else { DebugConsole.Log("Received entity removal message for ID " + entityId + ". Entity with a matching ID not found."); } } else { switch (message.ReadByte()) { case (byte)SpawnableType.Item: Item.ReadSpawnData(message, true); break; case (byte)SpawnableType.Character: Character.ReadSpawnData(message); break; default: DebugConsole.ThrowError("Received invalid entity spawn message (unknown spawnable type)"); break; } } }
public override void ClientReadInitial(IReadMessage msg) { // duplicate code from escortmission, should possibly be combined, though additional loot items might be added so maybe not byte characterCount = msg.ReadByte(); for (int i = 0; i < characterCount; i++) { characters.Add(Character.ReadSpawnData(msg)); ushort itemCount = msg.ReadUInt16(); for (int j = 0; j < itemCount; j++) { Item.ReadSpawnData(msg); } } if (characters.Contains(null)) { throw new System.Exception("Error in PirateMission.ClientReadInitial: character list contains null (mission: " + Prefab.Identifier + ")"); } if (characters.Count != characterCount) { throw new System.Exception("Error in PirateMission.ClientReadInitial: character count does not match the server count (" + characterCount + " != " + characters.Count + "mission: " + Prefab.Identifier + ")"); } }
/// <summary> /// Read the events from the message, ignoring ones we've already received. Returns false if reading the events fails. /// </summary> public bool Read(ServerNetObject type, IReadMessage msg, float sendingTime, List <IServerSerializable> entities) { UInt16 unreceivedEntityEventCount = 0; if (type == ServerNetObject.ENTITY_EVENT_INITIAL) { unreceivedEntityEventCount = msg.ReadUInt16(); firstNewID = msg.ReadUInt16(); if (GameSettings.VerboseLogging) { DebugConsole.NewMessage( "received midround syncing msg, unreceived: " + unreceivedEntityEventCount + ", first new ID: " + firstNewID, Microsoft.Xna.Framework.Color.Yellow); } } else { MidRoundSyncingDone = true; if (firstNewID != null) { if (GameSettings.VerboseLogging) { DebugConsole.NewMessage("midround syncing complete, switching to ID " + (UInt16)(firstNewID - 1), Microsoft.Xna.Framework.Color.Yellow); } lastReceivedID = (UInt16)(firstNewID - 1); firstNewID = null; } } entities.Clear(); UInt16 firstEventID = msg.ReadUInt16(); int eventCount = msg.ReadByte(); for (int i = 0; i < eventCount; i++) { //16 = entity ID, 8 = msg length if (msg.BitPosition + 16 + 8 > msg.LengthBits) { string errorMsg = $"Error while reading a message from the server. Entity event data exceeds the size of the buffer (current position: {msg.BitPosition}, length: {msg.LengthBits})."; errorMsg += "\nPrevious entities:"; for (int j = entities.Count - 1; j >= 0; j--) { errorMsg += "\n" + (entities[j] == null ? "NULL" : entities[j].ToString()); } DebugConsole.ThrowError(errorMsg); return(false); } UInt16 thisEventID = (UInt16)(firstEventID + (UInt16)i); UInt16 entityID = msg.ReadUInt16(); if (entityID == Entity.NullEntityID) { if (GameSettings.VerboseLogging) { DebugConsole.NewMessage("received msg " + thisEventID + " (null entity)", Microsoft.Xna.Framework.Color.Orange); } msg.ReadPadBits(); entities.Add(null); if (thisEventID == (UInt16)(lastReceivedID + 1)) { lastReceivedID++; } continue; } int msgLength = (int)msg.ReadVariableUInt32(); IServerSerializable entity = Entity.FindEntityByID(entityID) as IServerSerializable; entities.Add(entity); //skip the event if we've already received it or if the entity isn't found if (thisEventID != (UInt16)(lastReceivedID + 1) || entity == null) { if (thisEventID != (UInt16)(lastReceivedID + 1)) { if (GameSettings.VerboseLogging) { DebugConsole.NewMessage( "Received msg " + thisEventID + " (waiting for " + (lastReceivedID + 1) + ")", NetIdUtils.IdMoreRecent(thisEventID, (UInt16)(lastReceivedID + 1)) ? GUI.Style.Red : Microsoft.Xna.Framework.Color.Yellow); } } else if (entity == null) { DebugConsole.NewMessage( "Received msg " + thisEventID + ", entity " + entityID + " not found", GUI.Style.Red); GameMain.Client.ReportError(ClientNetError.MISSING_ENTITY, eventID: thisEventID, entityID: entityID); return(false); } msg.BitPosition += msgLength * 8; msg.ReadPadBits(); } else { long msgPosition = msg.BitPosition; if (GameSettings.VerboseLogging) { DebugConsole.NewMessage("received msg " + thisEventID + " (" + entity.ToString() + ")", Microsoft.Xna.Framework.Color.Green); } lastReceivedID++; try { ReadEvent(msg, entity, sendingTime); msg.ReadPadBits(); if (msg.BitPosition != msgPosition + msgLength * 8) { string errorMsg = "Message byte position incorrect after reading an event for the entity \"" + entity.ToString() + "\". Read " + (msg.BitPosition - msgPosition) + " bits, expected message length was " + (msgLength * 8) + " bits."; #if DEBUG DebugConsole.ThrowError(errorMsg); #endif GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:BitPosMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); //TODO: force the BitPosition to correct place? Having some entity in a potentially incorrect state is not as bad as a desync kick //msg.BitPosition = (int)(msgPosition + msgLength * 8); } } catch (Exception e) { string errorMsg = "Failed to read event for entity \"" + entity.ToString() + "\" (" + e.Message + ")! (MidRoundSyncing: " + thisClient.MidRoundSyncing + ")\n" + e.StackTrace.CleanupStackTrace(); errorMsg += "\nPrevious entities:"; for (int j = entities.Count - 2; j >= 0; j--) { errorMsg += "\n" + (entities[j] == null ? "NULL" : entities[j].ToString()); } DebugConsole.ThrowError("Failed to read event for entity \"" + entity.ToString() + "\"!", e); GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:ReadFailed" + entity.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); msg.BitPosition = (int)(msgPosition + msgLength * 8); msg.ReadPadBits(); } } } return(true); }
public static CharacterInfo ClientRead(string speciesName, IReadMessage inc) { ushort infoID = inc.ReadUInt16(); string newName = inc.ReadString(); string originalName = inc.ReadString(); int gender = inc.ReadByte(); int race = inc.ReadByte(); int headSpriteID = inc.ReadByte(); int hairIndex = inc.ReadByte(); int beardIndex = inc.ReadByte(); int moustacheIndex = inc.ReadByte(); int faceAttachmentIndex = inc.ReadByte(); Color skinColor = inc.ReadColorR8G8B8(); Color hairColor = inc.ReadColorR8G8B8(); Color facialHairColor = inc.ReadColorR8G8B8(); string ragdollFile = inc.ReadString(); string jobIdentifier = inc.ReadString(); int variant = inc.ReadByte(); JobPrefab jobPrefab = null; Dictionary <string, float> skillLevels = new Dictionary <string, float>(); if (!string.IsNullOrEmpty(jobIdentifier)) { jobPrefab = JobPrefab.Get(jobIdentifier); byte skillCount = inc.ReadByte(); for (int i = 0; i < skillCount; i++) { string skillIdentifier = inc.ReadString(); float skillLevel = inc.ReadSingle(); skillLevels.Add(skillIdentifier, skillLevel); } } // TODO: animations CharacterInfo ch = new CharacterInfo(speciesName, newName, originalName, jobPrefab, ragdollFile, variant) { ID = infoID, }; ch.RecreateHead(headSpriteID, (Race)race, (Gender)gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex); ch.SkinColor = skinColor; ch.HairColor = hairColor; ch.FacialHairColor = facialHairColor; if (ch.Job != null) { foreach (KeyValuePair <string, float> skill in skillLevels) { Skill matchingSkill = ch.Job.Skills.Find(s => s.Identifier == skill.Key); if (matchingSkill == null) { ch.Job.Skills.Add(new Skill(skill.Key, skill.Value)); continue; } matchingSkill.Level = skill.Value; } ch.Job.Skills.RemoveAll(s => !skillLevels.ContainsKey(s.Identifier)); } byte savedStatValueCount = inc.ReadByte(); for (int i = 0; i < savedStatValueCount; i++) { int statType = inc.ReadByte(); string statIdentifier = inc.ReadString(); float statValue = inc.ReadSingle(); bool removeOnDeath = inc.ReadBoolean(); ch.ChangeSavedStatValue((StatTypes)statType, statValue, statIdentifier, removeOnDeath); } ch.ExperiencePoints = inc.ReadUInt16(); ch.AdditionalTalentPoints = inc.ReadUInt16(); return(ch); }
public static void ClientRead(IReadMessage inc) { ReadyCheckState state = (ReadyCheckState)inc.ReadByte(); CrewManager? crewManager = GameMain.GameSession?.CrewManager; List <Client> otherClients = GameMain.Client.ConnectedClients; if (crewManager == null || otherClients == null) { if (state == ReadyCheckState.Start) { SendState(ReadyStatus.No); } return; } switch (state) { case ReadyCheckState.Start: bool isOwn = false; byte authorId = 0; float duration = inc.ReadSingle(); string author = inc.ReadString(); bool hasAuthor = inc.ReadBoolean(); if (hasAuthor) { authorId = inc.ReadByte(); isOwn = authorId == GameMain.Client.ID; } ushort clientCount = inc.ReadUInt16(); List <byte> clients = new List <byte>(); for (int i = 0; i < clientCount; i++) { clients.Add(inc.ReadByte()); } ReadyCheck rCheck = new ReadyCheck(clients, duration); crewManager.ActiveReadyCheck = rCheck; if (isOwn) { SendState(ReadyStatus.Yes); rCheck.CreateResultsMessage(); } else { rCheck.CreateMessageBox(author); } if (hasAuthor && rCheck.Clients.ContainsKey(authorId)) { rCheck.Clients[authorId] = ReadyStatus.Yes; } break; case ReadyCheckState.Update: float time = inc.ReadSingle(); ReadyStatus newState = (ReadyStatus)inc.ReadByte(); byte targetId = inc.ReadByte(); if (crewManager.ActiveReadyCheck != null) { crewManager.ActiveReadyCheck.time = time; crewManager.ActiveReadyCheck?.UpdateState(targetId, newState); } break; case ReadyCheckState.End: ushort count = inc.ReadUInt16(); for (int i = 0; i < count; i++) { byte id = inc.ReadByte(); ReadyStatus status = (ReadyStatus)inc.ReadByte(); crewManager.ActiveReadyCheck?.UpdateState(id, status); } crewManager.ActiveReadyCheck?.EndReadyCheck(); crewManager.ActiveReadyCheck?.msgBox?.Close(); crewManager.ActiveReadyCheck = null; break; } }
public void Read(IReadMessage msg) { int oldPos = msg.BitPosition; UInt32 size = msg.ReadVariableUInt32(); float x; float y; float z; float w; byte r; byte g; byte b; byte a; int ix; int iy; int width; int height; switch (typeString) { case "float": if (size != 4) { break; } property.SetValue(parentObject, msg.ReadSingle()); return; case "int": if (size != 4) { break; } property.SetValue(parentObject, msg.ReadInt32()); return; case "vector2": if (size != 8) { break; } x = msg.ReadSingle(); y = msg.ReadSingle(); property.SetValue(parentObject, new Vector2(x, y)); return; case "vector3": if (size != 12) { break; } x = msg.ReadSingle(); y = msg.ReadSingle(); z = msg.ReadSingle(); property.SetValue(parentObject, new Vector3(x, y, z)); return; case "vector4": if (size != 16) { break; } x = msg.ReadSingle(); y = msg.ReadSingle(); z = msg.ReadSingle(); w = msg.ReadSingle(); property.SetValue(parentObject, new Vector4(x, y, z, w)); return; case "color": if (size != 4) { break; } r = msg.ReadByte(); g = msg.ReadByte(); b = msg.ReadByte(); a = msg.ReadByte(); property.SetValue(parentObject, new Color(r, g, b, a)); return; case "rectangle": if (size != 16) { break; } ix = msg.ReadInt32(); iy = msg.ReadInt32(); width = msg.ReadInt32(); height = msg.ReadInt32(); property.SetValue(parentObject, new Rectangle(ix, iy, width, height)); return; default: msg.BitPosition = oldPos; //reset position to properly read the string string incVal = msg.ReadString(); property.TrySetValue(parentObject, incVal); return; } //size didn't match: skip this msg.BitPosition += (int)(8 * size); }
//static because we may need to instantiate the campaign if it hasn't been done yet public static void ClientRead(IReadMessage msg) { bool isFirstRound = msg.ReadBoolean(); byte campaignID = msg.ReadByte(); UInt16 updateID = msg.ReadUInt16(); UInt16 saveID = msg.ReadUInt16(); string mapSeed = msg.ReadString(); UInt16 currentLocIndex = msg.ReadUInt16(); UInt16 selectedLocIndex = msg.ReadUInt16(); byte selectedMissionIndex = msg.ReadByte(); bool allowDebugTeleport = msg.ReadBoolean(); float? reputation = null; if (msg.ReadBoolean()) { reputation = msg.ReadSingle(); } Dictionary <string, float> factionReps = new Dictionary <string, float>(); byte factionsCount = msg.ReadByte(); for (int i = 0; i < factionsCount; i++) { factionReps.Add(msg.ReadString(), msg.ReadSingle()); } bool forceMapUI = msg.ReadBoolean(); int money = msg.ReadInt32(); bool purchasedHullRepairs = msg.ReadBoolean(); bool purchasedItemRepairs = msg.ReadBoolean(); bool purchasedLostShuttles = msg.ReadBoolean(); byte missionCount = msg.ReadByte(); List <Pair <string, byte> > availableMissions = new List <Pair <string, byte> >(); for (int i = 0; i < missionCount; i++) { string missionIdentifier = msg.ReadString(); byte connectionIndex = msg.ReadByte(); availableMissions.Add(new Pair <string, byte>(missionIdentifier, connectionIndex)); } UInt16?storeBalance = null; if (msg.ReadBoolean()) { storeBalance = msg.ReadUInt16(); } UInt16 buyCrateItemCount = msg.ReadUInt16(); List <PurchasedItem> buyCrateItems = new List <PurchasedItem>(); for (int i = 0; i < buyCrateItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity); buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity)); } UInt16 purchasedItemCount = msg.ReadUInt16(); List <PurchasedItem> purchasedItems = new List <PurchasedItem>(); for (int i = 0; i < purchasedItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity); purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity)); } UInt16 soldItemCount = msg.ReadUInt16(); List <SoldItem> soldItems = new List <SoldItem>(); for (int i = 0; i < soldItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); UInt16 id = msg.ReadUInt16(); bool removed = msg.ReadBoolean(); byte sellerId = msg.ReadByte(); soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId)); } ushort pendingUpgradeCount = msg.ReadUInt16(); List <PurchasedUpgrade> pendingUpgrades = new List <PurchasedUpgrade>(); for (int i = 0; i < pendingUpgradeCount; i++) { string upgradeIdentifier = msg.ReadString(); UpgradePrefab prefab = UpgradePrefab.Find(upgradeIdentifier); string categoryIdentifier = msg.ReadString(); UpgradeCategory category = UpgradeCategory.Find(categoryIdentifier); int upgradeLevel = msg.ReadByte(); if (prefab == null || category == null) { continue; } pendingUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel)); } bool hasCharacterData = msg.ReadBoolean(); CharacterInfo myCharacterInfo = null; if (hasCharacterData) { myCharacterInfo = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg); } if (!(GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign) || campaignID != campaign.CampaignID) { string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer); GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, mapSeed); campaign = (MultiPlayerCampaign)GameMain.GameSession.GameMode; campaign.CampaignID = campaignID; GameMain.NetLobbyScreen.ToggleCampaignMode(true); } //server has a newer save file if (NetIdUtils.IdMoreRecent(saveID, campaign.PendingSaveID)) { campaign.PendingSaveID = saveID; } if (NetIdUtils.IdMoreRecent(updateID, campaign.lastUpdateID)) { campaign.SuppressStateSending = true; campaign.IsFirstRound = isFirstRound; //we need to have the latest save file to display location/mission/store if (campaign.LastSaveID == saveID) { campaign.ForceMapUI = forceMapUI; UpgradeStore.WaitForServerUpdate = false; campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex); campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex); campaign.Map.SelectMission(selectedMissionIndex); campaign.Map.AllowDebugTeleport = allowDebugTeleport; campaign.CargoManager.SetItemsInBuyCrate(buyCrateItems); campaign.CargoManager.SetPurchasedItems(purchasedItems); campaign.CargoManager.SetSoldItems(soldItems); if (storeBalance.HasValue) { campaign.Map.CurrentLocation.StoreCurrentBalance = storeBalance.Value; } campaign.UpgradeManager.SetPendingUpgrades(pendingUpgrades); campaign.UpgradeManager.PurchasedUpgrades.Clear(); foreach (var(identifier, rep) in factionReps) { Faction faction = campaign.Factions.FirstOrDefault(f => f.Prefab.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase)); if (faction?.Reputation != null) { faction.Reputation.Value = rep; } else { DebugConsole.ThrowError($"Received an update for a faction that doesn't exist \"{identifier}\"."); } } if (reputation.HasValue) { campaign.Map.CurrentLocation.Reputation.Value = reputation.Value; campaign?.CampaignUI?.UpgradeStore?.RefreshAll(); } foreach (var availableMission in availableMissions) { MissionPrefab missionPrefab = MissionPrefab.List.Find(mp => mp.Identifier == availableMission.First); if (missionPrefab == null) { DebugConsole.ThrowError($"Error when receiving campaign data from the server: mission prefab \"{availableMission.First}\" not found."); continue; } if (availableMission.Second < 0 || availableMission.Second >= campaign.Map.CurrentLocation.Connections.Count) { DebugConsole.ThrowError($"Error when receiving campaign data from the server: connection index for mission \"{availableMission.First}\" out of range (index: {availableMission.Second}, current location: {campaign.Map.CurrentLocation.Name}, connections: {campaign.Map.CurrentLocation.Connections.Count})."); continue; } LocationConnection connection = campaign.Map.CurrentLocation.Connections[availableMission.Second]; campaign.Map.CurrentLocation.UnlockMission(missionPrefab, connection); } GameMain.NetLobbyScreen.ToggleCampaignMode(true); } bool shouldRefresh = campaign.Money != money || campaign.PurchasedHullRepairs != purchasedHullRepairs || campaign.PurchasedItemRepairs != purchasedItemRepairs || campaign.PurchasedLostShuttles != purchasedLostShuttles; campaign.Money = money; campaign.PurchasedHullRepairs = purchasedHullRepairs; campaign.PurchasedItemRepairs = purchasedItemRepairs; campaign.PurchasedLostShuttles = purchasedLostShuttles; if (shouldRefresh) { campaign?.CampaignUI?.UpgradeStore?.RefreshAll(); } if (myCharacterInfo != null) { GameMain.Client.CharacterInfo = myCharacterInfo; GameMain.NetLobbyScreen.SetCampaignCharacterInfo(myCharacterInfo); } else { GameMain.NetLobbyScreen.SetCampaignCharacterInfo(null); } campaign.lastUpdateID = updateID; campaign.SuppressStateSending = false; } }
public virtual void ServerRead(ClientNetObject type, IReadMessage msg, Client c) { if (GameMain.Server == null) { return; } switch (type) { case ClientNetObject.CHARACTER_INPUT: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } UInt16 networkUpdateID = msg.ReadUInt16(); byte inputCount = msg.ReadByte(); if (AllowInput) { Enabled = true; } for (int i = 0; i < inputCount; i++) { InputNetFlags newInput = (InputNetFlags)msg.ReadRangedInteger(0, (int)InputNetFlags.MaxVal); UInt16 newAim = 0; UInt16 newInteract = 0; if (newInput != InputNetFlags.None && newInput != InputNetFlags.FacingLeft) { c.KickAFKTimer = 0.0f; } else if (AnimController.Dir < 0.0f != newInput.HasFlag(InputNetFlags.FacingLeft)) { //character changed the direction they're facing c.KickAFKTimer = 0.0f; } newAim = msg.ReadUInt16(); if (newInput.HasFlag(InputNetFlags.Select) || newInput.HasFlag(InputNetFlags.Deselect) || newInput.HasFlag(InputNetFlags.Use) || newInput.HasFlag(InputNetFlags.Health) || newInput.HasFlag(InputNetFlags.Grab)) { newInteract = msg.ReadUInt16(); } if (NetIdUtils.IdMoreRecent((ushort)(networkUpdateID - i), LastNetworkUpdateID) && (i < 60)) { if ((i > 0 && memInput[i - 1].intAim != newAim)) { c.KickAFKTimer = 0.0f; } NetInputMem newMem = new NetInputMem { states = newInput, intAim = newAim, interact = newInteract, networkUpdateID = (ushort)(networkUpdateID - i) }; memInput.Insert(i, newMem); LastInputTime = Timing.TotalTime; } } if (NetIdUtils.IdMoreRecent(networkUpdateID, LastNetworkUpdateID)) { LastNetworkUpdateID = networkUpdateID; } else if (NetIdUtils.Difference(networkUpdateID, LastNetworkUpdateID) > 500) { #if DEBUG || UNSTABLE DebugConsole.AddWarning($"Large disrepancy between a client character's network update ID server-side and client-side (client: {networkUpdateID}, server: {LastNetworkUpdateID}). Resetting the ID."); #endif LastNetworkUpdateID = networkUpdateID; } if (memInput.Count > 60) { //deleting inputs from the queue here means the server is way behind and data needs to be dropped //we'll make the server drop down to 30 inputs for good measure memInput.RemoveRange(30, memInput.Count - 30); } break; case ClientNetObject.ENTITY_STATE: int eventType = msg.ReadRangedInteger(0, 3); switch (eventType) { case 0: Inventory.ServerRead(type, msg, c); break; case 1: bool doingCPR = msg.ReadBoolean(); if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } AnimController.Anim = doingCPR ? AnimController.Animation.CPR : AnimController.Animation.None; break; case 2: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } if (IsIncapacitated) { var causeOfDeath = CharacterHealth.GetCauseOfDeath(); Kill(causeOfDeath.First, causeOfDeath.Second); } break; } break; } msg.ReadPadBits(); }
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, "The name \"" + name + "\" is invalid"); 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.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> clientContentPackages = new List <ClientContentPackage>(); for (int i = 0; i < contentPackageCount; i++) { string packageName = inc.ReadString(); string packageHash = inc.ReadString(); clientContentPackages.Add(new ClientContentPackage(packageName, packageHash)); } //check if the client is missing any of our packages List <ContentPackage> missingPackages = new List <ContentPackage>(); foreach (ContentPackage serverContentPackage in GameMain.SelectedPackages) { if (!serverContentPackage.HasMultiplayerIncompatibleContent) { continue; } bool packageFound = clientContentPackages.Any(cp => cp.Name == serverContentPackage.Name && cp.Hash == serverContentPackage.MD5hash.Hash); if (!packageFound) { missingPackages.Add(serverContentPackage); } } //check if the client is using packages we don't have List <ClientContentPackage> redundantPackages = new List <ClientContentPackage>(); foreach (ClientContentPackage clientContentPackage in clientContentPackages) { bool packageFound = GameMain.SelectedPackages.Any(cp => cp.Name == clientContentPackage.Name && cp.MD5hash.Hash == clientContentPackage.Hash); if (!packageFound) { redundantPackages.Add(clientContentPackage); } } if (missingPackages.Count == 1) { RemovePendingClient(pendingClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}"); GameServer.Log(name + " (" + pendingClient.SteamID + ") 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, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}"); GameServer.Log(name + " (" + pendingClient.SteamID + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error); return; } if (redundantPackages.Count == 1) { RemovePendingClient(pendingClient, DisconnectReason.IncompatibleContentPackage, $"DisconnectMessage.IncompatibleContentPackage~[incompatiblecontentpackage]={GetPackageStr(redundantPackages[0])}"); GameServer.Log(name + " (" + pendingClient.SteamID + ") couldn't join the server (using an incompatible content package " + GetPackageStr(redundantPackages[0]) + ")", ServerLog.MessageType.Error); return; } if (redundantPackages.Count > 1) { List <string> packageStrs = new List <string>(); redundantPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp))); RemovePendingClient(pendingClient, DisconnectReason.IncompatibleContentPackage, $"DisconnectMessage.IncompatibleContentPackages~[incompatiblecontentpackages]={string.Join(", ", packageStrs)}"); GameServer.Log(name + " (" + pendingClient.SteamID + ") couldn't join the server (using incompatible 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, banMsg); return; } } pendingClient.UpdateTime = Timing.TotalTime; break; } }
public void ServerRead(IReadMessage msg, Client sender) { UInt16 currentLocIndex = msg.ReadUInt16(); UInt16 selectedLocIndex = msg.ReadUInt16(); byte selectedMissionCount = msg.ReadByte(); List <int> selectedMissionIndices = new List <int>(); for (int i = 0; i < selectedMissionCount; i++) { selectedMissionIndices.Add(msg.ReadByte()); } bool purchasedHullRepairs = msg.ReadBoolean(); bool purchasedItemRepairs = msg.ReadBoolean(); bool purchasedLostShuttles = msg.ReadBoolean(); UInt16 buyCrateItemCount = msg.ReadUInt16(); List <PurchasedItem> buyCrateItems = new List <PurchasedItem>(); for (int i = 0; i < buyCrateItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity); buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity)); } UInt16 purchasedItemCount = msg.ReadUInt16(); List <PurchasedItem> purchasedItems = new List <PurchasedItem>(); for (int i = 0; i < purchasedItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity); purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity)); } UInt16 soldItemCount = msg.ReadUInt16(); List <SoldItem> soldItems = new List <SoldItem>(); for (int i = 0; i < soldItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); UInt16 id = msg.ReadUInt16(); bool removed = msg.ReadBoolean(); byte sellerId = msg.ReadByte(); soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId)); } ushort purchasedUpgradeCount = msg.ReadUInt16(); List <PurchasedUpgrade> purchasedUpgrades = new List <PurchasedUpgrade>(); for (int i = 0; i < purchasedUpgradeCount; i++) { string upgradeIdentifier = msg.ReadString(); UpgradePrefab prefab = UpgradePrefab.Find(upgradeIdentifier); string categoryIdentifier = msg.ReadString(); UpgradeCategory category = UpgradeCategory.Find(categoryIdentifier); int upgradeLevel = msg.ReadByte(); if (category == null || prefab == null) { continue; } purchasedUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel)); } ushort purchasedItemSwapCount = msg.ReadUInt16(); List <PurchasedItemSwap> purchasedItemSwaps = new List <PurchasedItemSwap>(); for (int i = 0; i < purchasedItemSwapCount; i++) { UInt16 itemToRemoveID = msg.ReadUInt16(); Item itemToRemove = Entity.FindEntityByID(itemToRemoveID) as Item; string itemToInstallIdentifier = msg.ReadString(); ItemPrefab itemToInstall = string.IsNullOrEmpty(itemToInstallIdentifier) ? null : ItemPrefab.Find(string.Empty, itemToInstallIdentifier); if (itemToRemove == null) { continue; } purchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall)); } if (!AllowedToManageCampaign(sender)) { DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign"); return; } Location location = Map.CurrentLocation; int hullRepairCost = location?.GetAdjustedMechanicalCost(HullRepairCost) ?? HullRepairCost; int itemRepairCost = location?.GetAdjustedMechanicalCost(ItemRepairCost) ?? ItemRepairCost; int shuttleRetrieveCost = location?.GetAdjustedMechanicalCost(ShuttleReplaceCost) ?? ShuttleReplaceCost; if (purchasedHullRepairs != this.PurchasedHullRepairs) { if (purchasedHullRepairs && Money >= hullRepairCost) { this.PurchasedHullRepairs = true; Money -= hullRepairCost; } else if (!purchasedHullRepairs) { this.PurchasedHullRepairs = false; Money += hullRepairCost; } } if (purchasedItemRepairs != this.PurchasedItemRepairs) { if (purchasedItemRepairs && Money >= itemRepairCost) { this.PurchasedItemRepairs = true; Money -= itemRepairCost; } else if (!purchasedItemRepairs) { this.PurchasedItemRepairs = false; Money += itemRepairCost; } } if (purchasedLostShuttles != this.PurchasedLostShuttles) { if (GameMain.GameSession?.SubmarineInfo != null && GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied) { GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("ReplaceShuttleDockingPortOccupied"), sender, ChatMessageType.MessageBox); } else if (purchasedLostShuttles && Money >= shuttleRetrieveCost) { this.PurchasedLostShuttles = true; Money -= shuttleRetrieveCost; } else if (!purchasedItemRepairs) { this.PurchasedLostShuttles = false; Money += shuttleRetrieveCost; } } if (currentLocIndex < Map.Locations.Count && Map.AllowDebugTeleport) { Map.SetLocation(currentLocIndex); } Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex); if (Map.SelectedLocation == null) { Map.SelectRandomLocation(preferUndiscovered: true); } if (Map.SelectedConnection != null) { Map.SelectMission(selectedMissionIndices); } CheckTooManyMissions(Map.CurrentLocation, sender); List <PurchasedItem> currentBuyCrateItems = new List <PurchasedItem>(CargoManager.ItemsInBuyCrate); currentBuyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, -i.Quantity)); buyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, i.Quantity)); CargoManager.SellBackPurchasedItems(new List <PurchasedItem>(CargoManager.PurchasedItems)); CargoManager.PurchaseItems(purchasedItems, false); // for some reason CargoManager.SoldItem is never cleared by the server, I've added a check to SellItems that ignores all // sold items that are removed so they should be discarded on the next message CargoManager.BuyBackSoldItems(new List <SoldItem>(CargoManager.SoldItems)); CargoManager.SellItems(soldItems); foreach (var(prefab, category, _) in purchasedUpgrades) { UpgradeManager.PurchaseUpgrade(prefab, category); // unstable logging int price = prefab.Price.GetBuyprice(UpgradeManager.GetUpgradeLevel(prefab, category), Map?.CurrentLocation); int level = UpgradeManager.GetUpgradeLevel(prefab, category); GameServer.Log($"SERVER: Purchased level {level} {category.Identifier}.{prefab.Identifier} for {price}", ServerLog.MessageType.ServerMessage); } foreach (var purchasedItemSwap in purchasedItemSwaps) { if (purchasedItemSwap.ItemToInstall == null) { UpgradeManager.CancelItemSwap(purchasedItemSwap.ItemToRemove); } else { UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall); } } foreach (Item item in Item.ItemList) { if (item.PendingItemSwap != null && !purchasedItemSwaps.Any(it => it.ItemToRemove == item)) { UpgradeManager.CancelItemSwap(item); item.PendingItemSwap = null; } } }
/// <summary> /// Read the events from the message, ignoring ones we've already received /// </summary> public void Read(IReadMessage msg, Client sender = null) { UInt16 firstEventID = msg.ReadUInt16(); int eventCount = msg.ReadByte(); for (int i = 0; i < eventCount; i++) { UInt16 thisEventID = (UInt16)(firstEventID + (UInt16)i); UInt16 entityID = msg.ReadUInt16(); if (entityID == Entity.NullEntityID) { msg.ReadPadBits(); if (thisEventID == (UInt16)(sender.LastSentEntityEventID + 1)) { sender.LastSentEntityEventID++; } continue; } int msgLength = (int)msg.ReadVariableUInt32(); IClientSerializable entity = Entity.FindEntityByID(entityID) as IClientSerializable; //skip the event if we've already received it if (thisEventID != (UInt16)(sender.LastSentEntityEventID + 1)) { if (GameSettings.VerboseLogging) { DebugConsole.NewMessage("Received msg " + thisEventID + ", expecting " + sender.LastSentEntityEventID, Color.Red); } msg.BitPosition += msgLength * 8; } else if (entity == null) { //entity not found -> consider the even read and skip over it //(can happen, for example, when a client uses a medical item repeatedly //and creates an event for it before receiving the event about it being removed) if (GameSettings.VerboseLogging) { DebugConsole.NewMessage( "Received msg " + thisEventID + ", entity " + entityID + " not found", Microsoft.Xna.Framework.Color.Orange); } sender.LastSentEntityEventID++; msg.BitPosition += msgLength * 8; } else { if (GameSettings.VerboseLogging) { DebugConsole.NewMessage("Received msg " + thisEventID, Microsoft.Xna.Framework.Color.Green); } UInt16 characterStateID = msg.ReadUInt16(); ReadWriteMessage buffer = new ReadWriteMessage(); byte[] temp = msg.ReadBytes(msgLength - 2); buffer.Write(temp, 0, msgLength - 2); buffer.BitPosition = 0; BufferEvent(new BufferedEvent(sender, sender.Character, characterStateID, entity, buffer)); sender.LastSentEntityEventID++; } msg.ReadPadBits(); } }
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c) { List <Item> prevItems = new List <Item>(Items); byte itemCount = msg.ReadByte(); ushort[] newItemIDs = new ushort[itemCount]; for (int i = 0; i < itemCount; i++) { newItemIDs[i] = msg.ReadUInt16(); } if (c == null || c.Character == null) { return; } bool accessible = c.Character.CanAccessInventory(this); if (this is CharacterInventory && accessible) { if (Owner == null || !(Owner is Character)) { accessible = false; } else if (!((CharacterInventory)this).AccessibleWhenAlive && !((Character)Owner).IsDead) { accessible = false; } } if (!accessible) { //create a network event to correct the client's inventory state //otherwise they may have an item in their inventory they shouldn't have been able to pick up, //and receiving an event for that inventory later will cause the item to be dropped CreateNetworkEvent(); for (int i = 0; i < capacity; i++) { if (!(Entity.FindEntityByID(newItemIDs[i]) is Item item)) { continue; } item.PositionUpdateInterval = 0.0f; if (item.ParentInventory != null && item.ParentInventory != this) { item.ParentInventory.CreateNetworkEvent(); } } return; } List <Inventory> prevItemInventories = new List <Inventory>(Items.Select(i => i?.ParentInventory)); for (int i = 0; i < capacity; i++) { Item newItem = newItemIDs[i] == 0 ? null : Entity.FindEntityByID(newItemIDs[i]) as Item; prevItemInventories.Add(newItem?.ParentInventory); if (newItemIDs[i] == 0 || (newItem != Items[i])) { if (Items[i] != null) { Item droppedItem = Items[i]; Entity prevOwner = Owner; droppedItem.Drop(null); var previousInventory = prevOwner switch { Item itemInventory => (itemInventory.FindParentInventory(inventory => inventory is CharacterInventory) as CharacterInventory), Character character => character.Inventory, _ => null }; if (previousInventory != null && previousInventory != c.Character?.Inventory) { GameMain.Server?.KarmaManager.OnItemTakenFromPlayer(previousInventory, c, droppedItem); } if (droppedItem.body != null && prevOwner != null) { droppedItem.body.SetTransform(prevOwner.SimPosition, 0.0f); } } System.Diagnostics.Debug.Assert(Items[i] == null); } } for (int i = 0; i < capacity; i++) { if (newItemIDs[i] > 0) { if (!(Entity.FindEntityByID(newItemIDs[i]) is Item item) || item == Items[i]) { continue; } if (GameMain.Server != null) { var holdable = item.GetComponent <Holdable>(); if (holdable != null && !holdable.CanBeDeattached()) { continue; } if (!prevItems.Contains(item) && !item.CanClientAccess(c)) { #if DEBUG || UNSTABLE DebugConsole.NewMessage($"Client {c.Name} failed to pick up item \"{item}\" (parent inventory: {(item.ParentInventory?.Owner.ToString() ?? "null")}). No access.", Color.Yellow); #endif if (item.body != null && !c.PendingPositionUpdates.Contains(item)) { c.PendingPositionUpdates.Enqueue(item); } item.PositionUpdateInterval = 0.0f; continue; } } TryPutItem(item, i, true, true, c.Character, false); for (int j = 0; j < capacity; j++) { if (Items[j] == item && newItemIDs[j] != item.ID) { Items[j] = null; } } } } CreateNetworkEvent(); foreach (Inventory prevInventory in prevItemInventories.Distinct()) { if (prevInventory != this) { prevInventory?.CreateNetworkEvent(); } } foreach (Item item in Items.Distinct()) { if (item == null) { continue; } if (!prevItems.Contains(item)) { if (Owner == c.Character) { GameServer.Log(GameServer.CharacterLogName(c.Character) + " picked up " + item.Name, ServerLog.MessageType.Inventory); } else { GameServer.Log(GameServer.CharacterLogName(c.Character) + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory); } } } foreach (Item item in prevItems.Distinct()) { if (item == null) { continue; } if (!Items.Contains(item)) { if (Owner == c.Character) { GameServer.Log(GameServer.CharacterLogName(c.Character) + " dropped " + item.Name, ServerLog.MessageType.Inventory); } else { GameServer.Log(GameServer.CharacterLogName(c.Character) + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory); } } } }
public void ClientRead(IReadMessage inc) { AllowSubVoting = inc.ReadBoolean(); if (allowSubVoting) { UpdateVoteTexts(null, VoteType.Sub); int votableCount = inc.ReadByte(); for (int i = 0; i < votableCount; i++) { int votes = inc.ReadByte(); string subName = inc.ReadString(); List <SubmarineInfo> serversubs = new List <SubmarineInfo>(); foreach (GUIComponent item in GameMain.NetLobbyScreen?.SubList?.Content?.Children) { if (item.UserData != null && item.UserData is SubmarineInfo) { serversubs.Add(item.UserData as SubmarineInfo); } } SubmarineInfo sub = serversubs.FirstOrDefault(s => s.Name == subName); SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes); } } AllowModeVoting = inc.ReadBoolean(); if (allowModeVoting) { UpdateVoteTexts(null, VoteType.Mode); int votableCount = inc.ReadByte(); for (int i = 0; i < votableCount; i++) { int votes = inc.ReadByte(); string modeIdentifier = inc.ReadString(); GameModePreset mode = GameModePreset.List.Find(m => m.Identifier == modeIdentifier); SetVoteText(GameMain.NetLobbyScreen.ModeList, mode, votes); } } AllowEndVoting = inc.ReadBoolean(); if (AllowEndVoting) { GameMain.NetworkMember.EndVoteCount = inc.ReadByte(); GameMain.NetworkMember.EndVoteMax = inc.ReadByte(); } AllowVoteKick = inc.ReadBoolean(); byte subVoteStateByte = inc.ReadByte(); VoteState subVoteState = VoteState.None; try { subVoteState = (VoteState)subVoteStateByte; } catch (System.Exception e) { DebugConsole.ThrowError("Failed to cast vote type \"" + subVoteStateByte + "\"", e); } if (subVoteState != VoteState.None) { byte voteTypeByte = inc.ReadByte(); VoteType voteType = VoteType.Unknown; try { voteType = (VoteType)voteTypeByte; } catch (System.Exception e) { DebugConsole.ThrowError("Failed to cast vote type \"" + voteTypeByte + "\"", e); } if (voteType != VoteType.Unknown) { byte yesClientCount = inc.ReadByte(); for (int i = 0; i < yesClientCount; i++) { byte clientID = inc.ReadByte(); var matchingClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == clientID); matchingClient?.SetVote(voteType, 2); } byte noClientCount = inc.ReadByte(); for (int i = 0; i < noClientCount; i++) { byte clientID = inc.ReadByte(); var matchingClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == clientID); matchingClient?.SetVote(voteType, 1); } GameMain.NetworkMember.SubmarineVoteYesCount = yesClientCount; GameMain.NetworkMember.SubmarineVoteNoCount = noClientCount; GameMain.NetworkMember.SubmarineVoteMax = inc.ReadByte(); switch (subVoteState) { case VoteState.Started: Client myClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == GameMain.Client.ID); if (!myClient.InGame) { VoteRunning = true; return; } string subName1 = inc.ReadString(); SubmarineInfo info = GameMain.Client.ServerSubmarines.FirstOrDefault(s => s.Name == subName1); if (info == null) { DebugConsole.ThrowError("Failed to find a matching submarine, vote aborted"); return; } VoteRunning = true; byte starterID = inc.ReadByte(); Client starterClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == starterID); float timeOut = inc.ReadByte(); GameMain.Client.ShowSubmarineChangeVoteInterface(starterClient, info, voteType, timeOut); break; case VoteState.Running: // Nothing specific break; case VoteState.Passed: case VoteState.Failed: VoteRunning = false; bool passed = inc.ReadBoolean(); string subName2 = inc.ReadString(); SubmarineInfo subInfo = GameMain.Client.ServerSubmarines.FirstOrDefault(s => s.Name == subName2); if (subInfo == null) { DebugConsole.ThrowError("Failed to find a matching submarine, vote aborted"); return; } if (GameMain.Client.VotingInterface != null) { GameMain.Client.VotingInterface.EndVote(passed, yesClientCount, noClientCount); } else if (GameMain.Client.ConnectedClients.Count > 1) { GameMain.NetworkMember.AddChatMessage(VotingInterface.GetSubmarineVoteResultMessage(subInfo, voteType, yesClientCount.ToString(), noClientCount.ToString(), passed), ChatMessageType.Server); } if (passed) { int deliveryFee = inc.ReadInt16(); switch (voteType) { case VoteType.PurchaseAndSwitchSub: GameMain.GameSession.PurchaseSubmarine(subInfo); GameMain.GameSession.SwitchSubmarine(subInfo, 0); break; case VoteType.PurchaseSub: GameMain.GameSession.PurchaseSubmarine(subInfo); break; case VoteType.SwitchSub: GameMain.GameSession.SwitchSubmarine(subInfo, deliveryFee); break; } SubmarineSelection.ContentRefreshRequired = true; } break; } } } GameMain.NetworkMember.ConnectedClients.ForEach(c => c.SetVote(VoteType.StartRound, false)); byte readyClientCount = inc.ReadByte(); for (int i = 0; i < readyClientCount; i++) { byte clientID = inc.ReadByte(); var matchingClient = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == clientID); matchingClient?.SetVote(VoteType.StartRound, true); } UpdateVoteTexts(GameMain.NetworkMember.ConnectedClients, VoteType.StartRound); inc.ReadPadBits(); }