Ejemplo n.º 1
0
        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;
                }
            }
        }
Ejemplo n.º 3
0
        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);
                }
            }
        }
Ejemplo n.º 5
0
        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);
            }
        }
Ejemplo n.º 6
0
        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();
        }
Ejemplo n.º 7
0
        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();
        }
Ejemplo n.º 8
0
        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);
        }
Ejemplo n.º 9
0
        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 + ")");
            }
        }
Ejemplo n.º 10
0
        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);
            }
        }
Ejemplo n.º 11
0
        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;
            }
        }
Ejemplo n.º 12
0
        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);
            }
        }
Ejemplo n.º 13
0
        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;
            }
        }
Ejemplo n.º 14
0
        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);
                }
            }
        }
Ejemplo n.º 15
0
        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);
        }
Ejemplo n.º 16
0
        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);
                }
            }
        }
Ejemplo n.º 17
0
        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);
            }
        }
Ejemplo n.º 18
0
        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;
                }
            }
        }
Ejemplo n.º 19
0
        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);
        }
Ejemplo n.º 21
0
        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);
        }
Ejemplo n.º 22
0
        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;
            }
        }
Ejemplo n.º 23
0
            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);
            }
Ejemplo n.º 24
0
        //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();
        }
Ejemplo n.º 26
0
        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;
            }
        }
Ejemplo n.º 27
0
        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();
            }
        }
Ejemplo n.º 29
0
        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);
                    }
                }
            }
        }
Ejemplo n.º 30
0
        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();
        }