Example #1
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;
                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);
            }
        }
Example #2
0
        public void ClientRead(IReadMessage incMsg)
        {
            cachedServerListInfo = null;

            ServerName        = incMsg.ReadString();
            ServerMessageText = incMsg.ReadString();
            MaxPlayers        = incMsg.ReadByte();
            HasPassword       = incMsg.ReadBoolean();
            IsPublic          = incMsg.ReadBoolean();
            GameMain.NetLobbyScreen.SetPublic(IsPublic);
            AllowFileTransfers = 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);
            }
        }
Example #3
0
        public void ClientAdminRead(IReadMessage incMsg)
        {
            bool hasPermission = incMsg.ReadBoolean();

            if (!hasPermission)
            {
                incMsg.ReadPadBits();
                return;
            }

            bool isOwner = incMsg.ReadBoolean();

            incMsg.ReadPadBits();

            bannedPlayers.Clear();
            UInt32 bannedPlayerCount = incMsg.ReadVariableUInt32();

            for (int i = 0; i < (int)bannedPlayerCount; i++)
            {
                string name               = incMsg.ReadString();
                UInt16 uniqueIdentifier   = incMsg.ReadUInt16();
                bool   isRangeBan         = incMsg.ReadBoolean();
                bool   includesExpiration = incMsg.ReadBoolean();
                incMsg.ReadPadBits();

                DateTime?expiration = null;
                if (includesExpiration)
                {
                    double hoursFromNow = incMsg.ReadDouble();
                    expiration = DateTime.Now + TimeSpan.FromHours(hoursFromNow);
                }

                string reason = incMsg.ReadString();

                string endPoint = "";
                UInt64 steamID  = 0;
                if (isOwner)
                {
                    endPoint = incMsg.ReadString();
                    steamID  = incMsg.ReadUInt64();
                }
                else
                {
                    endPoint = "Endpoint concealed by host";
                    steamID  = 0;
                }
                bannedPlayers.Add(new BannedPlayer(name, uniqueIdentifier, isRangeBan, endPoint, steamID, reason, expiration));
            }

            if (banFrame != null)
            {
                var parent = banFrame.Parent;
                parent.RemoveChild(banFrame);
                CreateBanFrame(parent);
            }
        }
Example #4
0
        public bool ServerAdminRead(IReadMessage incMsg, Client c)
        {
            if (!c.HasPermission(ClientPermissions.ManageSettings))
            {
                bool   enabled     = incMsg.ReadBoolean(); incMsg.ReadPadBits();
                UInt16 removeCount = incMsg.ReadUInt16();
                incMsg.BitPosition += removeCount * 4 * 8;
                UInt16 addCount = incMsg.ReadUInt16();
                for (int i = 0; i < addCount; i++)
                {
                    incMsg.ReadString(); //skip name
                    incMsg.ReadString(); //skip ip
                }
                return(false);
            }
            else
            {
                bool prevEnabled = Enabled;
                bool enabled     = incMsg.ReadBoolean(); incMsg.ReadPadBits();
                Enabled = enabled;

                UInt16 removeCount = incMsg.ReadUInt16();
                for (int i = 0; i < removeCount; i++)
                {
                    UInt16            id = incMsg.ReadUInt16();
                    WhiteListedPlayer whitelistedPlayer = whitelistedPlayers.Find(p => p.UniqueIdentifier == id);
                    if (whitelistedPlayer != null)
                    {
                        GameServer.Log(GameServer.ClientLogName(c) + " removed " + whitelistedPlayer.Name + " from whitelist (" + whitelistedPlayer.IP + ")", ServerLog.MessageType.ConsoleUsage);
                        RemoveFromWhiteList(whitelistedPlayer);
                    }
                }

                UInt16 addCount = incMsg.ReadUInt16();
                for (int i = 0; i < addCount; i++)
                {
                    string name = incMsg.ReadString();
                    string ip   = incMsg.ReadString();

                    GameServer.Log(GameServer.ClientLogName(c) + " added " + name + " to whitelist (" + ip + ")", ServerLog.MessageType.ConsoleUsage);
                    AddToWhiteList(name, ip);
                }

                bool changed = removeCount > 0 || addCount > 0 || prevEnabled != enabled;
                if (changed)
                {
                    Save();
                }
                return(changed);
            }
        }
        public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
        {
            var newState = (State)msg.ReadRangedInteger(0, Enum.GetNames(typeof(State)).Length);

            switch (newState)
            {
            case State.Transporting:
                ReturnCountdownStarted = msg.ReadBoolean();
                maxTransportTime       = msg.ReadSingle();
                float transportTimeLeft = msg.ReadSingle();

                ReturnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: (int)(transportTimeLeft * 1000.0f));
                RespawnCountdownStarted = false;
                if (CurrentState != newState)
                {
                    CoroutineManager.StopCoroutines("forcepos");
                    //CoroutineManager.StartCoroutine(ForceShuttleToPos(Level.Loaded.StartPosition - Vector2.UnitY * Level.ShaftHeight, 100.0f), "forcepos");
                }
                break;

            case State.Waiting:
                RespawnCountdownStarted = msg.ReadBoolean();
                ResetShuttle();
                float newRespawnTime = msg.ReadSingle();
                RespawnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: (int)(newRespawnTime * 1000.0f));
                break;

            case State.Returning:
                RespawnCountdownStarted = false;
                break;
            }
            CurrentState = newState;

            msg.ReadPadBits();
        }
Example #6
0
        public void ClientAdminRead(IReadMessage incMsg)
        {
            bool hasPermission = incMsg.ReadBoolean();

            if (!hasPermission)
            {
                incMsg.ReadPadBits();
                return;
            }

            bool isOwner = incMsg.ReadBoolean();

            incMsg.ReadPadBits();

            bannedPlayers.Clear();
            UInt32 bannedPlayerCount = incMsg.ReadVariableUInt32();

            for (int i = 0; i < (int)bannedPlayerCount; i++)
            {
                string name             = incMsg.ReadString();
                UInt16 uniqueIdentifier = incMsg.ReadUInt16();
                bool   isRangeBan       = incMsg.ReadBoolean(); incMsg.ReadPadBits();

                string ip      = "";
                UInt64 steamID = 0;
                if (isOwner)
                {
                    ip      = incMsg.ReadString();
                    steamID = incMsg.ReadUInt64();
                }
                else
                {
                    ip      = "IP concealed by host";
                    steamID = 0;
                }
                bannedPlayers.Add(new BannedPlayer(name, uniqueIdentifier, isRangeBan, ip, steamID));
            }

            if (banFrame != null)
            {
                var parent = banFrame.Parent;
                parent.RemoveChild(banFrame);
                CreateBanFrame(parent);
            }
        }
Example #7
0
        public PosInfo ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime, string parentDebugName)
        {
            float MaxVel        = NetConfig.MaxPhysicsBodyVelocity;
            float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;

            Vector2 newPosition        = SimPosition;
            float?  newRotation        = null;
            bool    awake              = FarseerBody.Awake;
            Vector2 newVelocity        = LinearVelocity;
            float?  newAngularVelocity = null;

            newPosition = new Vector2(
                msg.ReadSingle(),
                msg.ReadSingle());

            awake = msg.ReadBoolean();
            bool fixedRotation = msg.ReadBoolean();

            if (!fixedRotation)
            {
                newRotation = msg.ReadRangedSingle(0.0f, MathHelper.TwoPi, 8);
            }
            if (awake)
            {
                newVelocity = new Vector2(
                    msg.ReadRangedSingle(-MaxVel, MaxVel, 12),
                    msg.ReadRangedSingle(-MaxVel, MaxVel, 12));
                newVelocity = NetConfig.Quantize(newVelocity, -MaxVel, MaxVel, 12);

                if (!fixedRotation)
                {
                    newAngularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8);
                    newAngularVelocity = NetConfig.Quantize(newAngularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8);
                }
            }
            msg.ReadPadBits();

            if (!MathUtils.IsValid(newPosition) ||
                !MathUtils.IsValid(newVelocity) ||
                (newRotation.HasValue && !MathUtils.IsValid(newRotation.Value)) ||
                (newAngularVelocity.HasValue && !MathUtils.IsValid(newAngularVelocity.Value)))
            {
                string errorMsg = "Received invalid position data for \"" + parentDebugName
                                  + "\" (position: " + newPosition + ", rotation: " + (newRotation ?? 0) + ", velocity: " + newVelocity + ", angular velocity: " + (newAngularVelocity ?? 0) + ")";
#if DEBUG
                DebugConsole.ThrowError(errorMsg);
#endif
                GameAnalyticsManager.AddErrorEventOnce("PhysicsBody.ClientRead:InvalidData" + parentDebugName,
                                                       GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
                                                       errorMsg);
                return(null);
            }

            return(lastProcessedNetworkState > sendingTime ?
                   null :
                   new PosInfo(newPosition, newRotation, newVelocity, newAngularVelocity, sendingTime));
        }
Example #8
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();
        }
Example #9
0
        public void ReadMonsterEnabled(IReadMessage inc)
        {
            InitMonstersEnabled();
            List <string> monsterNames = MonsterEnabled.Keys.ToList();

            foreach (string s in monsterNames)
            {
                MonsterEnabled[s] = inc.ReadBoolean();
            }
            inc.ReadPadBits();
        }
Example #10
0
        public void ClientAdminRead(IReadMessage incMsg)
        {
            bool hasPermission = incMsg.ReadBoolean();

            if (!hasPermission)
            {
                incMsg.ReadPadBits();
                return;
            }

            bool isOwner = incMsg.ReadBoolean();

            localEnabled = incMsg.ReadBoolean();
            Enabled      = localEnabled;
            incMsg.ReadPadBits();

            whitelistedPlayers.Clear();
            UInt32 bannedPlayerCount = incMsg.ReadVariableUInt32();

            for (int i = 0; i < (int)bannedPlayerCount; i++)
            {
                string name             = incMsg.ReadString();
                UInt16 uniqueIdentifier = incMsg.ReadUInt16();

                string ip = "";
                if (isOwner)
                {
                    ip = incMsg.ReadString();
                }
                else
                {
                    ip = "IP concealed by host";
                }
                whitelistedPlayers.Add(new WhiteListedPlayer(name, uniqueIdentifier, ip));
            }

            if (whitelistFrame != null)
            {
                CreateWhiteListFrame(whitelistFrame.Parent);
            }
        }
Example #11
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);
            }
        }
Example #12
0
        public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
        {
            var posInfo = PhysicsBody.ClientRead(type, msg, sendingTime, parentDebugName: Name);

            msg.ReadPadBits();

            if (posInfo != null)
            {
                int index = 0;
                while (index < subBody.PositionBuffer.Count && sendingTime > subBody.PositionBuffer[index].Timestamp)
                {
                    index++;
                }

                subBody.PositionBuffer.Insert(index, posInfo);
            }
        }
Example #13
0
        public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
        {
            if (type != ServerNetObject.ENTITY_POSITION)
            {
                DebugConsole.NewMessage($"Error while reading a network event for the submarine \"{Info.Name} ({ID})\". Invalid event type ({type}).", Color.Red);
            }

            var posInfo = PhysicsBody.ClientRead(type, msg, sendingTime, parentDebugName: Info.Name);

            msg.ReadPadBits();

            if (posInfo != null)
            {
                int index = 0;
                while (index < subBody.PositionBuffer.Count && sendingTime > subBody.PositionBuffer[index].Timestamp)
                {
                    index++;
                }

                subBody.PositionBuffer.Insert(index, posInfo);
            }
        }
Example #14
0
        public static void ClientRead(IReadMessage msg)
        {
            UInt16                     id           = msg.ReadUInt16();
            ChatMessageType            type         = (ChatMessageType)msg.ReadByte();
            PlayerConnectionChangeType changeType   = PlayerConnectionChangeType.None;
            string                     txt          = "";
            string                     styleSetting = string.Empty;

            if (type != ChatMessageType.Order)
            {
                changeType = (PlayerConnectionChangeType)msg.ReadByte();
                txt        = msg.ReadString();
            }

            string    senderName      = msg.ReadString();
            Character senderCharacter = null;
            Client    senderClient    = null;
            bool      hasSenderClient = msg.ReadBoolean();

            if (hasSenderClient)
            {
                UInt64 clientId = msg.ReadUInt64();
                senderClient = GameMain.Client.ConnectedClients.Find(c => c.SteamID == clientId || c.ID == clientId);
                if (senderClient != null)
                {
                    senderName = senderClient.Name;
                }
            }
            bool hasSenderCharacter = msg.ReadBoolean();

            if (hasSenderCharacter)
            {
                senderCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character;
                if (senderCharacter != null)
                {
                    senderName = senderCharacter.Name;
                }
            }
            msg.ReadPadBits();

            switch (type)
            {
            case ChatMessageType.Default:
                break;

            case ChatMessageType.Order:
                var orderMessageInfo = OrderChatMessage.ReadOrder(msg);
                if (orderMessageInfo.OrderIndex < 0 || orderMessageInfo.OrderIndex >= Order.PrefabList.Count)
                {
                    DebugConsole.ThrowError("Invalid order message - order index out of bounds.");
                    if (NetIdUtils.IdMoreRecent(id, LastID))
                    {
                        LastID = id;
                    }
                    return;
                }
                var    orderPrefab = orderMessageInfo.OrderPrefab ?? Order.PrefabList[orderMessageInfo.OrderIndex];
                string orderOption = orderMessageInfo.OrderOption;
                orderOption ??= orderMessageInfo.OrderOptionIndex.HasValue && orderMessageInfo.OrderOptionIndex >= 0 && orderMessageInfo.OrderOptionIndex < orderPrefab.Options.Length ?
                orderPrefab.Options[orderMessageInfo.OrderOptionIndex.Value] : "";
                string targetRoom;

                if (orderMessageInfo.TargetEntity is Hull targetHull)
                {
                    targetRoom = targetHull.DisplayName;
                }
                else
                {
                    targetRoom = senderCharacter?.CurrentHull?.DisplayName;
                }

                txt = orderPrefab.GetChatMessage(orderMessageInfo.TargetCharacter?.Name, targetRoom,
                                                 givingOrderToSelf: orderMessageInfo.TargetCharacter == senderCharacter,
                                                 orderOption: orderOption,
                                                 priority: orderMessageInfo.Priority);

                if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
                {
                    Order order = null;
                    switch (orderMessageInfo.TargetType)
                    {
                    case Order.OrderTargetType.Entity:
                        order = new Order(orderPrefab, orderMessageInfo.TargetEntity, orderPrefab.GetTargetItemComponent(orderMessageInfo.TargetEntity as Item), orderGiver: senderCharacter);
                        break;

                    case Order.OrderTargetType.Position:
                        order = new Order(orderPrefab, orderMessageInfo.TargetPosition, orderGiver: senderCharacter);
                        break;

                    case Order.OrderTargetType.WallSection:
                        order = new Order(orderPrefab, orderMessageInfo.TargetEntity as Structure, orderMessageInfo.WallSectionIndex, orderGiver: senderCharacter);
                        break;
                    }

                    if (order != null)
                    {
                        if (order.TargetAllCharacters)
                        {
                            var fadeOutTime = !orderPrefab.IsIgnoreOrder ? (float?)orderPrefab.FadeOutTime : null;
                            GameMain.GameSession?.CrewManager?.AddOrder(order, fadeOutTime);
                        }
                        else
                        {
                            orderMessageInfo.TargetCharacter?.SetOrder(order, orderOption, orderMessageInfo.Priority, senderCharacter);
                        }
                    }
                }

                if (NetIdUtils.IdMoreRecent(id, LastID))
                {
                    GameMain.Client.AddChatMessage(
                        new OrderChatMessage(orderPrefab, orderOption, orderMessageInfo.Priority, txt, orderMessageInfo.TargetPosition ?? orderMessageInfo.TargetEntity as ISpatialEntity, orderMessageInfo.TargetCharacter, senderCharacter));
                    LastID = id;
                }
                return;

            case ChatMessageType.ServerMessageBox:
                txt = TextManager.GetServerMessage(txt);
                break;

            case ChatMessageType.ServerMessageBoxInGame:
                styleSetting = msg.ReadString();
                txt          = TextManager.GetServerMessage(txt);
                break;
            }

            if (NetIdUtils.IdMoreRecent(id, LastID))
            {
                switch (type)
                {
                case ChatMessageType.MessageBox:
                case ChatMessageType.ServerMessageBox:
                    //only show the message box if the text differs from the text in the currently visible box
                    if ((GUIMessageBox.VisibleBox as GUIMessageBox)?.Text?.Text != txt)
                    {
                        new GUIMessageBox("", txt);
                    }
                    break;

                case ChatMessageType.ServerMessageBoxInGame:
                    new GUIMessageBox("", txt, new string[0], type: GUIMessageBox.Type.InGame, iconStyle: styleSetting);
                    break;

                case ChatMessageType.Console:
                    DebugConsole.NewMessage(txt, MessageColor[(int)ChatMessageType.Console]);
                    break;

                case ChatMessageType.ServerLog:
                    if (!Enum.TryParse(senderName, out ServerLog.MessageType messageType))
                    {
                        return;
                    }
                    GameMain.Client.ServerSettings.ServerLog?.WriteLine(txt, messageType);
                    break;

                default:
                    GameMain.Client.AddChatMessage(txt, type, senderName, senderClient, senderCharacter, changeType);
                    break;
                }
                LastID = id;
            }
        }
        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();
        }
        /// <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();
            }
        }
Example #17
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();
        }
Example #18
0
        protected void ReadConnectionInitializationStep(IReadMessage inc)
        {
            ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();

            IWriteMessage outMsg;

            switch (step)
            {
            case ConnectionInitialization.SteamTicketAndVersion:
                if (initializationStep != ConnectionInitialization.SteamTicketAndVersion)
                {
                    return;
                }
                outMsg = new WriteOnlyMessage();
                outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
                outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
                outMsg.Write(Name);
                outMsg.Write(ownerKey);
                outMsg.Write(SteamManager.GetSteamID());
                if (steamAuthTicket == null)
                {
                    outMsg.Write((UInt16)0);
                }
                else
                {
                    outMsg.Write((UInt16)steamAuthTicket.Data.Length);
                    outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);
                }
                outMsg.Write(GameMain.Version.ToString());
                outMsg.Write(GameMain.Config.Language);

                SendMsgInternal(DeliveryMethod.Reliable, outMsg);
                break;

            case ConnectionInitialization.ContentPackageOrder:
                if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
                    initializationStep == ConnectionInitialization.Password)
                {
                    initializationStep = ConnectionInitialization.ContentPackageOrder;
                }
                if (initializationStep != ConnectionInitialization.ContentPackageOrder)
                {
                    return;
                }
                outMsg = new WriteOnlyMessage();
                outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
                outMsg.Write((byte)ConnectionInitialization.ContentPackageOrder);

                string serverName = inc.ReadString();

                UInt32 cpCount = inc.ReadVariableUInt32();
                ServerContentPackage        corePackage     = null;
                List <ServerContentPackage> regularPackages = new List <ServerContentPackage>();
                List <ServerContentPackage> missingPackages = new List <ServerContentPackage>();
                for (int i = 0; i < cpCount; i++)
                {
                    string name       = inc.ReadString();
                    string hash       = inc.ReadString();
                    UInt64 workshopId = inc.ReadUInt64();
                    var    pkg        = new ServerContentPackage(name, hash, workshopId);
                    if (pkg.CorePackage != null)
                    {
                        corePackage = pkg;
                    }
                    else if (pkg.RegularPackage != null)
                    {
                        regularPackages.Add(pkg);
                    }
                    else
                    {
                        missingPackages.Add(pkg);
                    }
                }

                if (missingPackages.Count > 0)
                {
                    var nonDownloadable = missingPackages.Where(p => p.WorkshopId == 0);

                    if (nonDownloadable.Any())
                    {
                        string disconnectMsg;
                        if (nonDownloadable.Count() == 1)
                        {
                            disconnectMsg = $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}";
                        }
                        else
                        {
                            List <string> packageStrs = new List <string>();
                            nonDownloadable.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
                            disconnectMsg = $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}";
                        }
                        Close(disconnectMsg, disableReconnect: true);
                        OnDisconnectMessageReceived?.Invoke(DisconnectReason.MissingContentPackage + "/" + disconnectMsg);
                    }
                    else
                    {
                        Close(disableReconnect: true);

                        string missingModNames   = "\n";
                        int    displayedModCount = 0;
                        foreach (ServerContentPackage missingPackage in missingPackages)
                        {
                            missingModNames += "\n- " + GetPackageStr(missingPackage);
                            displayedModCount++;
                            if (GUI.Font.MeasureString(missingModNames).Y > GameMain.GraphicsHeight * 0.5f)
                            {
                                missingModNames += "\n\n" + TextManager.GetWithVariable("workshopitemdownloadprompttruncated", "[number]", (missingPackages.Count - displayedModCount).ToString());
                                break;
                            }
                        }
                        missingModNames += "\n\n";

                        var msgBox = new GUIMessageBox(
                            TextManager.Get("WorkshopItemDownloadTitle"),
                            TextManager.GetWithVariable("WorkshopItemDownloadPrompt", "[items]", missingModNames),
                            new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
                        msgBox.Buttons[0].OnClicked = (yesBtn, userdata) =>
                        {
                            GameMain.ServerListScreen.Select();
                            GameMain.ServerListScreen.DownloadWorkshopItems(missingPackages.Select(p => p.WorkshopId), serverName, ServerConnection.EndPointString);
                            return(true);
                        };
                        msgBox.Buttons[0].OnClicked += msgBox.Close;
                        msgBox.Buttons[1].OnClicked  = msgBox.Close;
                    }

                    return;
                }

                if (!contentPackageOrderReceived)
                {
                    GameMain.Config.BackUpModOrder();
                    GameMain.Config.SwapPackages(corePackage.CorePackage, regularPackages.Select(p => p.RegularPackage).ToList());
                    contentPackageOrderReceived = true;
                }

                SendMsgInternal(DeliveryMethod.Reliable, outMsg);
                break;

            case ConnectionInitialization.Password:
                if (initializationStep == ConnectionInitialization.SteamTicketAndVersion)
                {
                    initializationStep = ConnectionInitialization.Password;
                }
                if (initializationStep != ConnectionInitialization.Password)
                {
                    return;
                }
                bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
                int  retries      = 0;
                if (incomingSalt)
                {
                    passwordSalt = inc.ReadInt32();
                }
                else
                {
                    retries = inc.ReadInt32();
                }
                OnRequestPassword?.Invoke(passwordSalt, retries);
                break;
            }
        }
        public virtual void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
        {
            switch (type)
            {
            case ServerNetObject.ENTITY_POSITION:
                bool facingRight = AnimController.Dir > 0.0f;

                lastRecvPositionUpdateTime = (float)Lidgren.Network.NetTime.Now;

                AnimController.Frozen = false;
                Enabled = true;

                UInt16 networkUpdateID = 0;
                if (msg.ReadBoolean())
                {
                    networkUpdateID = msg.ReadUInt16();
                }
                else
                {
                    bool aimInput = msg.ReadBoolean();
                    keys[(int)InputType.Aim].Held = aimInput;
                    keys[(int)InputType.Aim].SetState(false, aimInput);

                    bool shootInput = msg.ReadBoolean();
                    keys[(int)InputType.Shoot].Held = shootInput;
                    keys[(int)InputType.Shoot].SetState(false, shootInput);

                    bool useInput = msg.ReadBoolean();
                    keys[(int)InputType.Use].Held = useInput;
                    keys[(int)InputType.Use].SetState(false, useInput);

                    if (AnimController is HumanoidAnimController)
                    {
                        bool crouching = msg.ReadBoolean();
                        keys[(int)InputType.Crouch].Held = crouching;
                        keys[(int)InputType.Crouch].SetState(false, crouching);
                    }

                    bool attackInput = msg.ReadBoolean();
                    keys[(int)InputType.Attack].Held = attackInput;
                    keys[(int)InputType.Attack].SetState(false, attackInput);

                    double aimAngle = msg.ReadUInt16() / 65535.0 * 2.0 * Math.PI;
                    cursorPosition = AimRefPosition + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 500.0f;
                    TransformCursorPos();

                    bool ragdollInput = msg.ReadBoolean();
                    keys[(int)InputType.Ragdoll].Held = ragdollInput;
                    keys[(int)InputType.Ragdoll].SetState(false, ragdollInput);

                    facingRight = msg.ReadBoolean();
                }

                bool      entitySelected    = msg.ReadBoolean();
                Character selectedCharacter = null;
                Item      selectedItem      = null;

                AnimController.Animation animation = AnimController.Animation.None;
                if (entitySelected)
                {
                    ushort characterID = msg.ReadUInt16();
                    ushort itemID      = msg.ReadUInt16();
                    selectedCharacter = FindEntityByID(characterID) as Character;
                    selectedItem      = FindEntityByID(itemID) as Item;
                    if (characterID != NullEntityID)
                    {
                        bool doingCpr = msg.ReadBoolean();
                        if (doingCpr && SelectedCharacter != null)
                        {
                            animation = AnimController.Animation.CPR;
                        }
                    }
                }

                Vector2 pos = new Vector2(
                    msg.ReadSingle(),
                    msg.ReadSingle());
                float   MaxVel         = NetConfig.MaxPhysicsBodyVelocity;
                Vector2 linearVelocity = new Vector2(
                    msg.ReadRangedSingle(-MaxVel, MaxVel, 12),
                    msg.ReadRangedSingle(-MaxVel, MaxVel, 12));
                linearVelocity = NetConfig.Quantize(linearVelocity, -MaxVel, MaxVel, 12);

                bool  fixedRotation   = msg.ReadBoolean();
                float?rotation        = null;
                float?angularVelocity = null;
                if (!fixedRotation)
                {
                    rotation = msg.ReadSingle();
                    float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;
                    angularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8);
                    angularVelocity = NetConfig.Quantize(angularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8);
                }

                bool readStatus = msg.ReadBoolean();
                if (readStatus)
                {
                    ReadStatus(msg);
                    (AIController as EnemyAIController)?.PetBehavior?.ClientRead(msg);
                }

                msg.ReadPadBits();

                int index = 0;
                if (GameMain.Client.Character == this && CanMove)
                {
                    var posInfo = new CharacterStateInfo(
                        pos, rotation,
                        networkUpdateID,
                        facingRight ? Direction.Right : Direction.Left,
                        selectedCharacter, selectedItem, animation);

                    while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID))
                    {
                        index++;
                    }
                    memState.Insert(index, posInfo);
                }
                else
                {
                    var posInfo = new CharacterStateInfo(
                        pos, rotation,
                        linearVelocity, angularVelocity,
                        sendingTime, facingRight ? Direction.Right : Direction.Left,
                        selectedCharacter, selectedItem, animation);

                    while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp)
                    {
                        index++;
                    }
                    memState.Insert(index, posInfo);
                }

                break;

            case ServerNetObject.ENTITY_EVENT:

                int eventType = msg.ReadRangedInteger(0, 5);
                switch (eventType)
                {
                case 0:         //NetEntityEvent.Type.InventoryState
                    if (Inventory == null)
                    {
                        string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ", removed: " + Removed + ")";
                        DebugConsole.ThrowError(errorMsg);
                        GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);

                        //read anyway to prevent messing up reading the rest of the message
                        UInt16 lastEventID = msg.ReadUInt16();
                        byte   itemCount   = msg.ReadByte();
                        for (int i = 0; i < itemCount; i++)
                        {
                            msg.ReadUInt16();
                        }
                    }
                    else
                    {
                        Inventory.ClientRead(type, msg, sendingTime);
                    }
                    break;

                case 1:         //NetEntityEvent.Type.Control
                    byte ownerID = msg.ReadByte();
                    ResetNetState();
                    if (ownerID == GameMain.Client.ID)
                    {
                        if (controlled != null)
                        {
                            LastNetworkUpdateID = controlled.LastNetworkUpdateID;
                        }

                        if (!IsDead)
                        {
                            Controlled = this;
                        }
                        IsRemotePlayer                   = false;
                        GameMain.Client.HasSpawned       = true;
                        GameMain.Client.Character        = this;
                        GameMain.LightManager.LosEnabled = true;
                    }
                    else
                    {
                        if (controlled == this)
                        {
                            Controlled     = null;
                            IsRemotePlayer = ownerID > 0;
                        }
                    }
                    break;

                case 2:         //NetEntityEvent.Type.Status
                    ReadStatus(msg);
                    break;

                case 3:         //NetEntityEvent.Type.UpdateSkills
                    int skillCount = msg.ReadByte();
                    for (int i = 0; i < skillCount; i++)
                    {
                        string skillIdentifier = msg.ReadString();
                        float  skillLevel      = msg.ReadSingle();
                        info?.SetSkillLevel(skillIdentifier, skillLevel, WorldPosition + Vector2.UnitY * 150.0f);
                    }
                    break;

                case 4:         //NetEntityEvent.Type.ExecuteAttack
                    int    attackLimbIndex = msg.ReadByte();
                    UInt16 targetEntityID  = msg.ReadUInt16();
                    int    targetLimbIndex = msg.ReadByte();

                    //255 = entity already removed, no need to do anything
                    if (attackLimbIndex == 255 || Removed)
                    {
                        break;
                    }

                    if (attackLimbIndex >= AnimController.Limbs.Length)
                    {
                        DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})");
                        break;
                    }
                    Limb attackLimb = AnimController.Limbs[attackLimbIndex];
                    Limb targetLimb = null;
                    if (!(FindEntityByID(targetEntityID) is IDamageable targetEntity))
                    {
                        DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Target entity not found (ID {targetEntityID})");
                        break;
                    }
                    if (targetEntity is Character targetCharacter)
                    {
                        if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length)
                        {
                            DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})");
                            break;
                        }
                        targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex];
                    }
                    if (attackLimb?.attack != null)
                    {
                        attackLimb.ExecuteAttack(targetEntity, targetLimb, out _);
                    }
                    break;

                case 5:         //NetEntityEvent.Type.AssignCampaignInteraction
                    byte campaignInteractionType = msg.ReadByte();
                    (GameMain.GameSession?.GameMode as CampaignMode)?.AssignNPCMenuInteraction(this, (CampaignMode.InteractionType)campaignInteractionType);
                    break;
                }
                msg.ReadPadBits();
                break;
            }
        }
        public void ServerRead(IReadMessage incMsg, Client c)
        {
            if (!c.HasPermission(Networking.ClientPermissions.ManageSettings))
            {
                return;
            }

            NetFlags flags = (NetFlags)incMsg.ReadByte();

            bool changed = false;

            if (flags.HasFlag(NetFlags.Name))
            {
                string serverName = incMsg.ReadString();
                if (ServerName != serverName)
                {
                    changed = true;
                }
                ServerName = serverName;
            }

            if (flags.HasFlag(NetFlags.Message))
            {
                string serverMessageText = incMsg.ReadString();
                if (ServerMessageText != serverMessageText)
                {
                    changed = true;
                }
                ServerMessageText = serverMessageText;
            }

            if (flags.HasFlag(NetFlags.Properties))
            {
                changed |= ReadExtraCargo(incMsg);

                UInt32 count = incMsg.ReadUInt32();

                for (int i = 0; i < count; i++)
                {
                    UInt32 key = incMsg.ReadUInt32();

                    if (netProperties.ContainsKey(key))
                    {
                        object prevValue = netProperties[key].Value;
                        netProperties[key].Read(incMsg);
                        if (!netProperties[key].PropEquals(prevValue, netProperties[key]))
                        {
                            GameServer.Log(GameServer.ClientLogName(c) + " changed " + netProperties[key].Name + " to " + netProperties[key].Value.ToString(), ServerLog.MessageType.ServerMessage);
                        }
                        changed = true;
                    }
                    else
                    {
                        UInt32 size = incMsg.ReadVariableUInt32();
                        incMsg.BitPosition += (int)(8 * size);
                    }
                }

                bool changedMonsterSettings = incMsg.ReadBoolean(); incMsg.ReadPadBits();
                changed |= changedMonsterSettings;
                if (changedMonsterSettings)
                {
                    ReadMonsterEnabled(incMsg);
                }
                changed |= BanList.ServerAdminRead(incMsg, c);
                changed |= Whitelist.ServerAdminRead(incMsg, c);
            }

            if (flags.HasFlag(NetFlags.Misc))
            {
                int orBits  = incMsg.ReadRangedInteger(0, (int)Barotrauma.MissionType.All) & (int)Barotrauma.MissionType.All;
                int andBits = incMsg.ReadRangedInteger(0, (int)Barotrauma.MissionType.All) & (int)Barotrauma.MissionType.All;
                GameMain.NetLobbyScreen.MissionType = (Barotrauma.MissionType)(((int)GameMain.NetLobbyScreen.MissionType | orBits) & andBits);

                int traitorSetting = (int)TraitorsEnabled + incMsg.ReadByte() - 1;
                if (traitorSetting < 0)
                {
                    traitorSetting = 2;
                }
                if (traitorSetting > 2)
                {
                    traitorSetting = 0;
                }
                TraitorsEnabled = (YesNoMaybe)traitorSetting;

                int botCount = BotCount + incMsg.ReadByte() - 1;
                if (botCount < 0)
                {
                    botCount = MaxBotCount;
                }
                if (botCount > MaxBotCount)
                {
                    botCount = 0;
                }
                BotCount = botCount;

                int botSpawnMode = (int)BotSpawnMode + incMsg.ReadByte() - 1;
                if (botSpawnMode < 0)
                {
                    botSpawnMode = 1;
                }
                if (botSpawnMode > 1)
                {
                    botSpawnMode = 0;
                }
                BotSpawnMode = (BotSpawnMode)botSpawnMode;

                float levelDifficulty = incMsg.ReadSingle();
                if (levelDifficulty >= 0.0f)
                {
                    SelectedLevelDifficulty = levelDifficulty;
                }

                UseRespawnShuttle = incMsg.ReadBoolean();

                bool changedAutoRestart = incMsg.ReadBoolean();
                bool autoRestart        = incMsg.ReadBoolean();
                if (changedAutoRestart)
                {
                    AutoRestart = autoRestart;
                }

                changed |= true;
            }

            if (flags.HasFlag(NetFlags.LevelSeed))
            {
                GameMain.NetLobbyScreen.LevelSeed = incMsg.ReadString();
                changed |= true;
            }

            if (changed)
            {
                if (KarmaPreset == "custom")
                {
                    GameMain.NetworkMember?.KarmaManager?.SaveCustomPreset();
                    GameMain.NetworkMember?.KarmaManager?.Save();
                }
                SaveSettings();
                GameMain.NetLobbyScreen.LastUpdateID++;
            }
        }
Example #21
0
        private void ReadConnectionInitializationStep(IReadMessage inc)
        {
            if (!isActive)
            {
                return;
            }

            ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();

            IWriteMessage outMsg;

            //DebugConsole.NewMessage(step + " " + initializationStep);
            switch (step)
            {
            case ConnectionInitialization.SteamTicketAndVersion:
                if (initializationStep != ConnectionInitialization.SteamTicketAndVersion)
                {
                    return;
                }
                outMsg = new WriteOnlyMessage();
                outMsg.Write((byte)DeliveryMethod.Reliable);
                outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
                outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
                outMsg.Write(Name);
                outMsg.Write(SteamManager.GetSteamID());
                outMsg.Write((UInt16)steamAuthTicket.Data.Length);
                outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);

                outMsg.Write(GameMain.Version.ToString());

                IEnumerable <ContentPackage> mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
                outMsg.WriteVariableUInt32((UInt32)mpContentPackages.Count());
                foreach (ContentPackage contentPackage in mpContentPackages)
                {
                    outMsg.Write(contentPackage.Name);
                    outMsg.Write(contentPackage.MD5hash.Hash);
                }

                heartbeatTimer = 5.0;
                Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
                sentBytes += outMsg.LengthBytes;
                break;

            case ConnectionInitialization.ContentPackageOrder:
                if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
                    initializationStep == ConnectionInitialization.Password)
                {
                    initializationStep = ConnectionInitialization.ContentPackageOrder;
                }
                if (initializationStep != ConnectionInitialization.ContentPackageOrder)
                {
                    return;
                }
                outMsg = new WriteOnlyMessage();
                outMsg.Write((byte)DeliveryMethod.Reliable);
                outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
                outMsg.Write((byte)ConnectionInitialization.ContentPackageOrder);

                UInt32 cpCount = inc.ReadVariableUInt32();
                List <ContentPackage> serverContentPackages = new List <ContentPackage>();
                for (int i = 0; i < cpCount; i++)
                {
                    string hash = inc.ReadString();
                    serverContentPackages.Add(GameMain.Config.SelectedContentPackages.Find(cp => cp.MD5hash.Hash == hash));
                }

                if (!contentPackageOrderReceived)
                {
                    GameMain.Config.ReorderSelectedContentPackages(cp => serverContentPackages.Contains(cp) ?
                                                                   serverContentPackages.IndexOf(cp) :
                                                                   serverContentPackages.Count + GameMain.Config.SelectedContentPackages.IndexOf(cp));
                    contentPackageOrderReceived = true;
                }

                Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
                sentBytes += outMsg.LengthBytes;
                break;

            case ConnectionInitialization.Password:
                if (initializationStep == ConnectionInitialization.SteamTicketAndVersion)
                {
                    initializationStep = ConnectionInitialization.Password;
                }
                if (initializationStep != ConnectionInitialization.Password)
                {
                    return;
                }
                bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
                int  retries      = 0;
                if (incomingSalt)
                {
                    passwordSalt = inc.ReadInt32();
                }
                else
                {
                    retries = inc.ReadInt32();
                }
                OnRequestPassword?.Invoke(passwordSalt, retries);
                break;
            }
        }
Example #22
0
        public static void ClientRead(IReadMessage msg)
        {
            UInt16                     id           = msg.ReadUInt16();
            ChatMessageType            type         = (ChatMessageType)msg.ReadByte();
            PlayerConnectionChangeType changeType   = PlayerConnectionChangeType.None;
            string                     txt          = "";
            string                     styleSetting = string.Empty;

            if (type != ChatMessageType.Order)
            {
                changeType = (PlayerConnectionChangeType)msg.ReadByte();
                txt        = msg.ReadString();
            }

            string    senderName      = msg.ReadString();
            Character senderCharacter = null;
            Client    senderClient    = null;
            bool      hasSenderClient = msg.ReadBoolean();

            if (hasSenderClient)
            {
                UInt64 clientId = msg.ReadUInt64();
                senderClient = GameMain.Client.ConnectedClients.Find(c => c.SteamID == clientId || c.ID == clientId);
                if (senderClient != null)
                {
                    senderName = senderClient.Name;
                }
            }
            bool hasSenderCharacter = msg.ReadBoolean();

            if (hasSenderCharacter)
            {
                senderCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character;
                if (senderCharacter != null)
                {
                    senderName = senderCharacter.Name;
                }
            }
            msg.ReadPadBits();

            switch (type)
            {
            case ChatMessageType.Default:
                break;

            case ChatMessageType.Order:
                int       orderIndex        = msg.ReadByte();
                UInt16    targetCharacterID = msg.ReadUInt16();
                Character targetCharacter   = Entity.FindEntityByID(targetCharacterID) as Character;
                Entity    targetEntity      = Entity.FindEntityByID(msg.ReadUInt16());

                Order  orderPrefab = null;
                int?   optionIndex = null;
                string orderOption = null;

                // The option of a Dismiss order is written differently so we know what order we target
                // now that the game supports multiple current orders simultaneously
                if (orderIndex >= 0 && orderIndex < Order.PrefabList.Count)
                {
                    orderPrefab = Order.PrefabList[orderIndex];
                    if (orderPrefab.Identifier != "dismissed")
                    {
                        optionIndex = msg.ReadByte();
                    }
                    // Does the dismiss order have a specified target?
                    else if (msg.ReadBoolean())
                    {
                        int identifierCount = msg.ReadByte();
                        if (identifierCount > 0)
                        {
                            int   dismissedOrderIndex  = msg.ReadByte();
                            Order dismissedOrderPrefab = null;
                            if (dismissedOrderIndex >= 0 && dismissedOrderIndex < Order.PrefabList.Count)
                            {
                                dismissedOrderPrefab = Order.PrefabList[dismissedOrderIndex];
                                orderOption          = dismissedOrderPrefab.Identifier;
                            }
                            if (identifierCount > 1)
                            {
                                int dismissedOrderOptionIndex = msg.ReadByte();
                                if (dismissedOrderPrefab != null)
                                {
                                    var options = dismissedOrderPrefab.Options;
                                    if (options != null && dismissedOrderOptionIndex >= 0 && dismissedOrderOptionIndex < options.Length)
                                    {
                                        orderOption += $".{options[dismissedOrderOptionIndex]}";
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    optionIndex = msg.ReadByte();
                }

                int                   orderPriority       = msg.ReadByte();
                OrderTarget           orderTargetPosition = null;
                Order.OrderTargetType orderTargetType     = (Order.OrderTargetType)msg.ReadByte();
                int                   wallSectionIndex    = 0;
                if (msg.ReadBoolean())
                {
                    var x    = msg.ReadSingle();
                    var y    = msg.ReadSingle();
                    var hull = Entity.FindEntityByID(msg.ReadUInt16()) as Hull;
                    orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, creatingFromExistingData: true);
                }
                else if (orderTargetType == Order.OrderTargetType.WallSection)
                {
                    wallSectionIndex = msg.ReadByte();
                }

                if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
                {
                    DebugConsole.ThrowError("Invalid order message - order index out of bounds.");
                    if (NetIdUtils.IdMoreRecent(id, LastID))
                    {
                        LastID = id;
                    }
                    return;
                }
                else
                {
                    orderPrefab ??= Order.PrefabList[orderIndex];
                }

                orderOption ??= optionIndex.HasValue && optionIndex >= 0 && optionIndex < orderPrefab.Options.Length ? orderPrefab.Options[optionIndex.Value] : "";
                txt = orderPrefab.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption);

                if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
                {
                    Order order = null;
                    switch (orderTargetType)
                    {
                    case Order.OrderTargetType.Entity:
                        order = new Order(orderPrefab, targetEntity, orderPrefab.GetTargetItemComponent(targetEntity as Item), orderGiver: senderCharacter);
                        break;

                    case Order.OrderTargetType.Position:
                        order = new Order(orderPrefab, orderTargetPosition, orderGiver: senderCharacter);
                        break;

                    case Order.OrderTargetType.WallSection:
                        order = new Order(orderPrefab, targetEntity as Structure, wallSectionIndex, orderGiver: senderCharacter);
                        break;
                    }

                    if (order != null)
                    {
                        if (order.TargetAllCharacters)
                        {
                            var fadeOutTime = !orderPrefab.IsIgnoreOrder ? (float?)orderPrefab.FadeOutTime : null;
                            GameMain.GameSession?.CrewManager?.AddOrder(order, fadeOutTime);
                        }
                        else if (targetCharacter != null)
                        {
                            targetCharacter.SetOrder(order, orderOption, orderPriority, senderCharacter);
                        }
                    }
                }

                if (NetIdUtils.IdMoreRecent(id, LastID))
                {
                    GameMain.Client.AddChatMessage(
                        new OrderChatMessage(orderPrefab, orderOption, orderPriority, txt, orderTargetPosition ?? targetEntity as ISpatialEntity, targetCharacter, senderCharacter));
                    LastID = id;
                }
                return;

            case ChatMessageType.ServerMessageBox:
                txt = TextManager.GetServerMessage(txt);
                break;

            case ChatMessageType.ServerMessageBoxInGame:
                styleSetting = msg.ReadString();
                txt          = TextManager.GetServerMessage(txt);
                break;
            }

            if (NetIdUtils.IdMoreRecent(id, LastID))
            {
                switch (type)
                {
                case ChatMessageType.MessageBox:
                case ChatMessageType.ServerMessageBox:
                    //only show the message box if the text differs from the text in the currently visible box
                    if ((GUIMessageBox.VisibleBox as GUIMessageBox)?.Text?.Text != txt)
                    {
                        new GUIMessageBox("", txt);
                    }
                    break;

                case ChatMessageType.ServerMessageBoxInGame:
                    new GUIMessageBox("", txt, new string[0], type: GUIMessageBox.Type.InGame, iconStyle: styleSetting);
                    break;

                case ChatMessageType.Console:
                    DebugConsole.NewMessage(txt, MessageColor[(int)ChatMessageType.Console]);
                    break;

                case ChatMessageType.ServerLog:
                    if (!Enum.TryParse(senderName, out ServerLog.MessageType messageType))
                    {
                        return;
                    }
                    GameMain.Client.ServerSettings.ServerLog?.WriteLine(txt, messageType);
                    break;

                default:
                    GameMain.Client.AddChatMessage(txt, type, senderName, senderClient, senderCharacter, changeType);
                    break;
                }
                LastID = id;
            }
        }
Example #23
0
        public void ServerRead(IReadMessage inc, Client sender)
        {
            if (GameMain.Server == null || sender == null)
            {
                return;
            }

            byte     voteTypeByte = inc.ReadByte();
            VoteType voteType     = VoteType.Unknown;

            try
            {
                voteType = (VoteType)voteTypeByte;
            }
            catch (Exception e)
            {
                DebugConsole.ThrowError("Failed to cast vote type \"" + voteTypeByte + "\"", e);
                return;
            }

            switch (voteType)
            {
            case VoteType.Sub:
                string        subName = inc.ReadString();
                SubmarineInfo sub     = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName);
                sender.SetVote(voteType, sub);
                break;

            case VoteType.Mode:
                string         modeIdentifier = inc.ReadString();
                GameModePreset mode           = GameModePreset.List.Find(gm => gm.Identifier == modeIdentifier);
                if (!mode.Votable)
                {
                    break;
                }

                sender.SetVote(voteType, mode);
                break;

            case VoteType.EndRound:
                if (!sender.HasSpawned)
                {
                    return;
                }
                sender.SetVote(voteType, inc.ReadBoolean());

                GameMain.NetworkMember.EndVoteCount = GameMain.Server.ConnectedClients.Count(c => c.HasSpawned && c.GetVote <bool>(VoteType.EndRound));
                GameMain.NetworkMember.EndVoteMax   = GameMain.Server.ConnectedClients.Count(c => c.HasSpawned);

                break;

            case VoteType.Kick:
                byte kickedClientID = inc.ReadByte();

                Client kicked = GameMain.Server.ConnectedClients.Find(c => c.ID == kickedClientID);
                if (kicked != null && kicked.Connection != GameMain.Server.OwnerConnection && !kicked.HasKickVoteFrom(sender))
                {
                    kicked.AddKickVote(sender);
                    Client.UpdateKickVotes(GameMain.Server.ConnectedClients);
                    GameMain.Server.SendChatMessage($"ServerMessage.HasVotedToKick~[initiator]={sender.Name}~[target]={kicked.Name}", ChatMessageType.Server, null);
                }

                break;

            case VoteType.StartRound:
                bool ready = inc.ReadBoolean();
                if (ready != sender.GetVote <bool>(VoteType.StartRound))
                {
                    sender.SetVote(VoteType.StartRound, ready);
                    GameServer.Log(GameServer.ClientLogName(sender) + (ready ? " is ready to start the game." : " is not ready to start the game."), ServerLog.MessageType.ServerMessage);
                }
                break;

            case VoteType.PurchaseAndSwitchSub:
            case VoteType.PurchaseSub:
            case VoteType.SwitchSub:
                bool startVote = inc.ReadBoolean();
                if (startVote)
                {
                    StartSubmarineVote(inc, voteType, sender);
                }
                else
                {
                    sender.SetVote(voteType, (int)inc.ReadByte());
                }

                GameMain.Server.SubmarineVoteYesCount = GameMain.Server.ConnectedClients.Count(c => c.GetVote <int>(SubVote.VoteType) == 2);
                GameMain.Server.SubmarineVoteNoCount  = GameMain.Server.ConnectedClients.Count(c => c.GetVote <int>(SubVote.VoteType) == 1);
                GameMain.Server.SubmarineVoteMax      = GameMain.Server.ConnectedClients.Count(c => c.InGame);
                break;
            }

            inc.ReadPadBits();

            GameMain.Server.UpdateVoteStatus();
        }
        public virtual void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
        {
            switch (type)
            {
            case ServerNetObject.ENTITY_POSITION:
                bool facingRight = AnimController.Dir > 0.0f;

                lastRecvPositionUpdateTime = (float)Lidgren.Network.NetTime.Now;

                AnimController.Frozen = false;
                Enabled = true;

                UInt16 networkUpdateID = 0;
                if (msg.ReadBoolean())
                {
                    networkUpdateID = msg.ReadUInt16();
                }
                else
                {
                    bool aimInput = msg.ReadBoolean();
                    keys[(int)InputType.Aim].Held = aimInput;
                    keys[(int)InputType.Aim].SetState(false, aimInput);

                    bool shootInput = msg.ReadBoolean();
                    keys[(int)InputType.Shoot].Held = shootInput;
                    keys[(int)InputType.Shoot].SetState(false, shootInput);

                    bool useInput = msg.ReadBoolean();
                    keys[(int)InputType.Use].Held = useInput;
                    keys[(int)InputType.Use].SetState(false, useInput);

                    if (AnimController is HumanoidAnimController)
                    {
                        bool crouching = msg.ReadBoolean();
                        keys[(int)InputType.Crouch].Held = crouching;
                        keys[(int)InputType.Crouch].SetState(false, crouching);
                    }

                    bool attackInput = msg.ReadBoolean();
                    keys[(int)InputType.Attack].Held = attackInput;
                    keys[(int)InputType.Attack].SetState(false, attackInput);

                    double aimAngle = msg.ReadUInt16() / 65535.0 * 2.0 * Math.PI;
                    cursorPosition = AimRefPosition + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 500.0f;
                    TransformCursorPos();

                    bool ragdollInput = msg.ReadBoolean();
                    keys[(int)InputType.Ragdoll].Held = ragdollInput;
                    keys[(int)InputType.Ragdoll].SetState(false, ragdollInput);

                    facingRight = msg.ReadBoolean();
                }

                bool      entitySelected    = msg.ReadBoolean();
                Character selectedCharacter = null;
                Item      selectedItem      = null;

                AnimController.Animation animation = AnimController.Animation.None;
                if (entitySelected)
                {
                    ushort characterID = msg.ReadUInt16();
                    ushort itemID      = msg.ReadUInt16();
                    selectedCharacter = FindEntityByID(characterID) as Character;
                    selectedItem      = FindEntityByID(itemID) as Item;
                    if (characterID != NullEntityID)
                    {
                        bool doingCpr = msg.ReadBoolean();
                        if (doingCpr && SelectedCharacter != null)
                        {
                            animation = AnimController.Animation.CPR;
                        }
                    }
                }

                Vector2 pos = new Vector2(
                    msg.ReadSingle(),
                    msg.ReadSingle());
                float   MaxVel         = NetConfig.MaxPhysicsBodyVelocity;
                Vector2 linearVelocity = new Vector2(
                    msg.ReadRangedSingle(-MaxVel, MaxVel, 12),
                    msg.ReadRangedSingle(-MaxVel, MaxVel, 12));
                linearVelocity = NetConfig.Quantize(linearVelocity, -MaxVel, MaxVel, 12);

                bool  fixedRotation   = msg.ReadBoolean();
                float?rotation        = null;
                float?angularVelocity = null;
                if (!fixedRotation)
                {
                    rotation = msg.ReadSingle();
                    float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;
                    angularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8);
                    angularVelocity = NetConfig.Quantize(angularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8);
                }

                bool readStatus = msg.ReadBoolean();
                if (readStatus)
                {
                    ReadStatus(msg);
                    AIController?.ClientRead(msg);
                }

                msg.ReadPadBits();

                int index = 0;
                if (GameMain.Client.Character == this && CanMove)
                {
                    var posInfo = new CharacterStateInfo(
                        pos, rotation,
                        networkUpdateID,
                        facingRight ? Direction.Right : Direction.Left,
                        selectedCharacter, selectedItem, animation);

                    while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID))
                    {
                        index++;
                    }
                    memState.Insert(index, posInfo);
                }
                else
                {
                    var posInfo = new CharacterStateInfo(
                        pos, rotation,
                        linearVelocity, angularVelocity,
                        sendingTime, facingRight ? Direction.Right : Direction.Left,
                        selectedCharacter, selectedItem, animation);

                    while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp)
                    {
                        index++;
                    }
                    memState.Insert(index, posInfo);
                }

                break;

            case ServerNetObject.ENTITY_EVENT:
                int eventType = msg.ReadRangedInteger(0, 13);
                switch (eventType)
                {
                case 0:         //NetEntityEvent.Type.InventoryState
                    if (Inventory == null)
                    {
                        string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ", removed: " + Removed + ")";
                        DebugConsole.ThrowError(errorMsg);
                        GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);

                        //read anyway to prevent messing up reading the rest of the message
                        _ = msg.ReadUInt16();
                        byte inventoryItemCount = msg.ReadByte();
                        for (int i = 0; i < inventoryItemCount; i++)
                        {
                            msg.ReadUInt16();
                        }
                    }
                    else
                    {
                        Inventory.ClientRead(type, msg, sendingTime);
                    }
                    break;

                case 1:         //NetEntityEvent.Type.Control
                    byte ownerID = msg.ReadByte();
                    ResetNetState();
                    if (ownerID == GameMain.Client.ID)
                    {
                        if (controlled != null)
                        {
                            LastNetworkUpdateID = controlled.LastNetworkUpdateID;
                        }

                        if (!IsDead)
                        {
                            Controlled = this;
                        }
                        IsRemotePlayer                          = false;
                        GameMain.Client.HasSpawned              = true;
                        GameMain.Client.Character               = this;
                        GameMain.LightManager.LosEnabled        = true;
                        GameMain.LightManager.LosAlpha          = 1f;
                        GameMain.Client.WaitForNextRoundRespawn = null;
                    }
                    else
                    {
                        if (controlled == this)
                        {
                            Controlled     = null;
                            IsRemotePlayer = ownerID > 0;
                        }
                    }
                    break;

                case 2:         //NetEntityEvent.Type.Status
                    ReadStatus(msg);
                    break;

                case 3:         //NetEntityEvent.Type.UpdateSkills
                    int skillCount = msg.ReadByte();
                    for (int i = 0; i < skillCount; i++)
                    {
                        string skillIdentifier = msg.ReadString();
                        float  skillLevel      = msg.ReadSingle();
                        info?.SetSkillLevel(skillIdentifier, skillLevel);
                    }
                    break;

                case 4:         // NetEntityEvent.Type.SetAttackTarget
                case 5:         //NetEntityEvent.Type.ExecuteAttack
                    int     attackLimbIndex = msg.ReadByte();
                    UInt16  targetEntityID  = msg.ReadUInt16();
                    int     targetLimbIndex = msg.ReadByte();
                    Vector2 targetSimPos    = new Vector2(msg.ReadSingle(), msg.ReadSingle());
                    //255 = entity already removed, no need to do anything
                    if (attackLimbIndex == 255 || Removed)
                    {
                        break;
                    }
                    if (attackLimbIndex >= AnimController.Limbs.Length)
                    {
                        DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})");
                        break;
                    }
                    Limb attackLimb = AnimController.Limbs[attackLimbIndex];
                    Limb targetLimb = null;
                    if (!(FindEntityByID(targetEntityID) is IDamageable targetEntity))
                    {
                        DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Target entity not found (ID {targetEntityID})");
                        break;
                    }
                    if (targetEntity is Character targetCharacter)
                    {
                        if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length)
                        {
                            DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})");
                            break;
                        }
                        targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex];
                    }
                    if (attackLimb?.attack != null && Controlled != this)
                    {
                        if (eventType == 4)
                        {
                            SetAttackTarget(attackLimb, targetEntity, targetSimPos);
                            PlaySound(CharacterSound.SoundType.Attack, maxInterval: 3);
                        }
                        else
                        {
                            attackLimb.ExecuteAttack(targetEntity, targetLimb, out _);
                        }
                    }
                    break;

                case 6:         //NetEntityEvent.Type.AssignCampaignInteraction
                    byte campaignInteractionType = msg.ReadByte();
                    bool requireConsciousness    = msg.ReadBoolean();
                    (GameMain.GameSession?.GameMode as CampaignMode)?.AssignNPCMenuInteraction(this, (CampaignMode.InteractionType)campaignInteractionType);
                    RequireConsciousnessForCustomInteract = requireConsciousness;
                    break;

                case 7:         //NetEntityEvent.Type.ObjectiveManagerState
                    // 1 = order, 2 = objective
                    int msgType = msg.ReadRangedInteger(0, 2);
                    if (msgType == 0)
                    {
                        break;
                    }
                    bool validData = msg.ReadBoolean();
                    if (!validData)
                    {
                        break;
                    }
                    if (msgType == 1)
                    {
                        int    orderIndex  = msg.ReadRangedInteger(0, Order.PrefabList.Count);
                        var    orderPrefab = Order.PrefabList[orderIndex];
                        string option      = null;
                        if (orderPrefab.HasOptions)
                        {
                            int optionIndex = msg.ReadRangedInteger(-1, orderPrefab.AllOptions.Length);
                            if (optionIndex > -1)
                            {
                                option = orderPrefab.AllOptions[optionIndex];
                            }
                        }
                        GameMain.GameSession?.CrewManager?.SetOrderHighlight(this, orderPrefab.Identifier, option);
                    }
                    else if (msgType == 2)
                    {
                        string identifier = msg.ReadString();
                        string option     = msg.ReadString();
                        ushort objectiveTargetEntityId = msg.ReadUInt16();
                        var    objectiveTargetEntity   = FindEntityByID(objectiveTargetEntityId);
                        GameMain.GameSession?.CrewManager?.CreateObjectiveIcon(this, identifier, option, objectiveTargetEntity);
                    }
                    break;

                case 8:         //NetEntityEvent.Type.TeamChange
                    byte newTeamId = msg.ReadByte();
                    ChangeTeam((CharacterTeamType)newTeamId);
                    break;

                case 9:         //NetEntityEvent.Type.AddToCrew
                    GameMain.GameSession.CrewManager.AddCharacter(this);
                    CharacterTeamType teamID    = (CharacterTeamType)msg.ReadByte();
                    ushort            itemCount = msg.ReadUInt16();
                    for (int i = 0; i < itemCount; i++)
                    {
                        ushort itemID = msg.ReadUInt16();
                        if (!(Entity.FindEntityByID(itemID) is Item item))
                        {
                            continue;
                        }
                        item.AllowStealing = true;
                        var wifiComponent = item.GetComponent <WifiComponent>();
                        if (wifiComponent != null)
                        {
                            wifiComponent.TeamID = teamID;
                        }
                        var idCard = item.GetComponent <IdCard>();
                        if (idCard != null)
                        {
                            idCard.TeamID = teamID;
                            idCard.SubmarineSpecificID = 0;
                        }
                    }
                    break;

                case 10:         //NetEntityEvent.Type.UpdateExperience
                    int experienceAmount = msg.ReadInt32();
                    info?.SetExperience(experienceAmount);
                    break;

                case 11:         //NetEntityEvent.Type.UpdateTalents:
                    ushort talentCount = msg.ReadUInt16();
                    for (int i = 0; i < talentCount; i++)
                    {
                        bool   addedThisRound   = msg.ReadBoolean();
                        UInt32 talentIdentifier = msg.ReadUInt32();
                        GiveTalent(talentIdentifier, addedThisRound);
                    }
                    break;

                case 12:         //NetEntityEvent.Type.UpdateMoney:
                    int moneyAmount = msg.ReadInt32();
                    SetMoney(moneyAmount);
                    break;

                case 13:         //NetEntityEvent.Type.UpdatePermanentStats:
                    byte      savedStatValueCount = msg.ReadByte();
                    StatTypes statType            = (StatTypes)msg.ReadByte();
                    info?.ClearSavedStatValues(statType);
                    for (int i = 0; i < savedStatValueCount; i++)
                    {
                        string statIdentifier = msg.ReadString();
                        float  statValue      = msg.ReadSingle();
                        bool   removeOnDeath  = msg.ReadBoolean();
                        info?.ChangeSavedStatValue(statType, statValue, statIdentifier, removeOnDeath, setValue: true);
                    }
                    break;
                }
                msg.ReadPadBits();
                break;
            }
        }
        public virtual void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
        {
            switch (type)
            {
            case ServerNetObject.ENTITY_POSITION:
                bool facingRight = AnimController.Dir > 0.0f;

                lastRecvPositionUpdateTime = (float)Lidgren.Network.NetTime.Now;

                AnimController.Frozen = false;
                Enabled = true;

                UInt16 networkUpdateID = 0;
                if (msg.ReadBoolean())
                {
                    networkUpdateID = msg.ReadUInt16();
                }
                else
                {
                    bool aimInput = msg.ReadBoolean();
                    keys[(int)InputType.Aim].Held = aimInput;
                    keys[(int)InputType.Aim].SetState(false, aimInput);

                    bool shootInput = msg.ReadBoolean();
                    keys[(int)InputType.Shoot].Held = shootInput;
                    keys[(int)InputType.Shoot].SetState(false, shootInput);

                    bool useInput = msg.ReadBoolean();
                    keys[(int)InputType.Use].Held = useInput;
                    keys[(int)InputType.Use].SetState(false, useInput);

                    if (AnimController is HumanoidAnimController)
                    {
                        bool crouching = msg.ReadBoolean();
                        keys[(int)InputType.Crouch].Held = crouching;
                        keys[(int)InputType.Crouch].SetState(false, crouching);
                    }

                    bool attackInput = msg.ReadBoolean();
                    keys[(int)InputType.Attack].Held = attackInput;
                    keys[(int)InputType.Attack].SetState(false, attackInput);

                    double aimAngle = msg.ReadUInt16() / 65535.0 * 2.0 * Math.PI;
                    cursorPosition = AimRefPosition + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 500.0f;
                    TransformCursorPos();

                    bool ragdollInput = msg.ReadBoolean();
                    keys[(int)InputType.Ragdoll].Held = ragdollInput;
                    keys[(int)InputType.Ragdoll].SetState(false, ragdollInput);

                    facingRight = msg.ReadBoolean();
                }

                bool      entitySelected    = msg.ReadBoolean();
                Character selectedCharacter = null;
                Item      selectedItem      = null;

                AnimController.Animation animation = AnimController.Animation.None;
                if (entitySelected)
                {
                    ushort characterID = msg.ReadUInt16();
                    ushort itemID      = msg.ReadUInt16();
                    selectedCharacter = FindEntityByID(characterID) as Character;
                    selectedItem      = FindEntityByID(itemID) as Item;
                    if (characterID != NullEntityID)
                    {
                        bool doingCpr = msg.ReadBoolean();
                        if (doingCpr && SelectedCharacter != null)
                        {
                            animation = AnimController.Animation.CPR;
                        }
                    }
                }

                Vector2 pos = new Vector2(
                    msg.ReadSingle(),
                    msg.ReadSingle());
                float   MaxVel         = NetConfig.MaxPhysicsBodyVelocity;
                Vector2 linearVelocity = new Vector2(
                    msg.ReadRangedSingle(-MaxVel, MaxVel, 12),
                    msg.ReadRangedSingle(-MaxVel, MaxVel, 12));
                linearVelocity = NetConfig.Quantize(linearVelocity, -MaxVel, MaxVel, 12);

                bool  fixedRotation   = msg.ReadBoolean();
                float?rotation        = null;
                float?angularVelocity = null;
                if (!fixedRotation)
                {
                    rotation = msg.ReadSingle();
                    float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;
                    angularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8);
                    angularVelocity = NetConfig.Quantize(angularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8);
                }

                bool readStatus = msg.ReadBoolean();
                if (readStatus)
                {
                    ReadStatus(msg);
                }

                msg.ReadPadBits();

                int index = 0;
                if (GameMain.Client.Character == this && AllowInput)
                {
                    var posInfo = new CharacterStateInfo(
                        pos, rotation,
                        networkUpdateID,
                        facingRight ? Direction.Right : Direction.Left,
                        selectedCharacter, selectedItem, animation);

                    while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID))
                    {
                        index++;
                    }
                    memState.Insert(index, posInfo);
                }
                else
                {
                    var posInfo = new CharacterStateInfo(
                        pos, rotation,
                        linearVelocity, angularVelocity,
                        sendingTime, facingRight ? Direction.Right : Direction.Left,
                        selectedCharacter, selectedItem, animation);

                    while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp)
                    {
                        index++;
                    }
                    memState.Insert(index, posInfo);
                }

                break;

            case ServerNetObject.ENTITY_EVENT:

                int eventType = msg.ReadRangedInteger(0, 3);
                switch (eventType)
                {
                case 0:
                    if (Inventory == null)
                    {
                        string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ", removed: " + Removed + ")";
                        DebugConsole.ThrowError(errorMsg);
                        GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);

                        //read anyway to prevent messing up reading the rest of the message
                        byte itemCount = msg.ReadByte();
                        for (int i = 0; i < itemCount; i++)
                        {
                            msg.ReadUInt16();
                        }
                    }
                    else
                    {
                        Inventory.ClientRead(type, msg, sendingTime);
                    }
                    break;

                case 1:
                    byte ownerID = msg.ReadByte();
                    ResetNetState();
                    if (ownerID == GameMain.Client.ID)
                    {
                        if (controlled != null)
                        {
                            LastNetworkUpdateID = controlled.LastNetworkUpdateID;
                        }

                        Controlled                       = this;
                        IsRemotePlayer                   = false;
                        GameMain.Client.HasSpawned       = true;
                        GameMain.Client.Character        = this;
                        GameMain.LightManager.LosEnabled = true;
                    }
                    else
                    {
                        if (controlled == this)
                        {
                            Controlled     = null;
                            IsRemotePlayer = ownerID > 0;
                        }
                    }
                    break;

                case 2:
                    ReadStatus(msg);
                    break;

                case 3:
                    int skillCount = msg.ReadByte();
                    for (int i = 0; i < skillCount; i++)
                    {
                        string skillIdentifier = msg.ReadString();
                        float  skillLevel      = msg.ReadSingle();
                        info?.SetSkillLevel(skillIdentifier, skillLevel, WorldPosition + Vector2.UnitY * 150.0f);
                    }
                    break;
                }
                msg.ReadPadBits();
                break;
            }
        }
        private void ReadConnectionInitializationStep(IReadMessage inc)
        {
            if (!isActive)
            {
                return;
            }

            ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();

            //DebugConsole.NewMessage(step + " " + initializationStep);
            switch (step)
            {
            case ConnectionInitialization.SteamTicketAndVersion:
                if (initializationStep != ConnectionInitialization.SteamTicketAndVersion)
                {
                    return;
                }
                IWriteMessage outMsg = new WriteOnlyMessage();
                outMsg.Write((byte)DeliveryMethod.Reliable);
                outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
                outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
                outMsg.Write(Name);
                outMsg.Write(SteamManager.GetSteamID());
                outMsg.Write((UInt16)steamAuthTicket.Data.Length);
                outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);

                outMsg.Write(GameMain.Version.ToString());

                IEnumerable <ContentPackage> mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
                outMsg.WriteVariableUInt32((UInt32)mpContentPackages.Count());
                foreach (ContentPackage contentPackage in mpContentPackages)
                {
                    outMsg.Write(contentPackage.Name);
                    outMsg.Write(contentPackage.MD5hash.Hash);
                }

                heartbeatTimer = 5.0;
                SteamManager.Instance.Networking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes,
                                                               Facepunch.Steamworks.Networking.SendType.Reliable);
                break;

            case ConnectionInitialization.Password:
                if (initializationStep == ConnectionInitialization.SteamTicketAndVersion)
                {
                    initializationStep = ConnectionInitialization.Password;
                }
                if (initializationStep != ConnectionInitialization.Password)
                {
                    return;
                }
                bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
                int  retries      = 0;
                if (incomingSalt)
                {
                    passwordSalt = inc.ReadInt32();
                }
                else
                {
                    retries = inc.ReadInt32();
                }
                OnRequestPassword?.Invoke(passwordSalt, retries);
                break;
            }
        }
        /// <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);
        }
Example #28
0
        /// <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 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++)
            {
                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;
                }

                byte msgLength = msg.ReadByte();

                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))
                                    ? Microsoft.Xna.Framework.Color.Red
                                    : Microsoft.Xna.Framework.Color.Yellow);
                        }
                    }
                    else if (entity == null)
                    {
                        DebugConsole.NewMessage(
                            "Received msg " + thisEventID + ", entity " + entityID + " not found",
                            Microsoft.Xna.Framework.Color.Red);
                        GameMain.Client.ReportError(ClientNetError.MISSING_ENTITY, eventID: thisEventID, entityID: entityID);
                        return(false);
                    }

                    msg.BitPosition += msgLength * 8;
                }
                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);
                    }

                    catch (Exception e)
                    {
                        string errorMsg = "Failed to read event for entity \"" + entity.ToString() + "\" (" + e.Message + ")! (MidRoundSyncing: " + thisClient.MidRoundSyncing + ")\n" + e.StackTrace;
                        errorMsg += "\nPrevious entities:";
                        for (int j = entities.Count - 2; j >= 0; j--)
                        {
                            errorMsg += "\n" + (entities[j] == null ? "NULL" : entities[j].ToString());
                        }

                        if (GameSettings.VerboseLogging)
                        {
                            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);
        }