Ejemplo n.º 1
0
        public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
        {
            bool isDocked = msg.ReadBoolean();

            for (int i = 0; i < 2; i++)
            {
                if (hulls[i] == null)
                {
                    continue;
                }
                item.linkedTo.Remove(hulls[i]);
                hulls[i].Remove();
                hulls[i] = null;
            }

            if (gap != null)
            {
                item.linkedTo.Remove(gap);
                gap.Remove();
                gap = null;
            }

            if (isDocked)
            {
                ushort dockingTargetID = msg.ReadUInt16();

                bool isLocked = msg.ReadBoolean();

                Entity targetEntity = Entity.FindEntityByID(dockingTargetID);
                if (targetEntity == null || !(targetEntity is Item))
                {
                    DebugConsole.ThrowError("Invalid docking port network event (can't dock to " + (targetEntity?.ToString() ?? "null") + ")");
                    return;
                }

                DockingTarget = (targetEntity as Item).GetComponent <DockingPort>();
                if (DockingTarget == null)
                {
                    DebugConsole.ThrowError("Invalid docking port network event (" + targetEntity + " doesn't have a docking port component)");
                    return;
                }

                Dock(DockingTarget);
                if (joint == null)
                {
                    string errorMsg = "Error while reading a docking port network event (Dock method did not create a joint between the ports)." +
                                      " Submarine: " + (item.Submarine?.Info.Name ?? "null") +
                                      ", target submarine: " + (DockingTarget.item.Submarine?.Info.Name ?? "null");
                    if (item.Submarine?.ConnectedDockingPorts.ContainsKey(DockingTarget.item.Submarine) ?? false)
                    {
                        errorMsg += "\nAlready docked.";
                    }
                    if (item.Submarine == DockingTarget.item.Submarine)
                    {
                        errorMsg += "\nTrying to dock the submarine to itself.";
                    }
                    GameAnalyticsManager.AddErrorEventOnce("DockingPort.ClientRead:JointNotCreated", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
                }

                if (isLocked)
                {
                    if (DockingTarget.joint != null)
                    {
                        DockingTarget.Lock(isNetworkMessage: true);
                    }
                    else
                    {
                        Lock(isNetworkMessage: true);
                    }
                }
            }
            else
            {
                Undock();
            }
        }
Ejemplo n.º 2
0
        public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
        {
            List <Item> prevItems = new List <Item>(Items);

            byte itemCount = msg.ReadByte();

            ushort[] newItemIDs = new ushort[itemCount];
            for (int i = 0; i < itemCount; i++)
            {
                newItemIDs[i] = msg.ReadUInt16();
            }

            if (c == null || c.Character == null)
            {
                return;
            }

            bool accessible = c.Character.CanAccessInventory(this);

            if (this is CharacterInventory && accessible)
            {
                if (Owner == null || !(Owner is Character))
                {
                    accessible = false;
                }
                else if (!((CharacterInventory)this).AccessibleWhenAlive && !((Character)Owner).IsDead)
                {
                    accessible = false;
                }
            }

            if (!accessible)
            {
                //create a network event to correct the client's inventory state
                //otherwise they may have an item in their inventory they shouldn't have been able to pick up,
                //and receiving an event for that inventory later will cause the item to be dropped
                CreateNetworkEvent();
                for (int i = 0; i < capacity; i++)
                {
                    if (!(Entity.FindEntityByID(newItemIDs[i]) is Item item))
                    {
                        continue;
                    }
                    item.PositionUpdateInterval = 0.0f;
                    if (item.ParentInventory != null && item.ParentInventory != this)
                    {
                        item.ParentInventory.CreateNetworkEvent();
                    }
                }
                return;
            }

            List <Inventory> prevItemInventories = new List <Inventory>(Items.Select(i => i?.ParentInventory));

            for (int i = 0; i < capacity; i++)
            {
                Item newItem = newItemIDs[i] == 0 ? null : Entity.FindEntityByID(newItemIDs[i]) as Item;
                prevItemInventories.Add(newItem?.ParentInventory);

                if (newItemIDs[i] == 0 || (newItem != Items[i]))
                {
                    if (Items[i] != null)
                    {
                        Item   droppedItem = Items[i];
                        Entity prevOwner   = Owner;
                        droppedItem.Drop(null);

                        var previousInventory = prevOwner switch
                        {
                            Item itemInventory => (itemInventory.FindParentInventory(inventory => inventory is CharacterInventory) as CharacterInventory),
                            Character character => character.Inventory,
                            _ => null
                        };

                        if (previousInventory != null && previousInventory != c.Character?.Inventory)
                        {
                            GameMain.Server?.KarmaManager.OnItemTakenFromPlayer(previousInventory, c, droppedItem);
                        }

                        if (droppedItem.body != null && prevOwner != null)
                        {
                            droppedItem.body.SetTransform(prevOwner.SimPosition, 0.0f);
                        }
                    }
                    System.Diagnostics.Debug.Assert(Items[i] == null);
                }
            }

            for (int i = 0; i < capacity; i++)
            {
                if (newItemIDs[i] > 0)
                {
                    if (!(Entity.FindEntityByID(newItemIDs[i]) is Item item) || item == Items[i])
                    {
                        continue;
                    }

                    if (GameMain.Server != null)
                    {
                        var holdable = item.GetComponent <Holdable>();
                        if (holdable != null && !holdable.CanBeDeattached())
                        {
                            continue;
                        }

                        if (!prevItems.Contains(item) && !item.CanClientAccess(c))
                        {
                            if (item.body != null && !c.PendingPositionUpdates.Contains(item))
                            {
                                c.PendingPositionUpdates.Enqueue(item);
                            }
                            item.PositionUpdateInterval = 0.0f;
                            continue;
                        }
                    }
                    TryPutItem(item, i, true, true, c.Character, false);
                    for (int j = 0; j < capacity; j++)
                    {
                        if (Items[j] == item && newItemIDs[j] != item.ID)
                        {
                            Items[j] = null;
                        }
                    }
                }
            }

            CreateNetworkEvent();
            foreach (Inventory prevInventory in prevItemInventories.Distinct())
            {
                if (prevInventory != this)
                {
                    prevInventory?.CreateNetworkEvent();
                }
            }

            foreach (Item item in Items.Distinct())
            {
                if (item == null)
                {
                    continue;
                }
                if (!prevItems.Contains(item))
                {
                    if (Owner == c.Character)
                    {
                        GameServer.Log(GameServer.CharacterLogName(c.Character) + " picked up " + item.Name, ServerLog.MessageType.Inventory);
                    }
                    else
                    {
                        GameServer.Log(GameServer.CharacterLogName(c.Character) + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory);
                    }
                }
            }
            foreach (Item item in prevItems.Distinct())
            {
                if (item == null)
                {
                    continue;
                }
                if (!Items.Contains(item))
                {
                    if (Owner == c.Character)
                    {
                        GameServer.Log(GameServer.CharacterLogName(c.Character) + " dropped " + item.Name, ServerLog.MessageType.Inventory);
                    }
                    else
                    {
                        GameServer.Log(GameServer.CharacterLogName(c.Character) + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory);
                    }
                }
            }
        }
Ejemplo n.º 3
0
        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;
                }
                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 (IsUnconscious)
                    {
                        var causeOfDeath = CharacterHealth.GetCauseOfDeath();
                        Kill(causeOfDeath.First, causeOfDeath.Second);
                    }
                    break;
                }
                break;
            }
            msg.ReadPadBits();
        }
Ejemplo n.º 4
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;
            bool      hasSenderCharacter = msg.ReadBoolean();

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

            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());
                int       optionIndex       = msg.ReadByte();

                Order order = null;
                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
                {
                    order = Order.PrefabList[orderIndex];
                }
                string orderOption = "";
                if (optionIndex >= 0 && optionIndex < order.Options.Length)
                {
                    orderOption = order.Options[optionIndex];
                }
                txt = order.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption);

                if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
                {
                    if (order.TargetAllCharacters)
                    {
                        GameMain.GameSession?.CrewManager?.AddOrder(
                            new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: senderCharacter),
                            order.Prefab.FadeOutTime);
                    }
                    else if (targetCharacter != null)
                    {
                        targetCharacter.SetOrder(
                            new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: senderCharacter),
                            orderOption, senderCharacter);
                    }
                }

                if (NetIdUtils.IdMoreRecent(ID, LastID))
                {
                    GameMain.Client.AddChatMessage(
                        new OrderChatMessage(order, orderOption, txt, targetEntity, 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, senderCharacter, changeType);
                    break;
                }
                LastID = ID;
            }
        }
Ejemplo n.º 5
0
        public void ReadMessage(IReadMessage inc)
        {
            System.Diagnostics.Debug.Assert(!activeTransfers.Any(t =>
                                                                 t.Status == FileTransferStatus.Error ||
                                                                 t.Status == FileTransferStatus.Canceled ||
                                                                 t.Status == FileTransferStatus.Finished), "List of active file transfers contains entires that should have been removed");

            byte transferMessageType = inc.ReadByte();

            switch (transferMessageType)
            {
            case (byte)FileTransferMessageType.Initiate:
            {
                byte transferId       = inc.ReadByte();
                var  existingTransfer = activeTransfers.Find(t => t.ID == transferId);
                finishedTransfers.RemoveAll(t => t.First == transferId);
                byte fileType = inc.ReadByte();
                //ushort chunkLen = inc.ReadUInt16();
                int    fileSize = inc.ReadInt32();
                string fileName = inc.ReadString();

                if (existingTransfer != null)
                {
                    if (fileType != (byte)existingTransfer.FileType ||
                        fileSize != existingTransfer.FileSize ||
                        fileName != existingTransfer.FileName)
                    {
                        GameMain.Client.CancelFileTransfer(transferId);
                        DebugConsole.ThrowError("File transfer error: file transfer initiated with an ID that's already in use");
                    }
                    else         //resend acknowledgement packet
                    {
                        GameMain.Client.UpdateFileTransfer(transferId, 0);
                    }
                    return;
                }

                if (!ValidateInitialData(fileType, fileName, fileSize, out string errorMsg))
                {
                    GameMain.Client.CancelFileTransfer(transferId);
                    DebugConsole.ThrowError("File transfer failed (" + errorMsg + ")");
                    return;
                }

                if (GameSettings.VerboseLogging)
                {
                    DebugConsole.Log("Received file transfer initiation message: ");
                    DebugConsole.Log("  File: " + fileName);
                    DebugConsole.Log("  Size: " + fileSize);
                    DebugConsole.Log("  ID: " + transferId);
                }

                string downloadFolder = downloadFolders[(FileTransferType)fileType];
                if (!Directory.Exists(downloadFolder))
                {
                    try
                    {
                        Directory.CreateDirectory(downloadFolder);
                    }
                    catch (Exception e)
                    {
                        DebugConsole.ThrowError("Could not start a file transfer: failed to create the folder \"" + downloadFolder + "\".", e);
                        return;
                    }
                }

                FileTransferIn newTransfer = new FileTransferIn(inc.Sender, Path.Combine(downloadFolder, fileName), (FileTransferType)fileType)
                {
                    ID       = transferId,
                    Status   = FileTransferStatus.Receiving,
                    FileSize = fileSize
                };

                int maxRetries = 4;
                for (int i = 0; i <= maxRetries; i++)
                {
                    try
                    {
                        newTransfer.OpenStream();
                    }
                    catch (IOException e)
                    {
                        if (i < maxRetries)
                        {
                            DebugConsole.NewMessage("Failed to initiate a file transfer {" + e.Message + "}, retrying in 250 ms...", Color.Red);
                            Thread.Sleep(250);
                        }
                        else
                        {
                            DebugConsole.NewMessage("Failed to initiate a file transfer {" + e.Message + "}", Color.Red);
                            GameMain.Client.CancelFileTransfer(transferId);
                            newTransfer.Status = FileTransferStatus.Error;
                            OnTransferFailed(newTransfer);
                            return;
                        }
                    }
                }
                activeTransfers.Add(newTransfer);

                GameMain.Client.UpdateFileTransfer(transferId, 0);         //send acknowledgement packet
            }
            break;

            case (byte)FileTransferMessageType.TransferOnSameMachine:
            {
                byte   transferId = inc.ReadByte();
                byte   fileType   = inc.ReadByte();
                string filePath   = inc.ReadString();

                if (GameSettings.VerboseLogging)
                {
                    DebugConsole.Log("Received file transfer message on the same machine: ");
                    DebugConsole.Log("  File: " + filePath);
                    DebugConsole.Log("  ID: " + transferId);
                }

                if (!File.Exists(filePath))
                {
                    DebugConsole.ThrowError("File transfer on the same machine failed, file \"" + filePath + "\" not found.");
                    GameMain.Client.CancelFileTransfer(transferId);
                    return;
                }

                FileTransferIn directTransfer = new FileTransferIn(inc.Sender, filePath, (FileTransferType)fileType)
                {
                    ID       = transferId,
                    Status   = FileTransferStatus.Finished,
                    FileSize = 0
                };

                Md5Hash.RemoveFromCache(directTransfer.FilePath);
                OnFinished(directTransfer);
            }
            break;

            case (byte)FileTransferMessageType.Data:
            {
                byte transferId = inc.ReadByte();

                var activeTransfer = activeTransfers.Find(t => t.Connection == inc.Sender && t.ID == transferId);
                if (activeTransfer == null)
                {
                    //it's possible for the server to send some extra data
                    //before it acknowledges that the download is finished,
                    //so let's suppress the error message in that case
                    finishedTransfers.RemoveAll(t => t.Second + 5.0 < Timing.TotalTime);
                    if (!finishedTransfers.Any(t => t.First == transferId))
                    {
                        GameMain.Client.CancelFileTransfer(transferId);
                        DebugConsole.ThrowError("File transfer error: received data without a transfer initiation message");
                    }
                    return;
                }

                int offset = inc.ReadInt32();
                if (offset != activeTransfer.Received)
                {
                    if (offset < activeTransfer.Received)
                    {
                        GameMain.Client.UpdateFileTransfer(activeTransfer.ID, activeTransfer.Received);
                    }
                    return;
                }

                int bytesToRead = inc.ReadUInt16();

                if (activeTransfer.Received + bytesToRead > activeTransfer.FileSize)
                {
                    GameMain.Client.CancelFileTransfer(transferId);
                    DebugConsole.ThrowError("File transfer error: Received more data than expected (total received: " + activeTransfer.Received +
                                            ", msg received: " + (inc.LengthBytes - inc.BytePosition) +
                                            ", msg length: " + inc.LengthBytes +
                                            ", msg read: " + inc.BytePosition +
                                            ", filesize: " + activeTransfer.FileSize);
                    activeTransfer.Status = FileTransferStatus.Error;
                    StopTransfer(activeTransfer);
                    return;
                }

                try
                {
                    activeTransfer.ReadBytes(inc, bytesToRead);
                }
                catch (Exception e)
                {
                    GameMain.Client.CancelFileTransfer(transferId);
                    DebugConsole.ThrowError("File transfer error: " + e.Message);
                    activeTransfer.Status = FileTransferStatus.Error;
                    StopTransfer(activeTransfer, true);
                    return;
                }

                if (activeTransfer.Status == FileTransferStatus.Finished)
                {
                    GameMain.Client.UpdateFileTransfer(activeTransfer.ID, activeTransfer.Received, true);
                    activeTransfer.Dispose();

                    if (ValidateReceivedData(activeTransfer, out string errorMessage))
                    {
                        finishedTransfers.Add(new Pair <int, double>(transferId, Timing.TotalTime));
                        StopTransfer(activeTransfer);
                        Md5Hash.RemoveFromCache(activeTransfer.FilePath);
                        OnFinished(activeTransfer);
                    }
                    else
                    {
                        new GUIMessageBox("File transfer aborted", errorMessage);

                        activeTransfer.Status = FileTransferStatus.Error;
                        StopTransfer(activeTransfer, true);
                    }
                }
            }
            break;

            case (byte)FileTransferMessageType.Cancel:
            {
                byte transferId       = inc.ReadByte();
                var  matchingTransfer = activeTransfers.Find(t => t.Connection == inc.Sender && t.ID == transferId);
                if (matchingTransfer != null)
                {
                    new GUIMessageBox("File transfer cancelled", "The server has cancelled the transfer of the file \"" + matchingTransfer.FileName + "\".");
                    StopTransfer(matchingTransfer);
                }
                break;
            }
            }
        }
Ejemplo n.º 6
0
        public static Character ReadSpawnData(IReadMessage inc, bool spawn = true)
        {
            DebugConsole.Log("Reading character spawn data");

            if (GameMain.Client == null)
            {
                return(null);
            }

            bool   noInfo      = inc.ReadBoolean();
            ushort id          = inc.ReadUInt16();
            string speciesName = inc.ReadString();
            string seed        = inc.ReadString();

            Vector2 position = new Vector2(inc.ReadSingle(), inc.ReadSingle());

            bool enabled = inc.ReadBoolean();

            DebugConsole.Log("Received spawn data for " + speciesName);

            Character character = null;

            if (noInfo)
            {
                if (!spawn)
                {
                    return(null);
                }

                character    = Create(speciesName, position, seed, null, true);
                character.ID = id;
            }
            else
            {
                bool   hasOwner        = inc.ReadBoolean();
                int    ownerId         = hasOwner ? inc.ReadByte() : -1;
                byte   teamID          = inc.ReadByte();
                bool   hasAi           = inc.ReadBoolean();
                string infoSpeciesName = inc.ReadString();

                if (!spawn)
                {
                    return(null);
                }

                CharacterInfo info = CharacterInfo.ClientRead(infoSpeciesName, inc);

                character        = Create(infoSpeciesName, position, seed, info, GameMain.Client.ID != ownerId, hasAi);
                character.ID     = id;
                character.TeamID = (TeamType)teamID;

                if (character.IsHuman && character.TeamID != TeamType.FriendlyNPC)
                {
                    CharacterInfo duplicateCharacterInfo = GameMain.GameSession.CrewManager.GetCharacterInfos().FirstOrDefault(c => c.ID == info.ID);
                    GameMain.GameSession.CrewManager.RemoveCharacterInfo(duplicateCharacterInfo);
                    GameMain.GameSession.CrewManager.AddCharacter(character);
                }

                if (GameMain.Client.ID == ownerId)
                {
                    GameMain.Client.HasSpawned = true;
                    GameMain.Client.Character  = character;
                    Controlled = character;

                    GameMain.LightManager.LosEnabled = true;

                    character.memInput.Clear();
                    character.memState.Clear();
                    character.memLocalState.Clear();
                }
            }

            character.Enabled = Controlled == character || enabled;

            return(character);
        }
Ejemplo n.º 7
0
        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 && 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, 4);
                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
                        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:
                    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:
                    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;

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

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

                    if (attackLimbIndex >= AnimController.Limbs.Length)
                    {
                        DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Limb index out of bounds ({attackLimbIndex})");
                        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 ({targetLimbIndex})");
                            break;
                        }
                        targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex];
                    }
                    if (attackLimb?.attack != null)
                    {
                        attackLimb.ExecuteAttack(targetEntity, targetLimb, out _);
                    }
                    break;
                }
                msg.ReadPadBits();
                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 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;
                    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;
                        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);
        }
Ejemplo n.º 9
0
        //static because we may need to instantiate the campaign if it hasn't been done yet
        public static void ClientRead(IReadMessage msg)
        {
            byte   campaignID           = msg.ReadByte();
            UInt16 updateID             = msg.ReadUInt16();
            UInt16 saveID               = msg.ReadUInt16();
            string mapSeed              = msg.ReadString();
            UInt16 currentLocIndex      = msg.ReadUInt16();
            UInt16 selectedLocIndex     = msg.ReadUInt16();
            byte   selectedMissionIndex = msg.ReadByte();

            UInt16 startWatchmanID = msg.ReadUInt16();
            UInt16 endWatchmanID   = msg.ReadUInt16();

            int  money = msg.ReadInt32();
            bool purchasedHullRepairs  = msg.ReadBoolean();
            bool purchasedItemRepairs  = msg.ReadBoolean();
            bool purchasedLostShuttles = msg.ReadBoolean();

            UInt16 purchasedItemCount           = msg.ReadUInt16();
            List <PurchasedItem> purchasedItems = new List <PurchasedItem>();

            for (int i = 0; i < purchasedItemCount; i++)
            {
                string itemPrefabIdentifier = msg.ReadString();
                int    itemQuantity         = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
                purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
            }

            bool          hasCharacterData = msg.ReadBoolean();
            CharacterInfo myCharacterInfo  = null;

            if (hasCharacterData)
            {
                myCharacterInfo = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg);
            }

            MultiPlayerCampaign campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;

            if (campaign == null || campaignID != campaign.CampaignID)
            {
                string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer);

                GameMain.GameSession = new GameSession(null, savePath,
                                                       GameModePreset.List.Find(g => g.Identifier == "multiplayercampaign"));

                campaign            = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
                campaign.CampaignID = campaignID;
                campaign.GenerateMap(mapSeed);
                GameMain.NetLobbyScreen.ToggleCampaignMode(true);
            }


            //server has a newer save file
            if (NetIdUtils.IdMoreRecent(saveID, campaign.PendingSaveID))
            {
                /*//stop any active campaign save transfers, they're outdated now
                 * List<FileReceiver.FileTransferIn> saveTransfers =
                 *  GameMain.Client.FileReceiver.ActiveTransfers.FindAll(t => t.FileType == FileTransferType.CampaignSave);
                 *
                 * foreach (var transfer in saveTransfers)
                 * {
                 *  GameMain.Client.FileReceiver.StopTransfer(transfer);
                 * }
                 *
                 * GameMain.Client.RequestFile(FileTransferType.CampaignSave, null, null);*/
                campaign.PendingSaveID = saveID;
            }

            if (NetIdUtils.IdMoreRecent(updateID, campaign.lastUpdateID))
            {
                campaign.SuppressStateSending = true;

                //we need to have the latest save file to display location/mission/store
                if (campaign.LastSaveID == saveID)
                {
                    campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex);
                    campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
                    campaign.Map.SelectMission(selectedMissionIndex);
                    campaign.CargoManager.SetPurchasedItems(purchasedItems);
                }

                campaign.startWatchmanID = startWatchmanID;
                campaign.endWatchmanID   = endWatchmanID;

                campaign.Money = money;
                campaign.PurchasedHullRepairs  = purchasedHullRepairs;
                campaign.PurchasedItemRepairs  = purchasedItemRepairs;
                campaign.PurchasedLostShuttles = purchasedLostShuttles;

                if (myCharacterInfo != null)
                {
                    GameMain.Client.CharacterInfo = myCharacterInfo;
                    GameMain.NetLobbyScreen.SetCampaignCharacterInfo(myCharacterInfo);
                }
                else
                {
                    GameMain.NetLobbyScreen.SetCampaignCharacterInfo(null);
                }

                campaign.lastUpdateID         = updateID;
                campaign.SuppressStateSending = false;
            }
        }
Ejemplo n.º 10
0
        //static because we may need to instantiate the campaign if it hasn't been done yet
        public static void ClientRead(IReadMessage msg)
        {
            bool   isFirstRound         = msg.ReadBoolean();
            byte   campaignID           = msg.ReadByte();
            UInt16 updateID             = msg.ReadUInt16();
            UInt16 saveID               = msg.ReadUInt16();
            string mapSeed              = msg.ReadString();
            UInt16 currentLocIndex      = msg.ReadUInt16();
            UInt16 selectedLocIndex     = msg.ReadUInt16();
            byte   selectedMissionIndex = msg.ReadByte();
            bool   allowDebugTeleport   = msg.ReadBoolean();
            float? reputation           = null;

            if (msg.ReadBoolean())
            {
                reputation = msg.ReadSingle();
            }

            Dictionary <string, float> factionReps = new Dictionary <string, float>();
            byte factionsCount = msg.ReadByte();

            for (int i = 0; i < factionsCount; i++)
            {
                factionReps.Add(msg.ReadString(), msg.ReadSingle());
            }

            bool forceMapUI = msg.ReadBoolean();

            int  money = msg.ReadInt32();
            bool purchasedHullRepairs  = msg.ReadBoolean();
            bool purchasedItemRepairs  = msg.ReadBoolean();
            bool purchasedLostShuttles = msg.ReadBoolean();

            byte missionCount = msg.ReadByte();
            List <Pair <string, byte> > availableMissions = new List <Pair <string, byte> >();

            for (int i = 0; i < missionCount; i++)
            {
                string missionIdentifier = msg.ReadString();
                byte   connectionIndex   = msg.ReadByte();
                availableMissions.Add(new Pair <string, byte>(missionIdentifier, connectionIndex));
            }

            UInt16?storeBalance = null;

            if (msg.ReadBoolean())
            {
                storeBalance = msg.ReadUInt16();
            }

            UInt16 buyCrateItemCount           = msg.ReadUInt16();
            List <PurchasedItem> buyCrateItems = new List <PurchasedItem>();

            for (int i = 0; i < buyCrateItemCount; i++)
            {
                string itemPrefabIdentifier = msg.ReadString();
                int    itemQuantity         = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
                buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
            }

            UInt16 purchasedItemCount           = msg.ReadUInt16();
            List <PurchasedItem> purchasedItems = new List <PurchasedItem>();

            for (int i = 0; i < purchasedItemCount; i++)
            {
                string itemPrefabIdentifier = msg.ReadString();
                int    itemQuantity         = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
                purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
            }

            UInt16          soldItemCount = msg.ReadUInt16();
            List <SoldItem> soldItems     = new List <SoldItem>();

            for (int i = 0; i < soldItemCount; i++)
            {
                string itemPrefabIdentifier = msg.ReadString();
                UInt16 id       = msg.ReadUInt16();
                bool   removed  = msg.ReadBoolean();
                byte   sellerId = msg.ReadByte();
                soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId));
            }

            ushort pendingUpgradeCount = msg.ReadUInt16();
            List <PurchasedUpgrade> pendingUpgrades = new List <PurchasedUpgrade>();

            for (int i = 0; i < pendingUpgradeCount; i++)
            {
                string          upgradeIdentifier  = msg.ReadString();
                UpgradePrefab   prefab             = UpgradePrefab.Find(upgradeIdentifier);
                string          categoryIdentifier = msg.ReadString();
                UpgradeCategory category           = UpgradeCategory.Find(categoryIdentifier);
                int             upgradeLevel       = msg.ReadByte();
                if (prefab == null || category == null)
                {
                    continue;
                }
                pendingUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel));
            }

            bool          hasCharacterData = msg.ReadBoolean();
            CharacterInfo myCharacterInfo  = null;

            if (hasCharacterData)
            {
                myCharacterInfo = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg);
            }

            if (!(GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign) || campaignID != campaign.CampaignID)
            {
                string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer);

                GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, mapSeed);
                campaign             = (MultiPlayerCampaign)GameMain.GameSession.GameMode;
                campaign.CampaignID  = campaignID;
                GameMain.NetLobbyScreen.ToggleCampaignMode(true);
            }

            //server has a newer save file
            if (NetIdUtils.IdMoreRecent(saveID, campaign.PendingSaveID))
            {
                campaign.PendingSaveID = saveID;
            }

            if (NetIdUtils.IdMoreRecent(updateID, campaign.lastUpdateID))
            {
                campaign.SuppressStateSending = true;
                campaign.IsFirstRound         = isFirstRound;

                //we need to have the latest save file to display location/mission/store
                if (campaign.LastSaveID == saveID)
                {
                    campaign.ForceMapUI = forceMapUI;

                    UpgradeStore.WaitForServerUpdate = false;

                    campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex);
                    campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
                    campaign.Map.SelectMission(selectedMissionIndex);
                    campaign.Map.AllowDebugTeleport = allowDebugTeleport;
                    campaign.CargoManager.SetItemsInBuyCrate(buyCrateItems);
                    campaign.CargoManager.SetPurchasedItems(purchasedItems);
                    campaign.CargoManager.SetSoldItems(soldItems);
                    if (storeBalance.HasValue)
                    {
                        campaign.Map.CurrentLocation.StoreCurrentBalance = storeBalance.Value;
                    }
                    campaign.UpgradeManager.SetPendingUpgrades(pendingUpgrades);
                    campaign.UpgradeManager.PurchasedUpgrades.Clear();

                    foreach (var(identifier, rep) in factionReps)
                    {
                        Faction faction = campaign.Factions.FirstOrDefault(f => f.Prefab.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase));
                        if (faction?.Reputation != null)
                        {
                            faction.Reputation.Value = rep;
                        }
                        else
                        {
                            DebugConsole.ThrowError($"Received an update for a faction that doesn't exist \"{identifier}\".");
                        }
                    }

                    if (reputation.HasValue)
                    {
                        campaign.Map.CurrentLocation.Reputation.Value = reputation.Value;
                        campaign?.CampaignUI?.UpgradeStore?.RefreshAll();
                    }

                    foreach (var availableMission in availableMissions)
                    {
                        MissionPrefab missionPrefab = MissionPrefab.List.Find(mp => mp.Identifier == availableMission.First);
                        if (missionPrefab == null)
                        {
                            DebugConsole.ThrowError($"Error when receiving campaign data from the server: mission prefab \"{availableMission.First}\" not found.");
                            continue;
                        }
                        if (availableMission.Second < 0 || availableMission.Second >= campaign.Map.CurrentLocation.Connections.Count)
                        {
                            DebugConsole.ThrowError($"Error when receiving campaign data from the server: connection index for mission \"{availableMission.First}\" out of range (index: {availableMission.Second}, current location: {campaign.Map.CurrentLocation.Name}, connections: {campaign.Map.CurrentLocation.Connections.Count}).");
                            continue;
                        }
                        LocationConnection connection = campaign.Map.CurrentLocation.Connections[availableMission.Second];
                        campaign.Map.CurrentLocation.UnlockMission(missionPrefab, connection);
                    }

                    GameMain.NetLobbyScreen.ToggleCampaignMode(true);
                }

                bool shouldRefresh = campaign.Money != money ||
                                     campaign.PurchasedHullRepairs != purchasedHullRepairs ||
                                     campaign.PurchasedItemRepairs != purchasedItemRepairs ||
                                     campaign.PurchasedLostShuttles != purchasedLostShuttles;

                campaign.Money = money;
                campaign.PurchasedHullRepairs  = purchasedHullRepairs;
                campaign.PurchasedItemRepairs  = purchasedItemRepairs;
                campaign.PurchasedLostShuttles = purchasedLostShuttles;

                if (shouldRefresh)
                {
                    campaign?.CampaignUI?.UpgradeStore?.RefreshAll();
                }

                if (myCharacterInfo != null)
                {
                    GameMain.Client.CharacterInfo = myCharacterInfo;
                    GameMain.NetLobbyScreen.SetCampaignCharacterInfo(myCharacterInfo);
                }
                else
                {
                    GameMain.NetLobbyScreen.SetCampaignCharacterInfo(null);
                }

                campaign.lastUpdateID         = updateID;
                campaign.SuppressStateSending = false;
            }
        }
Ejemplo n.º 11
0
        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, 9);
                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, Position + Vector2.UnitY * 150.0f);
                    }
                    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)
                    {
                        if (eventType == 4)
                        {
                            SetAttackTarget(attackLimb, targetEntity, targetSimPos);
                        }
                        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 <Items.Components.WifiComponent>();
                        if (wifiComponent != null)
                        {
                            wifiComponent.TeamID = teamID;
                        }
                    }
                    break;
                }
                msg.ReadPadBits();
                break;
            }
        }
Ejemplo n.º 12
0
        public static void ClientRead(IReadMessage inc)
        {
            ReadyCheckState state        = (ReadyCheckState)inc.ReadByte();
            CrewManager?    crewManager  = GameMain.GameSession?.CrewManager;
            List <Client>   otherClients = GameMain.Client.ConnectedClients;

            if (crewManager == null || otherClients == null)
            {
                if (state == ReadyCheckState.Start)
                {
                    SendState(ReadyStatus.No);
                }
                return;
            }

            switch (state)
            {
            case ReadyCheckState.Start:
                bool isOwn    = false;
                byte authorId = 0;

                float  duration  = inc.ReadSingle();
                string author    = inc.ReadString();
                bool   hasAuthor = inc.ReadBoolean();

                if (hasAuthor)
                {
                    authorId = inc.ReadByte();
                    isOwn    = authorId == GameMain.Client.ID;
                }

                ushort      clientCount = inc.ReadUInt16();
                List <byte> clients     = new List <byte>();
                for (int i = 0; i < clientCount; i++)
                {
                    clients.Add(inc.ReadByte());
                }

                ReadyCheck rCheck = new ReadyCheck(clients, duration);
                crewManager.ActiveReadyCheck = rCheck;

                if (isOwn)
                {
                    SendState(ReadyStatus.Yes);
                    rCheck.CreateResultsMessage();
                }
                else
                {
                    rCheck.CreateMessageBox(author);
                }

                if (hasAuthor && rCheck.Clients.ContainsKey(authorId))
                {
                    rCheck.Clients[authorId] = ReadyStatus.Yes;
                }
                break;

            case ReadyCheckState.Update:
                float       time     = inc.ReadSingle();
                ReadyStatus newState = (ReadyStatus)inc.ReadByte();
                byte        targetId = inc.ReadByte();
                if (crewManager.ActiveReadyCheck != null)
                {
                    crewManager.ActiveReadyCheck.time = time;
                    crewManager.ActiveReadyCheck?.UpdateState(targetId, newState);
                }
                break;

            case ReadyCheckState.End:
                ushort count = inc.ReadUInt16();
                for (int i = 0; i < count; i++)
                {
                    byte        id     = inc.ReadByte();
                    ReadyStatus status = (ReadyStatus)inc.ReadByte();
                    crewManager.ActiveReadyCheck?.UpdateState(id, status);
                }

                crewManager.ActiveReadyCheck?.EndReadyCheck();
                crewManager.ActiveReadyCheck?.msgBox?.Close();
                crewManager.ActiveReadyCheck = null;
                break;
            }
        }
Ejemplo n.º 13
0
        /// <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;
                }

                byte msgLength = msg.ReadByte();

                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, Color.Red);
                    }
                    msg.BitPosition += msgLength * 8;
                }
                else if (entity == null)
                {
                    //entity not found -> consider the even read and skip over it
                    //(can happen, for example, when a client uses a medical item repeatedly
                    //and creates an event for it before receiving the event about it being removed)
                    if (GameSettings.VerboseLogging)
                    {
                        DebugConsole.NewMessage(
                            "Received msg " + thisEventID + ", entity " + entityID + " not found",
                            Microsoft.Xna.Framework.Color.Orange);
                    }
                    sender.LastSentEntityEventID++;
                    msg.BitPosition += msgLength * 8;
                }
                else
                {
                    if (GameSettings.VerboseLogging)
                    {
                        DebugConsole.NewMessage("Received msg " + thisEventID, Microsoft.Xna.Framework.Color.Green);
                    }

                    UInt16 characterStateID = msg.ReadUInt16();

                    ReadWriteMessage buffer = new ReadWriteMessage();
                    byte[]           temp   = msg.ReadBytes(msgLength - 2);
                    buffer.Write(temp, 0, msgLength - 2);
                    buffer.BitPosition = 0;
                    BufferEvent(new BufferedEvent(sender, sender.Character, characterStateID, entity, buffer));

                    sender.LastSentEntityEventID++;
                }
                msg.ReadPadBits();
            }
        }
Ejemplo n.º 14
0
        private void ReadConnectionInitializationStep(PendingClient pendingClient, IReadMessage inc)
        {
            if (!started)
            {
                return;
            }

            pendingClient.TimeOut = NetworkConnection.TimeoutThreshold;

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

            //DebugConsole.NewMessage(initializationStep+" "+pendingClient.InitializationStep);

            if (pendingClient.InitializationStep != initializationStep)
            {
                return;
            }

            pendingClient.UpdateTime = Timing.TotalTime + Timing.Step;

            switch (initializationStep)
            {
            case ConnectionInitialization.SteamTicketAndVersion:
                string name         = Client.SanitizeName(inc.ReadString());
                UInt64 steamId      = inc.ReadUInt64();
                UInt16 ticketLength = inc.ReadUInt16();
                inc.BitPosition += ticketLength * 8;     //skip ticket, owner handles steam authentication

                if (!Client.IsValidName(name, serverSettings))
                {
                    RemovePendingClient(pendingClient, DisconnectReason.InvalidName, "The name \"" + name + "\" is invalid");
                    return;
                }

                string version             = inc.ReadString();
                bool   isCompatibleVersion = NetworkMember.IsCompatible(version, GameMain.Version.ToString()) ?? false;
                if (!isCompatibleVersion)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.InvalidVersion,
                                        $"DisconnectMessage.InvalidVersion~[version]={GameMain.Version.ToString()}~[clientversion]={version}");

                    GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
                    DebugConsole.NewMessage(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red);
                    return;
                }

                int contentPackageCount = (int)inc.ReadVariableUInt32();
                List <ClientContentPackage> clientContentPackages = new List <ClientContentPackage>();
                for (int i = 0; i < contentPackageCount; i++)
                {
                    string packageName = inc.ReadString();
                    string packageHash = inc.ReadString();
                    clientContentPackages.Add(new ClientContentPackage(packageName, packageHash));
                }

                //check if the client is missing any of our packages
                List <ContentPackage> missingPackages = new List <ContentPackage>();
                foreach (ContentPackage serverContentPackage in GameMain.SelectedPackages)
                {
                    if (!serverContentPackage.HasMultiplayerIncompatibleContent)
                    {
                        continue;
                    }
                    bool packageFound = clientContentPackages.Any(cp => cp.Name == serverContentPackage.Name && cp.Hash == serverContentPackage.MD5hash.Hash);
                    if (!packageFound)
                    {
                        missingPackages.Add(serverContentPackage);
                    }
                }

                //check if the client is using packages we don't have
                List <ClientContentPackage> redundantPackages = new List <ClientContentPackage>();
                foreach (ClientContentPackage clientContentPackage in clientContentPackages)
                {
                    bool packageFound = GameMain.SelectedPackages.Any(cp => cp.Name == clientContentPackage.Name && cp.MD5hash.Hash == clientContentPackage.Hash);
                    if (!packageFound)
                    {
                        redundantPackages.Add(clientContentPackage);
                    }
                }

                if (missingPackages.Count == 1)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.MissingContentPackage,
                                        $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
                    GameServer.Log(name + " (" + pendingClient.SteamID + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
                    return;
                }
                else if (missingPackages.Count > 1)
                {
                    List <string> packageStrs = new List <string>();
                    missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
                    RemovePendingClient(pendingClient, DisconnectReason.MissingContentPackage,
                                        $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}");
                    GameServer.Log(name + " (" + pendingClient.SteamID + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
                    return;
                }
                if (redundantPackages.Count == 1)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.IncompatibleContentPackage,
                                        $"DisconnectMessage.IncompatibleContentPackage~[incompatiblecontentpackage]={GetPackageStr(redundantPackages[0])}");
                    GameServer.Log(name + " (" + pendingClient.SteamID + ") couldn't join the server (using an incompatible content package " + GetPackageStr(redundantPackages[0]) + ")", ServerLog.MessageType.Error);
                    return;
                }
                if (redundantPackages.Count > 1)
                {
                    List <string> packageStrs = new List <string>();
                    redundantPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
                    RemovePendingClient(pendingClient, DisconnectReason.IncompatibleContentPackage,
                                        $"DisconnectMessage.IncompatibleContentPackages~[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
                    GameServer.Log(name + " (" + pendingClient.SteamID + ") couldn't join the server (using incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
                    return;
                }

                if (!pendingClient.AuthSessionStarted)
                {
                    pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;

                    pendingClient.Name = name;
                    pendingClient.AuthSessionStarted = true;
                }
                break;

            case ConnectionInitialization.Password:
                int    pwLength    = inc.ReadByte();
                byte[] incPassword = inc.ReadBytes(pwLength);
                if (pendingClient.PasswordSalt == null)
                {
                    DebugConsole.ThrowError("Received password message from client without salt");
                    return;
                }
                if (serverSettings.IsPasswordCorrect(incPassword, pendingClient.PasswordSalt.Value))
                {
                    pendingClient.InitializationStep = ConnectionInitialization.ContentPackageOrder;
                }
                else
                {
                    pendingClient.Retries++;
                    if (serverSettings.BanAfterWrongPassword && pendingClient.Retries > serverSettings.MaxPasswordRetriesBeforeBan)
                    {
                        string banMsg = "Failed to enter correct password too many times";
                        serverSettings.BanList.BanPlayer(pendingClient.Name, pendingClient.SteamID, banMsg, null);

                        RemovePendingClient(pendingClient, DisconnectReason.Banned, banMsg);
                        return;
                    }
                }
                pendingClient.UpdateTime = Timing.TotalTime;
                break;

            case ConnectionInitialization.ContentPackageOrder:
                pendingClient.InitializationStep = ConnectionInitialization.Success;
                pendingClient.UpdateTime         = Timing.TotalTime;
                break;
            }
        }
Ejemplo n.º 15
0
        public static void ServerRead(IReadMessage msg, Client c)
        {
            c.KickAFKTimer = 0.0f;

            UInt16          ID   = msg.ReadUInt16();
            ChatMessageType type = (ChatMessageType)msg.ReadByte();
            string          txt  = "";

            int              orderIndex           = -1;
            Character        orderTargetCharacter = null;
            Entity           orderTargetEntity    = null;
            int              orderOptionIndex     = -1;
            OrderChatMessage orderMsg             = null;

            if (type == ChatMessageType.Order)
            {
                orderIndex           = msg.ReadByte();
                orderTargetCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character;
                orderTargetEntity    = Entity.FindEntityByID(msg.ReadUInt16()) as Entity;
                orderOptionIndex     = msg.ReadByte();

                if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
                {
                    DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderIndex}, {orderOptionIndex}).");
                    if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID))
                    {
                        c.LastSentChatMsgID = ID;
                    }
                    return;
                }

                Order  order       = Order.PrefabList[orderIndex];
                string orderOption = orderOptionIndex < 0 || orderOptionIndex >= order.Options.Length ? "" : order.Options[orderOptionIndex];
                orderMsg = new OrderChatMessage(order, orderOption, orderTargetEntity, orderTargetCharacter, c.Character);
                txt      = orderMsg.Text;
            }
            else
            {
                txt = msg.ReadString() ?? "";
            }

            if (!NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID))
            {
                return;
            }

            c.LastSentChatMsgID = ID;

            if (txt.Length > MaxLength)
            {
                txt = txt.Substring(0, MaxLength);
            }

            c.LastSentChatMessages.Add(txt);
            if (c.LastSentChatMessages.Count > 10)
            {
                c.LastSentChatMessages.RemoveRange(0, c.LastSentChatMessages.Count - 10);
            }

            float similarity = 0.0f;

            for (int i = 0; i < c.LastSentChatMessages.Count; i++)
            {
                float closeFactor = 1.0f / (c.LastSentChatMessages.Count - i);

                if (string.IsNullOrEmpty(txt))
                {
                    similarity += closeFactor;
                }
                else
                {
                    int levenshteinDist = ToolBox.LevenshteinDistance(txt, c.LastSentChatMessages[i]);
                    similarity += Math.Max((txt.Length - levenshteinDist) / (float)txt.Length * closeFactor, 0.0f);
                }
            }
            //order/report messages can be sent a little faster than normal messages without triggering the spam filter
            if (orderMsg != null)
            {
                similarity *= 0.25f;
            }

            bool isOwner = GameMain.Server.OwnerConnection != null && c.Connection == GameMain.Server.OwnerConnection;

            if (similarity + c.ChatSpamSpeed > 5.0f && !isOwner)
            {
                GameMain.Server.KarmaManager.OnSpamFilterTriggered(c);

                c.ChatSpamCount++;
                if (c.ChatSpamCount > 3)
                {
                    //kick for spamming too much
                    GameMain.Server.KickClient(c, TextManager.Get("SpamFilterKicked"));
                }
                else
                {
                    ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
                    c.ChatSpamTimer = 10.0f;
                    GameMain.Server.SendDirectChatMessage(denyMsg, c);
                }
                return;
            }

            c.ChatSpamSpeed += similarity + 0.5f;

            if (c.ChatSpamTimer > 0.0f && !isOwner)
            {
                ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
                c.ChatSpamTimer = 10.0f;
                GameMain.Server.SendDirectChatMessage(denyMsg, c);
                return;
            }

            if (type == ChatMessageType.Order)
            {
                if (c.Character == null || c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead)
                {
                    return;
                }

                ChatMessageType messageType = CanUseRadio(orderMsg.Sender) ? ChatMessageType.Radio : ChatMessageType.Default;
                if (orderMsg.Order.TargetAllCharacters)
                {
                    //do nothing
                }
                else if (orderTargetCharacter != null)
                {
                    orderTargetCharacter.SetOrder(
                        new Order(orderMsg.Order.Prefab, orderTargetEntity, (orderTargetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == orderMsg.Order.ItemComponentType)),
                        orderMsg.OrderOption, orderMsg.Sender);
                }

                GameMain.Server.SendOrderChatMessage(orderMsg);
            }
            else
            {
                GameMain.Server.SendChatMessage(txt, null, c);
            }
        }
Ejemplo n.º 16
0
        public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
        {
            List <Item> prevItems = new List <Item>(AllItems.Distinct());

            byte slotCount = msg.ReadByte();

            List <ushort>[] newItemIDs = new List <ushort> [slotCount];
            for (int i = 0; i < slotCount; i++)
            {
                newItemIDs[i] = new List <ushort>();
                int itemCount = msg.ReadRangedInteger(0, MaxStackSize);
                for (int j = 0; j < itemCount; j++)
                {
                    newItemIDs[i].Add(msg.ReadUInt16());
                }
            }

            if (c == null || c.Character == null)
            {
                return;
            }

            bool accessible = c.Character.CanAccessInventory(this);

            if (this is CharacterInventory characterInventory && accessible)
            {
                if (Owner == null || !(Owner is Character ownerCharacter))
                {
                    accessible = false;
                }
                else if (!characterInventory.AccessibleWhenAlive && !ownerCharacter.IsDead)
                {
                    accessible = false;
                }
            }

            if (!accessible)
            {
                //create a network event to correct the client's inventory state
                //otherwise they may have an item in their inventory they shouldn't have been able to pick up,
                //and receiving an event for that inventory later will cause the item to be dropped
                CreateNetworkEvent();
                for (int i = 0; i < capacity; i++)
                {
                    foreach (ushort id in newItemIDs[i])
                    {
                        if (!(Entity.FindEntityByID(id) is Item item))
                        {
                            continue;
                        }
                        item.PositionUpdateInterval = 0.0f;
                        if (item.ParentInventory != null && item.ParentInventory != this)
                        {
                            item.ParentInventory.CreateNetworkEvent();
                        }
                    }
                }
                return;
            }

            List <Inventory> prevItemInventories = new List <Inventory>()
            {
                this
            };

            for (int i = 0; i < capacity; i++)
            {
                foreach (Item item in slots[i].Items.ToList())
                {
                    if (!newItemIDs[i].Contains(item.ID))
                    {
                        Item      droppedItem       = item;
                        Entity    prevOwner         = Owner;
                        Inventory previousInventory = droppedItem.ParentInventory;
                        droppedItem.Drop(null);
                        droppedItem.PreviousParentInventory = previousInventory;

                        var previousCharacterInventory = prevOwner switch
                        {
                            Item itemInventory => itemInventory.FindParentInventory(inventory => inventory is CharacterInventory) as CharacterInventory,
                            Character character => character.Inventory,
                            _ => null
                        };

                        if (previousCharacterInventory != null && previousCharacterInventory != c.Character?.Inventory)
                        {
                            GameMain.Server?.KarmaManager.OnItemTakenFromPlayer(previousCharacterInventory, c, droppedItem);
                        }

                        if (droppedItem.body != null && prevOwner != null)
                        {
                            droppedItem.body.SetTransform(prevOwner.SimPosition, 0.0f);
                        }
                    }
                }

                foreach (ushort id in newItemIDs[i])
                {
                    Item newItem = id == 0 ? null : Entity.FindEntityByID(id) as Item;
                    prevItemInventories.Add(newItem?.ParentInventory);
                }
            }

            for (int i = 0; i < capacity; i++)
            {
                foreach (ushort id in newItemIDs[i])
                {
                    if (!(Entity.FindEntityByID(id) is Item item) || slots[i].Contains(item))
                    {
                        continue;
                    }

                    if (GameMain.Server != null)
                    {
                        var holdable = item.GetComponent <Holdable>();
                        if (holdable != null && !holdable.CanBeDeattached())
                        {
                            continue;
                        }

                        if (!prevItems.Contains(item) && !item.CanClientAccess(c) &&
                            (c.Character == null || item.PreviousParentInventory == null || !c.Character.CanAccessInventory(item.PreviousParentInventory)))
                        {
    #if DEBUG || UNSTABLE
                            DebugConsole.NewMessage($"Client {c.Name} failed to pick up item \"{item}\" (parent inventory: {(item.ParentInventory?.Owner.ToString() ?? "null")}). No access.", Color.Yellow);
    #endif
                            if (item.body != null && !c.PendingPositionUpdates.Contains(item))
                            {
                                c.PendingPositionUpdates.Enqueue(item);
                            }
                            item.PositionUpdateInterval = 0.0f;
                            continue;
                        }
                    }
                    TryPutItem(item, i, true, true, c.Character, false);
                    for (int j = 0; j < capacity; j++)
                    {
                        if (slots[j].Contains(item) && !newItemIDs[j].Contains(item.ID))
                        {
                            slots[j].RemoveItem(item);
                        }
                    }
                }
            }

            CreateNetworkEvent();
            foreach (Inventory prevInventory in prevItemInventories.Distinct())
            {
                if (prevInventory != this)
                {
                    prevInventory?.CreateNetworkEvent();
                }
            }

            foreach (Item item in AllItems.Distinct())
            {
                if (item == null)
                {
                    continue;
                }
                if (!prevItems.Contains(item))
                {
                    if (Owner == c.Character)
                    {
                        HumanAIController.ItemTaken(item, c.Character);
                        GameServer.Log(GameServer.CharacterLogName(c.Character) + " picked up " + item.Name, ServerLog.MessageType.Inventory);
                    }
                    else
                    {
                        GameServer.Log(GameServer.CharacterLogName(c.Character) + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory);
                    }
                }
            }
            foreach (Item item in prevItems.Distinct())
            {
                if (item == null)
                {
                    continue;
                }
                if (!AllItems.Contains(item))
                {
                    if (Owner == c.Character)
                    {
                        GameServer.Log(GameServer.CharacterLogName(c.Character) + " dropped " + item.Name, ServerLog.MessageType.Inventory);
                    }
                    else
                    {
                        GameServer.Log(GameServer.CharacterLogName(c.Character) + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory);
                    }
                }
            }
        }
Ejemplo n.º 17
0
        private void HandleDataMessage(IReadMessage inc)
        {
            if (!isActive)
            {
                return;
            }

            UInt64         recipientSteamId = inc.ReadUInt64();
            DeliveryMethod deliveryMethod   = (DeliveryMethod)inc.ReadByte();

            int p2pDataStart = inc.BytePosition;

            byte incByte = inc.ReadByte();

            bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
            bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
            bool isDisconnectMessage            = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
            bool isServerMessage    = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
            bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;

            if (recipientSteamId != selfSteamID)
            {
                if (!isServerMessage)
                {
                    DebugConsole.ThrowError("Received non-server message meant for remote peer");
                    return;
                }

                RemotePeer peer = remotePeers.Find(p => p.SteamID == recipientSteamId);

                if (peer == null)
                {
                    return;
                }

                if (isDisconnectMessage)
                {
                    DisconnectPeer(peer, inc.ReadString());
                    return;
                }

                Steamworks.P2PSend sendType;
                switch (deliveryMethod)
                {
                case DeliveryMethod.Reliable:
                case DeliveryMethod.ReliableOrdered:
                    //the documentation seems to suggest that the Reliable send type
                    //enforces packet order (TODO: verify)
                    sendType = Steamworks.P2PSend.Reliable;
                    break;

                default:
                    sendType = Steamworks.P2PSend.Unreliable;
                    break;
                }

                byte[] p2pData;

                if (isConnectionInitializationStep)
                {
                    p2pData    = new byte[inc.LengthBytes - p2pDataStart + 8];
                    p2pData[0] = inc.Buffer[p2pDataStart];
                    Lidgren.Network.NetBitWriter.WriteUInt64(SteamManager.CurrentLobbyID, 64, p2pData, 8);
                    Array.Copy(inc.Buffer, p2pDataStart + 1, p2pData, 9, inc.LengthBytes - p2pDataStart - 1);
                }
                else
                {
                    p2pData = new byte[inc.LengthBytes - p2pDataStart];
                    Array.Copy(inc.Buffer, p2pDataStart, p2pData, 0, p2pData.Length);
                }

                if (p2pData.Length + 4 >= MsgConstants.MTU)
                {
                    DebugConsole.Log("WARNING: message length comes close to exceeding MTU, forcing reliable send (" + p2pData.Length.ToString() + " bytes)");
                    sendType = Steamworks.P2PSend.Reliable;
                }

                bool successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, 0, sendType);
                sentBytes += p2pData.Length;

                if (!successSend)
                {
                    if (sendType != Steamworks.P2PSend.Reliable)
                    {
                        DebugConsole.Log("WARNING: message couldn't be sent unreliably, forcing reliable send (" + p2pData.Length.ToString() + " bytes)");
                        sendType    = Steamworks.P2PSend.Reliable;
                        successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, 0, sendType);
                        sentBytes  += p2pData.Length;
                    }
                    if (!successSend)
                    {
                        DebugConsole.ThrowError("Failed to send message to remote peer! (" + p2pData.Length.ToString() + " bytes)");
                    }
                }
            }
            else
            {
                if (isDisconnectMessage)
                {
                    DebugConsole.ThrowError("Received disconnect message from owned server");
                    return;
                }
                if (!isServerMessage)
                {
                    DebugConsole.ThrowError("Received non-server message from owned server");
                    return;
                }
                if (isHeartbeatMessage)
                {
                    return; //timeout is handled by Lidgren, ignore this message
                }
                if (isConnectionInitializationStep)
                {
                    IWriteMessage outMsg = new WriteOnlyMessage();
                    outMsg.Write(selfSteamID);
                    outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep));
                    outMsg.Write(Name);

                    byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
                    Array.Resize(ref msgToSend, outMsg.LengthBytes);
                    ChildServerRelay.Write(msgToSend);
                    return;
                }
                else
                {
                    if (initializationStep != ConnectionInitialization.Success)
                    {
                        OnInitializationComplete?.Invoke();
                        initializationStep = ConnectionInitialization.Success;
                    }
                    UInt16       length = inc.ReadUInt16();
                    IReadMessage msg    = new ReadOnlyMessage(inc.Buffer, isCompressed, inc.BytePosition, length, ServerConnection);
                    OnMessageReceived?.Invoke(msg);

                    return;
                }
            }
        }
Ejemplo n.º 18
0
        private void HandleDataMessage(IReadMessage inc)
        {
            if (!started)
            {
                return;
            }

            UInt64 senderSteamId = inc.ReadUInt64();

            byte incByte      = inc.ReadByte();
            bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
            bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
            bool isDisconnectMessage            = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
            bool isServerMessage    = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
            bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;

            if (isServerMessage)
            {
                DebugConsole.ThrowError("Got server message from" + senderSteamId.ToString());
                return;
            }

            if (senderSteamId != OwnerSteamID) //sender is remote, handle disconnects and heartbeats
            {
                PendingClient      pendingClient   = pendingClients.Find(c => c.SteamID == senderSteamId);
                SteamP2PConnection connectedClient = connectedClients.Find(c => c.SteamID == senderSteamId) as SteamP2PConnection;

                pendingClient?.Heartbeat();
                connectedClient?.Heartbeat();

                if (serverSettings.BanList.IsBanned(senderSteamId, out string banReason))
                {
                    if (pendingClient != null)
                    {
                        RemovePendingClient(pendingClient, DisconnectReason.Banned, banReason);
                    }
                    else if (connectedClient != null)
                    {
                        Disconnect(connectedClient, DisconnectReason.Banned.ToString() + "/ " + banReason);
                    }
                    return;
                }
                else if (isDisconnectMessage)
                {
                    if (pendingClient != null)
                    {
                        string disconnectMsg = $"ServerMessage.HasDisconnected~[client]={pendingClient.Name}";
                        RemovePendingClient(pendingClient, DisconnectReason.Unknown, disconnectMsg);
                    }
                    else if (connectedClient != null)
                    {
                        string disconnectMsg = $"ServerMessage.HasDisconnected~[client]={connectedClient.Name}";
                        Disconnect(connectedClient, disconnectMsg, false);
                    }
                    return;
                }
                else if (isHeartbeatMessage)
                {
                    //message exists solely as a heartbeat, ignore its contents
                    return;
                }
                else if (isConnectionInitializationStep)
                {
                    if (pendingClient != null)
                    {
                        ReadConnectionInitializationStep(pendingClient, new ReadOnlyMessage(inc.Buffer, false, inc.BytePosition, inc.LengthBytes - inc.BytePosition, null));
                    }
                    else
                    {
                        ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();
                        if (initializationStep == ConnectionInitialization.ConnectionStarted)
                        {
                            pendingClients.Add(new PendingClient(new SteamP2PConnection("PENDING", senderSteamId))
                            {
                                SteamID = senderSteamId
                            });
                        }
                    }
                }
                else if (connectedClient != null)
                {
                    UInt16 length = inc.ReadUInt16();

                    IReadMessage msg = new ReadOnlyMessage(inc.Buffer, isCompressed, inc.BytePosition, length, connectedClient);
                    OnMessageReceived?.Invoke(connectedClient, msg);
                }
            }
            else //sender is owner
            {
                if (OwnerConnection != null)
                {
                    (OwnerConnection as SteamP2PConnection).Heartbeat();
                }

                if (isDisconnectMessage)
                {
                    DebugConsole.ThrowError("Received disconnect message from owner");
                    return;
                }
                if (isServerMessage)
                {
                    DebugConsole.ThrowError("Received server message from owner");
                    return;
                }
                if (isConnectionInitializationStep)
                {
                    if (OwnerConnection == null)
                    {
                        string ownerName = inc.ReadString();
                        OwnerConnection = new SteamP2PConnection(ownerName, OwnerSteamID)
                        {
                            Language = GameMain.Config.Language
                        };

                        OnInitializationComplete?.Invoke(OwnerConnection);
                    }
                    return;
                }
                if (isHeartbeatMessage)
                {
                    return;
                }
                else
                {
                    UInt16 length = inc.ReadUInt16();

                    IReadMessage msg = new ReadOnlyMessage(inc.Buffer, isCompressed, inc.BytePosition, length, OwnerConnection);
                    OnMessageReceived?.Invoke(OwnerConnection, msg);
                }
            }
        }
Ejemplo n.º 19
0
        public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
        {
            NetEntityEvent.Type eventType =
                (NetEntityEvent.Type)msg.ReadRangedInteger(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);

            c.KickAFKTimer = 0.0f;

            switch (eventType)
            {
            case NetEntityEvent.Type.ComponentState:
                int componentIndex = msg.ReadRangedInteger(0, components.Count - 1);
                (components[componentIndex] as IClientSerializable).ServerRead(type, msg, c);
                break;

            case NetEntityEvent.Type.InventoryState:
                int containerIndex = msg.ReadRangedInteger(0, components.Count - 1);
                (components[containerIndex] as ItemContainer).Inventory.ServerRead(type, msg, c);
                break;

            case NetEntityEvent.Type.Treatment:
                if (c.Character == null || !c.Character.CanInteractWith(this))
                {
                    return;
                }

                UInt16 characterID = msg.ReadUInt16();
                byte   limbIndex   = msg.ReadByte();

                Character targetCharacter = FindEntityByID(characterID) as Character;
                if (targetCharacter == null)
                {
                    break;
                }
                if (targetCharacter != c.Character && c.Character.SelectedCharacter != targetCharacter)
                {
                    break;
                }

                Limb targetLimb = limbIndex < targetCharacter.AnimController.Limbs.Length ? targetCharacter.AnimController.Limbs[limbIndex] : null;

                if (ContainedItems == null || ContainedItems.All(i => i == null))
                {
                    GameServer.Log(GameServer.CharacterLogName(c.Character) + " used item " + Name, ServerLog.MessageType.ItemInteraction);
                }
                else
                {
                    GameServer.Log(
                        GameServer.CharacterLogName(c.Character) + " used item " + Name + " (contained items: " + string.Join(", ", ContainedItems.Select(i => i.Name)) + ")",
                        ServerLog.MessageType.ItemInteraction);
                }

                ApplyTreatment(c.Character, targetCharacter, targetLimb);

                break;

            case NetEntityEvent.Type.ChangeProperty:
                ReadPropertyChange(msg, inGameEditableOnly: GameMain.NetworkMember.IsServer, sender: c);
                break;

            case NetEntityEvent.Type.Combine:
                UInt16 combineTargetID = msg.ReadUInt16();
                Item   combineTarget   = FindEntityByID(combineTargetID) as Item;
                if (combineTarget == null || !c.Character.CanInteractWith(this) || !c.Character.CanInteractWith(combineTarget))
                {
                    return;
                }
                Combine(combineTarget, c.Character);
                break;
            }
        }
Ejemplo n.º 20
0
        public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
        {
            List <Wire>[] wires = new List <Wire> [Connections.Count];

            //read wire IDs for each connection
            for (int i = 0; i < Connections.Count; i++)
            {
                wires[i] = new List <Wire>();
                for (int j = 0; j < Connection.MaxLinked; j++)
                {
                    ushort wireId = msg.ReadUInt16();

                    if (!(Entity.FindEntityByID(wireId) is Item wireItem))
                    {
                        continue;
                    }

                    Wire wireComponent = wireItem.GetComponent <Wire>();
                    if (wireComponent != null)
                    {
                        wires[i].Add(wireComponent);
                    }
                }
            }

            List <Wire> clientSideDisconnectedWires = new List <Wire>();
            ushort      disconnectedWireCount       = msg.ReadUInt16();

            for (int i = 0; i < disconnectedWireCount; i++)
            {
                ushort wireId = msg.ReadUInt16();
                if (!(Entity.FindEntityByID(wireId) is Item wireItem))
                {
                    continue;
                }
                Wire wireComponent = wireItem.GetComponent <Wire>();
                if (wireComponent == null)
                {
                    continue;
                }
                clientSideDisconnectedWires.Add(wireComponent);
            }

            //don't allow rewiring locked panels
            if (Locked || !GameMain.NetworkMember.ServerSettings.AllowRewiring)
            {
                return;
            }

            item.CreateServerEvent(this);

            //check if the character can access this connectionpanel
            //and all the wires they're trying to connect
            if (!item.CanClientAccess(c))
            {
                return;
            }
            for (int i = 0; i < Connections.Count; i++)
            {
                foreach (Wire wire in wires[i])
                {
                    //wire not found in any of the connections yet (client is trying to connect a new wire)
                    //  -> we need to check if the client has access to it
                    if (!Connections.Any(connection => connection.Wires.Contains(wire)) && !DisconnectedWires.Contains(wire))
                    {
                        if (!wire.Item.CanClientAccess(c))
                        {
                            return;
                        }
                    }
                }
            }

            if (!CheckCharacterSuccess(c.Character))
            {
                item.CreateServerEvent(this);
                c.Character.Inventory?.CreateNetworkEvent();
                for (int i = 0; i < 2; i++)
                {
                    var selectedWire = c.Character.SelectedItems[i]?.GetComponent <Wire>();
                    if (selectedWire == null)
                    {
                        continue;
                    }

                    selectedWire.CreateNetworkEvent();
                    var panel1 = selectedWire.Connections[0]?.ConnectionPanel;
                    if (panel1 != null && panel1 != this)
                    {
                        panel1.item.CreateServerEvent(panel1);
                    }
                    var panel2 = selectedWire.Connections[1]?.ConnectionPanel;
                    if (panel2 != null && panel2 != this)
                    {
                        panel2.item.CreateServerEvent(panel2);
                    }

                    CoroutineManager.InvokeAfter(() =>
                    {
                        item.CreateServerEvent(this);
                        if (panel1 != null && panel1 != this)
                        {
                            panel1.item.CreateServerEvent(panel1);
                        }
                        if (panel2 != null && panel2 != this)
                        {
                            panel2.item.CreateServerEvent(panel2);
                        }
                        if (!selectedWire.Item.Removed)
                        {
                            selectedWire.CreateNetworkEvent();
                        }
                    }, 1.0f);
                }
                GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFailure, this, c.Character.ID });
                return;
            }

            //go through existing wire links
            for (int i = 0; i < Connections.Count; i++)
            {
                int j = -1;
                foreach (Wire existingWire in Connections[i].Wires)
                {
                    j++;
                    if (existingWire == null)
                    {
                        continue;
                    }

                    //existing wire not in the list of new wires -> disconnect it
                    if (!wires[i].Contains(existingWire))
                    {
                        if (existingWire.Locked)
                        {
                            //this should not be possible unless the client is running a modified version of the game
                            GameServer.Log(GameServer.CharacterLogName(c.Character) + " attempted to disconnect a locked wire from " +
                                           Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.Error);
                            continue;
                        }

                        existingWire.RemoveConnection(item);
                        if (existingWire.Item.ParentInventory == null)
                        {
                            item.GetComponent <ConnectionPanel>()?.DisconnectedWires.Add(existingWire);
                        }

                        if (!wires.Any(w => w.Contains(existingWire)))
                        {
                            GameMain.Server.KarmaManager.OnWireDisconnected(c.Character, existingWire);
                        }

                        if (existingWire.Connections[0] == null && existingWire.Connections[1] == null)
                        {
                            GameServer.Log(GameServer.CharacterLogName(c.Character) + " disconnected a wire from " +
                                           Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.Wiring);

                            if (existingWire.Item.ParentInventory != null)
                            {
                                //in an inventory and not connected to anything -> the wire cannot have any nodes
                                existingWire.ClearConnections();
                            }
                            else if (!clientSideDisconnectedWires.Contains(existingWire))
                            {
                                //not in an inventory, not connected to anything, not hanging loose from any panel -> must be dropped
                                existingWire.Item.Drop(c.Character);
                            }
                        }
                        else if (existingWire.Connections[0] != null)
                        {
                            GameServer.Log(GameServer.CharacterLogName(c.Character) + " disconnected a wire from " +
                                           Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[0].Item.Name + " (" + existingWire.Connections[0].Name + ")", ServerLog.MessageType.Wiring);

                            //wires that are not in anyone's inventory (i.e. not currently being rewired)
                            //can never be connected to only one connection
                            // -> the client must have dropped the wire from the connection panel

                            /*if (existingWire.Item.ParentInventory == null && !wires.Any(w => w.Contains(existingWire)))
                             * {
                             *  //let other clients know the item was also disconnected from the other connection
                             *  existingWire.Connections[0].Item.CreateServerEvent(existingWire.Connections[0].Item.GetComponent<ConnectionPanel>());
                             *  existingWire.Item.Drop(c.Character);
                             * }*/
                        }
                        else if (existingWire.Connections[1] != null)
                        {
                            GameServer.Log(GameServer.CharacterLogName(c.Character) + " disconnected a wire from " +
                                           Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[1].Item.Name + " (" + existingWire.Connections[1].Name + ")", ServerLog.MessageType.Wiring);

                            /*if (existingWire.Item.ParentInventory == null && !wires.Any(w => w.Contains(existingWire)))
                             * {
                             *  //let other clients know the item was also disconnected from the other connection
                             *  existingWire.Connections[1].Item.CreateServerEvent(existingWire.Connections[1].Item.GetComponent<ConnectionPanel>());
                             *  existingWire.Item.Drop(c.Character);
                             * }*/
                        }

                        Connections[i].SetWire(j, null);
                    }
                }
            }

            foreach (Wire disconnectedWire in DisconnectedWires.ToList())
            {
                if (disconnectedWire.Connections[0] == null &&
                    disconnectedWire.Connections[1] == null &&
                    !clientSideDisconnectedWires.Contains(disconnectedWire) &&
                    disconnectedWire.Item.ParentInventory == null)
                {
                    disconnectedWire.Item.Drop(c.Character);
                    GameServer.Log(GameServer.CharacterLogName(c.Character) + " dropped " + disconnectedWire.Name, ServerLog.MessageType.Inventory);
                }
            }

            //go through new wires
            for (int i = 0; i < Connections.Count; i++)
            {
                foreach (Wire newWire in wires[i])
                {
                    //already connected, no need to do anything
                    if (Connections[i].Wires.Contains(newWire))
                    {
                        continue;
                    }

                    Connections[i].TryAddLink(newWire);
                    newWire.Connect(Connections[i], true, true);

                    var otherConnection = newWire.OtherConnection(Connections[i]);

                    if (otherConnection == null)
                    {
                        GameServer.Log(GameServer.CharacterLogName(c.Character) + " connected a wire to " +
                                       Connections[i].Item.Name + " (" + Connections[i].Name + ")",
                                       ServerLog.MessageType.Wiring);
                    }
                    else
                    {
                        GameServer.Log(GameServer.CharacterLogName(c.Character) + " connected a wire from " +
                                       Connections[i].Item.Name + " (" + Connections[i].Name + ") to " +
                                       (otherConnection == null ? "none" : otherConnection.Item.Name + " (" + (otherConnection.Name) + ")"),
                                       ServerLog.MessageType.Wiring);
                    }
                }
            }
        }
Ejemplo n.º 21
0
        public static Character ReadSpawnData(IReadMessage inc)
        {
            DebugConsole.Log("Reading character spawn data");

            if (GameMain.Client == null)
            {
                return(null);
            }

            bool   noInfo      = inc.ReadBoolean();
            ushort id          = inc.ReadUInt16();
            string speciesName = inc.ReadString();
            string seed        = inc.ReadString();

            Vector2 position = new Vector2(inc.ReadSingle(), inc.ReadSingle());

            bool enabled = inc.ReadBoolean();

            DebugConsole.Log("Received spawn data for " + speciesName);

            Character character = null;

            if (noInfo)
            {
                character    = Create(speciesName, position, seed, null, true);
                character.ID = id;
                bool containsStatusData = inc.ReadBoolean();
                if (containsStatusData)
                {
                    character.ReadStatus(inc);
                }
            }
            else
            {
                bool   hasOwner        = inc.ReadBoolean();
                int    ownerId         = hasOwner ? inc.ReadByte() : -1;
                byte   teamID          = inc.ReadByte();
                bool   hasAi           = inc.ReadBoolean();
                string infoSpeciesName = inc.ReadString();

                CharacterInfo info = CharacterInfo.ClientRead(infoSpeciesName, inc);

                character        = Create(speciesName, position, seed, info, GameMain.Client.ID != ownerId, hasAi);
                character.ID     = id;
                character.TeamID = (TeamType)teamID;

                // Check if the character has a current order
                if (inc.ReadBoolean())
                {
                    int       orderPrefabIndex = inc.ReadByte();
                    Entity    targetEntity     = FindEntityByID(inc.ReadUInt16());
                    Character orderGiver       = inc.ReadBoolean() ? FindEntityByID(inc.ReadUInt16()) as Character : null;
                    int       orderOptionIndex = inc.ReadByte();

                    if (orderPrefabIndex >= 0 && orderPrefabIndex < Order.PrefabList.Count)
                    {
                        var orderPrefab = Order.PrefabList[orderPrefabIndex];
                        if (!orderPrefab.MustSetTarget || (targetEntity != null && (targetEntity as Item).Components.Any(c => c?.GetType() == orderPrefab.ItemComponentType)))
                        {
                            character.SetOrder(
                                new Order(orderPrefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(c => c?.GetType() == orderPrefab.ItemComponentType), orderGiver: orderGiver),
                                orderOptionIndex >= 0 && orderOptionIndex < orderPrefab.Options.Length ? orderPrefab.Options[orderOptionIndex] : null,
                                orderGiver, speak: false);
                        }
                        else
                        {
                            DebugConsole.ThrowError("Could not set order \"" + orderPrefab.Identifier + "\" for character \"" + character.Name + "\" because required target entity was not found.");
                        }
                    }
                    else
                    {
                        DebugConsole.ThrowError("Invalid order prefab index - index (" + orderPrefabIndex + ") out of bounds.");
                    }
                }

                bool containsStatusData = inc.ReadBoolean();
                if (containsStatusData)
                {
                    character.ReadStatus(inc);
                }

                if (character.IsHuman && character.TeamID != TeamType.FriendlyNPC && !character.IsDead)
                {
                    CharacterInfo duplicateCharacterInfo = GameMain.GameSession.CrewManager.GetCharacterInfos().FirstOrDefault(c => c.ID == info.ID);
                    GameMain.GameSession.CrewManager.RemoveCharacterInfo(duplicateCharacterInfo);
                    GameMain.GameSession.CrewManager.AddCharacter(character);
                }

                if (GameMain.Client.ID == ownerId)
                {
                    GameMain.Client.HasSpawned = true;
                    GameMain.Client.Character  = character;
                    if (!character.IsDead)
                    {
                        Controlled = character;
                    }

                    GameMain.LightManager.LosEnabled = true;

                    character.memInput.Clear();
                    character.memState.Clear();
                    character.memLocalState.Clear();
                }
            }

            character.Enabled = Controlled == character || enabled;

            return(character);
        }
Ejemplo n.º 22
0
        public static Character ReadSpawnData(IReadMessage inc)
        {
            DebugConsole.Log("Reading character spawn data");

            if (GameMain.Client == null)
            {
                return(null);
            }

            bool   noInfo      = inc.ReadBoolean();
            ushort id          = inc.ReadUInt16();
            string speciesName = inc.ReadString();
            string seed        = inc.ReadString();

            Vector2 position = new Vector2(inc.ReadSingle(), inc.ReadSingle());

            bool enabled = inc.ReadBoolean();

            DebugConsole.Log("Received spawn data for " + speciesName);

            Character character = null;

            if (noInfo)
            {
                character = Create(speciesName, position, seed, characterInfo: null, id: id, isRemotePlayer: false);
                bool containsStatusData = inc.ReadBoolean();
                if (containsStatusData)
                {
                    character.ReadStatus(inc);
                }
            }
            else
            {
                bool   hasOwner        = inc.ReadBoolean();
                int    ownerId         = hasOwner ? inc.ReadByte() : -1;
                byte   teamID          = inc.ReadByte();
                bool   hasAi           = inc.ReadBoolean();
                string infoSpeciesName = inc.ReadString();

                CharacterInfo info = CharacterInfo.ClientRead(infoSpeciesName, inc);

                character        = Create(speciesName, position, seed, characterInfo: info, id: id, isRemotePlayer: ownerId > 0 && GameMain.Client.ID != ownerId, hasAi: hasAi);
                character.TeamID = (CharacterTeamType)teamID;
                character.CampaignInteractionType = (CampaignMode.InteractionType)inc.ReadByte();
                if (character.CampaignInteractionType != CampaignMode.InteractionType.None)
                {
                    (GameMain.GameSession.GameMode as CampaignMode)?.AssignNPCMenuInteraction(character, character.CampaignInteractionType);
                }

                // Check if the character has current orders
                int orderCount = inc.ReadByte();
                for (int i = 0; i < orderCount; i++)
                {
                    int         orderPrefabIndex = inc.ReadByte();
                    Entity      targetEntity     = FindEntityByID(inc.ReadUInt16());
                    Character   orderGiver       = inc.ReadBoolean() ? FindEntityByID(inc.ReadUInt16()) as Character : null;
                    int         orderOptionIndex = inc.ReadByte();
                    int         orderPriority    = inc.ReadByte();
                    OrderTarget targetPosition   = null;
                    if (inc.ReadBoolean())
                    {
                        var x    = inc.ReadSingle();
                        var y    = inc.ReadSingle();
                        var hull = FindEntityByID(inc.ReadUInt16()) as Hull;
                        targetPosition = new OrderTarget(new Vector2(x, y), hull, true);
                    }

                    if (orderPrefabIndex >= 0 && orderPrefabIndex < Order.PrefabList.Count)
                    {
                        var orderPrefab = Order.PrefabList[orderPrefabIndex];
                        var component   = orderPrefab.GetTargetItemComponent(targetEntity as Item);
                        if (!orderPrefab.MustSetTarget || (targetEntity != null && component != null) || targetPosition != null)
                        {
                            var order = targetPosition == null ?
                                        new Order(orderPrefab, targetEntity, component, orderGiver: orderGiver) :
                                        new Order(orderPrefab, targetPosition, orderGiver: orderGiver);
                            character.SetOrder(order,
                                               orderOptionIndex >= 0 && orderOptionIndex < orderPrefab.Options.Length ? orderPrefab.Options[orderOptionIndex] : null,
                                               orderPriority, orderGiver, speak: false);
                        }
                        else
                        {
                            DebugConsole.ThrowError("Could not set order \"" + orderPrefab.Identifier + "\" for character \"" + character.Name + "\" because required target entity was not found.");
                        }
                    }
                    else
                    {
                        DebugConsole.ThrowError("Invalid order prefab index - index (" + orderPrefabIndex + ") out of bounds.");
                    }
                }

                bool containsStatusData = inc.ReadBoolean();
                if (containsStatusData)
                {
                    character.ReadStatus(inc);
                }

                if (character.IsHuman && character.TeamID != CharacterTeamType.FriendlyNPC && character.TeamID != CharacterTeamType.None && !character.IsDead)
                {
                    CharacterInfo duplicateCharacterInfo = GameMain.GameSession.CrewManager.GetCharacterInfos().FirstOrDefault(c => c.ID == info.ID);
                    GameMain.GameSession.CrewManager.RemoveCharacterInfo(duplicateCharacterInfo);
                    GameMain.GameSession.CrewManager.AddCharacter(character);
                }

                if (GameMain.Client.ID == ownerId)
                {
                    GameMain.Client.HasSpawned = true;
                    GameMain.Client.Character  = character;
                    if (!character.IsDead)
                    {
                        Controlled = character;
                    }

                    GameMain.LightManager.LosEnabled = true;
                    GameMain.LightManager.LosAlpha   = 1f;

                    character.memInput.Clear();
                    character.memState.Clear();
                    character.memLocalState.Clear();
                }
            }

            character.Enabled = Controlled == character || enabled;

            return(character);
        }
Ejemplo n.º 23
0
        public static void ServerRead(IReadMessage msg, Client c)
        {
            c.KickAFKTimer = 0.0f;

            UInt16          ID   = msg.ReadUInt16();
            ChatMessageType type = (ChatMessageType)msg.ReadByte();
            string          txt;

            Character        orderTargetCharacter = null;
            Entity           orderTargetEntity    = null;
            OrderChatMessage orderMsg             = null;
            OrderTarget      orderTargetPosition  = null;

            Order.OrderTargetType orderTargetType = Order.OrderTargetType.Entity;
            int?wallSectionIndex = null;

            if (type == ChatMessageType.Order)
            {
                int orderIndex = msg.ReadByte();
                orderTargetCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character;
                orderTargetEntity    = Entity.FindEntityByID(msg.ReadUInt16()) as Entity;

                Order  orderPrefab      = null;
                int?   orderOptionIndex = 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")
                    {
                        orderOptionIndex = 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
                {
                    orderOptionIndex = msg.ReadByte();
                }

                int orderPriority = msg.ReadByte();
                orderTargetType = (Order.OrderTargetType)msg.ReadByte();
                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, true);
                }
                else if (orderTargetType == Order.OrderTargetType.WallSection)
                {
                    wallSectionIndex = msg.ReadByte();
                }

                if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
                {
                    DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderIndex}).");
                    if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID))
                    {
                        c.LastSentChatMsgID = ID;
                    }
                    return;
                }

                orderPrefab ??= Order.PrefabList[orderIndex];
                orderOption ??= orderOptionIndex == null || orderOptionIndex < 0 || orderOptionIndex >= orderPrefab.Options.Length ? "" : orderPrefab.Options[orderOptionIndex.Value];
                orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderPriority, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character)
                {
                    WallSectionIndex = wallSectionIndex
                };
                txt = orderMsg.Text;
            }
            else
            {
                txt = msg.ReadString() ?? "";
            }

            if (!NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID))
            {
                return;
            }

            c.LastSentChatMsgID = ID;

            if (txt.Length > MaxLength)
            {
                txt = txt.Substring(0, MaxLength);
            }

            c.LastSentChatMessages.Add(txt);
            if (c.LastSentChatMessages.Count > 10)
            {
                c.LastSentChatMessages.RemoveRange(0, c.LastSentChatMessages.Count - 10);
            }

            float similarity = 0.0f;

            for (int i = 0; i < c.LastSentChatMessages.Count; i++)
            {
                float closeFactor = 1.0f / (c.LastSentChatMessages.Count - i);

                if (string.IsNullOrEmpty(txt))
                {
                    similarity += closeFactor;
                }
                else
                {
                    int levenshteinDist = ToolBox.LevenshteinDistance(txt, c.LastSentChatMessages[i]);
                    similarity += Math.Max((txt.Length - levenshteinDist) / (float)txt.Length * closeFactor, 0.0f);
                }
            }
            //order/report messages can be sent a little faster than normal messages without triggering the spam filter
            if (orderMsg != null)
            {
                similarity *= 0.25f;
            }

            bool isOwner = GameMain.Server.OwnerConnection != null && c.Connection == GameMain.Server.OwnerConnection;

            if (similarity + c.ChatSpamSpeed > 5.0f && !isOwner)
            {
                GameMain.Server.KarmaManager.OnSpamFilterTriggered(c);

                c.ChatSpamCount++;
                if (c.ChatSpamCount > 3)
                {
                    //kick for spamming too much
                    GameMain.Server.KickClient(c, TextManager.Get("SpamFilterKicked"));
                }
                else
                {
                    ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
                    c.ChatSpamTimer = 10.0f;
                    GameMain.Server.SendDirectChatMessage(denyMsg, c);
                }
                return;
            }

            c.ChatSpamSpeed += similarity + 0.5f;

            if (c.ChatSpamTimer > 0.0f && !isOwner)
            {
                ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
                c.ChatSpamTimer = 10.0f;
                GameMain.Server.SendDirectChatMessage(denyMsg, c);
                return;
            }

            if (type == ChatMessageType.Order)
            {
                if (c.Character == null || c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead)
                {
                    return;
                }
                Order order = null;
                if (orderMsg.Order.IsReport)
                {
                    HumanAIController.ReportProblem(orderMsg.Sender, orderMsg.Order);
                }
                else if (orderTargetCharacter != null && !orderMsg.Order.TargetAllCharacters)
                {
                    switch (orderTargetType)
                    {
                    case Order.OrderTargetType.Entity:
                        order = new Order(orderMsg.Order.Prefab, orderTargetEntity, orderMsg.Order.Prefab?.GetTargetItemComponent(orderTargetEntity as Item), orderGiver: orderMsg.Sender);
                        break;

                    case Order.OrderTargetType.Position:
                        order = new Order(orderMsg.Order.Prefab, orderTargetPosition, orderGiver: orderMsg.Sender);
                        break;
                    }
                    if (order != null)
                    {
                        orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.OrderPriority, orderMsg.Sender);
                    }
                }
                else if (orderMsg.Order.IsIgnoreOrder)
                {
                    switch (orderTargetType)
                    {
                    case Order.OrderTargetType.Entity:
                        if (orderTargetEntity is IIgnorable ignorableEntity)
                        {
                            ignorableEntity.OrderedToBeIgnored = orderMsg.Order.Identifier == "ignorethis";
                        }
                        break;

                    case Order.OrderTargetType.WallSection:
                        if (!wallSectionIndex.HasValue)
                        {
                            break;
                        }
                        if (orderTargetEntity is Structure s && s.GetSection(wallSectionIndex.Value) is IIgnorable ignorableWall)
                        {
                            ignorableWall.OrderedToBeIgnored = orderMsg.Order.Identifier == "ignorethis";
                        }
                        break;
                    }
                }
                GameMain.Server.SendOrderChatMessage(orderMsg);
            }
            else
            {
                GameMain.Server.SendChatMessage(txt, null, c);
            }
        }
Ejemplo n.º 24
0
        public void ServerReadCrew(IReadMessage msg, Client sender)
        {
            int[] pendingHires = null;

            bool updatePending = msg.ReadBoolean();

            if (updatePending)
            {
                ushort pendingHireLength = msg.ReadUInt16();
                pendingHires = new int[pendingHireLength];
                for (int i = 0; i < pendingHireLength; i++)
                {
                    pendingHires[i] = msg.ReadInt32();
                }
            }

            bool validateHires = msg.ReadBoolean();
            bool fireCharacter = msg.ReadBoolean();

            int firedIdentifier = -1;

            if (fireCharacter)
            {
                firedIdentifier = msg.ReadInt32();
            }

            Location location = map?.CurrentLocation;

            CharacterInfo firedCharacter = null;

            if (location != null && AllowedToManageCampaign(sender))
            {
                if (fireCharacter)
                {
                    firedCharacter = CrewManager.CharacterInfos.FirstOrDefault(info => info.GetIdentifier() == firedIdentifier);
                    if (firedCharacter != null && (firedCharacter.Character?.IsBot ?? true))
                    {
                        CrewManager.FireCharacter(firedCharacter);
                    }
                    else
                    {
                        DebugConsole.ThrowError($"Tried to fire an invalid character ({firedIdentifier})");
                    }
                }

                if (location.HireManager != null)
                {
                    if (validateHires)
                    {
                        foreach (CharacterInfo hireInfo in location.HireManager.PendingHires)
                        {
                            TryHireCharacter(location, hireInfo);
                        }
                    }

                    if (updatePending)
                    {
                        List <CharacterInfo> pendingHireInfos = new List <CharacterInfo>();
                        foreach (int identifier in pendingHires)
                        {
                            CharacterInfo match = location.GetHireableCharacters().FirstOrDefault(info => info.GetIdentifier() == identifier);
                            if (match == null)
                            {
                                DebugConsole.ThrowError($"Tried to hire a character that doesn't exist ({identifier})");
                                continue;
                            }

                            pendingHireInfos.Add(match);
                        }
                        location.HireManager.PendingHires = pendingHireInfos;
                    }
                }
            }

            // bounce back
            SendCrewState(validateHires, firedCharacter);
        }
Ejemplo n.º 25
0
        private void ApplyRemoteState(IReadMessage msg)
        {
            List <Wire> prevWires = Connections.SelectMany(c => c.Wires.Where(w => w != null)).ToList();
            List <Wire> newWires  = new List <Wire>();

            ushort userID = msg.ReadUInt16();

            if (userID == 0)
            {
                user = null;
            }
            else
            {
                user          = Entity.FindEntityByID(userID) as Character;
                base.IsActive = true;
            }

            foreach (Connection connection in Connections)
            {
                connection.ClearConnections();
            }

            foreach (Connection connection in Connections)
            {
                for (int i = 0; i < connection.MaxWires; i++)
                {
                    ushort wireId = msg.ReadUInt16();

                    if (!(Entity.FindEntityByID(wireId) is Item wireItem))
                    {
                        continue;
                    }
                    Wire wireComponent = wireItem.GetComponent <Wire>();
                    if (wireComponent == null)
                    {
                        continue;
                    }

                    newWires.Add(wireComponent);

                    connection.SetWire(i, wireComponent);
                    wireComponent.Connect(connection, false);
                }
            }

            List <Wire> previousDisconnectedWires = new List <Wire>(DisconnectedWires);

            DisconnectedWires.Clear();
            ushort disconnectedWireCount = msg.ReadUInt16();

            for (int i = 0; i < disconnectedWireCount; i++)
            {
                ushort wireId = msg.ReadUInt16();
                if (!(Entity.FindEntityByID(wireId) is Item wireItem))
                {
                    continue;
                }
                Wire wireComponent = wireItem.GetComponent <Wire>();
                if (wireComponent == null)
                {
                    continue;
                }
                DisconnectedWires.Add(wireComponent);
                base.IsActive = true;
            }

            foreach (Wire wire in prevWires)
            {
                bool connected = wire.Connections[0] != null || wire.Connections[1] != null;
                if (!connected)
                {
                    foreach (Item item in Item.ItemList)
                    {
                        var connectionPanel = item.GetComponent <ConnectionPanel>();
                        if (connectionPanel != null && connectionPanel.DisconnectedWires.Contains(wire))
                        {
                            connected = true;
                            break;
                        }
                    }
                }
                if (wire.Item.ParentInventory == null && !connected)
                {
                    wire.Item.Drop(null);
                }
            }

            foreach (Wire disconnectedWire in previousDisconnectedWires)
            {
                if (disconnectedWire.Connections[0] == null &&
                    disconnectedWire.Connections[1] == null &&
                    !DisconnectedWires.Contains(disconnectedWire))
                {
                    disconnectedWire.Item.Drop(dropper: null);
                }
            }
        }
Ejemplo n.º 26
0
        public void ServerRead(IReadMessage msg, Client sender)
        {
            UInt16 currentLocIndex  = msg.ReadUInt16();
            UInt16 selectedLocIndex = msg.ReadUInt16();

            byte       selectedMissionCount   = msg.ReadByte();
            List <int> selectedMissionIndices = new List <int>();

            for (int i = 0; i < selectedMissionCount; i++)
            {
                selectedMissionIndices.Add(msg.ReadByte());
            }

            bool purchasedHullRepairs  = msg.ReadBoolean();
            bool purchasedItemRepairs  = msg.ReadBoolean();
            bool purchasedLostShuttles = msg.ReadBoolean();

            UInt16 buyCrateItemCount           = msg.ReadUInt16();
            List <PurchasedItem> buyCrateItems = new List <PurchasedItem>();

            for (int i = 0; i < buyCrateItemCount; i++)
            {
                string itemPrefabIdentifier = msg.ReadString();
                int    itemQuantity         = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
                buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
            }

            UInt16 purchasedItemCount           = msg.ReadUInt16();
            List <PurchasedItem> purchasedItems = new List <PurchasedItem>();

            for (int i = 0; i < purchasedItemCount; i++)
            {
                string itemPrefabIdentifier = msg.ReadString();
                int    itemQuantity         = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
                purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
            }

            UInt16          soldItemCount = msg.ReadUInt16();
            List <SoldItem> soldItems     = new List <SoldItem>();

            for (int i = 0; i < soldItemCount; i++)
            {
                string itemPrefabIdentifier = msg.ReadString();
                UInt16 id       = msg.ReadUInt16();
                bool   removed  = msg.ReadBoolean();
                byte   sellerId = msg.ReadByte();
                soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId));
            }

            ushort purchasedUpgradeCount = msg.ReadUInt16();
            List <PurchasedUpgrade> purchasedUpgrades = new List <PurchasedUpgrade>();

            for (int i = 0; i < purchasedUpgradeCount; i++)
            {
                string        upgradeIdentifier = msg.ReadString();
                UpgradePrefab prefab            = UpgradePrefab.Find(upgradeIdentifier);

                string          categoryIdentifier = msg.ReadString();
                UpgradeCategory category           = UpgradeCategory.Find(categoryIdentifier);

                int upgradeLevel = msg.ReadByte();

                if (category == null || prefab == null)
                {
                    continue;
                }
                purchasedUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel));
            }

            ushort purchasedItemSwapCount = msg.ReadUInt16();
            List <PurchasedItemSwap> purchasedItemSwaps = new List <PurchasedItemSwap>();

            for (int i = 0; i < purchasedItemSwapCount; i++)
            {
                UInt16 itemToRemoveID = msg.ReadUInt16();
                Item   itemToRemove   = Entity.FindEntityByID(itemToRemoveID) as Item;

                string     itemToInstallIdentifier = msg.ReadString();
                ItemPrefab itemToInstall           = string.IsNullOrEmpty(itemToInstallIdentifier) ? null : ItemPrefab.Find(string.Empty, itemToInstallIdentifier);

                if (itemToRemove == null)
                {
                    continue;
                }

                purchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall));
            }

            if (!AllowedToManageCampaign(sender))
            {
                DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign");
                return;
            }

            Location location            = Map.CurrentLocation;
            int      hullRepairCost      = location?.GetAdjustedMechanicalCost(HullRepairCost) ?? HullRepairCost;
            int      itemRepairCost      = location?.GetAdjustedMechanicalCost(ItemRepairCost) ?? ItemRepairCost;
            int      shuttleRetrieveCost = location?.GetAdjustedMechanicalCost(ShuttleReplaceCost) ?? ShuttleReplaceCost;

            if (purchasedHullRepairs != this.PurchasedHullRepairs)
            {
                if (purchasedHullRepairs && Money >= hullRepairCost)
                {
                    this.PurchasedHullRepairs = true;
                    Money -= hullRepairCost;
                }
                else if (!purchasedHullRepairs)
                {
                    this.PurchasedHullRepairs = false;
                    Money += hullRepairCost;
                }
            }
            if (purchasedItemRepairs != this.PurchasedItemRepairs)
            {
                if (purchasedItemRepairs && Money >= itemRepairCost)
                {
                    this.PurchasedItemRepairs = true;
                    Money -= itemRepairCost;
                }
                else if (!purchasedItemRepairs)
                {
                    this.PurchasedItemRepairs = false;
                    Money += itemRepairCost;
                }
            }
            if (purchasedLostShuttles != this.PurchasedLostShuttles)
            {
                if (GameMain.GameSession?.SubmarineInfo != null &&
                    GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied)
                {
                    GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("ReplaceShuttleDockingPortOccupied"), sender, ChatMessageType.MessageBox);
                }
                else if (purchasedLostShuttles && Money >= shuttleRetrieveCost)
                {
                    this.PurchasedLostShuttles = true;
                    Money -= shuttleRetrieveCost;
                }
                else if (!purchasedItemRepairs)
                {
                    this.PurchasedLostShuttles = false;
                    Money += shuttleRetrieveCost;
                }
            }

            if (currentLocIndex < Map.Locations.Count && Map.AllowDebugTeleport)
            {
                Map.SetLocation(currentLocIndex);
            }

            Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
            if (Map.SelectedLocation == null)
            {
                Map.SelectRandomLocation(preferUndiscovered: true);
            }
            if (Map.SelectedConnection != null)
            {
                Map.SelectMission(selectedMissionIndices);
            }

            CheckTooManyMissions(Map.CurrentLocation, sender);

            List <PurchasedItem> currentBuyCrateItems = new List <PurchasedItem>(CargoManager.ItemsInBuyCrate);

            currentBuyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, -i.Quantity));
            buyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, i.Quantity));

            CargoManager.SellBackPurchasedItems(new List <PurchasedItem>(CargoManager.PurchasedItems));
            CargoManager.PurchaseItems(purchasedItems, false);

            // for some reason CargoManager.SoldItem is never cleared by the server, I've added a check to SellItems that ignores all
            // sold items that are removed so they should be discarded on the next message
            CargoManager.BuyBackSoldItems(new List <SoldItem>(CargoManager.SoldItems));
            CargoManager.SellItems(soldItems);

            foreach (var(prefab, category, _) in purchasedUpgrades)
            {
                UpgradeManager.PurchaseUpgrade(prefab, category);

                // unstable logging
                int price = prefab.Price.GetBuyprice(UpgradeManager.GetUpgradeLevel(prefab, category), Map?.CurrentLocation);
                int level = UpgradeManager.GetUpgradeLevel(prefab, category);
                GameServer.Log($"SERVER: Purchased level {level} {category.Identifier}.{prefab.Identifier} for {price}", ServerLog.MessageType.ServerMessage);
            }

            foreach (var purchasedItemSwap in purchasedItemSwaps)
            {
                if (purchasedItemSwap.ItemToInstall == null)
                {
                    UpgradeManager.CancelItemSwap(purchasedItemSwap.ItemToRemove);
                }
                else
                {
                    UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall);
                }
            }
            foreach (Item item in Item.ItemList)
            {
                if (item.PendingItemSwap != null && !purchasedItemSwaps.Any(it => it.ItemToRemove == item))
                {
                    UpgradeManager.CancelItemSwap(item);
                    item.PendingItemSwap = null;
                }
            }
        }
Ejemplo n.º 27
0
        public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
        {
            bool launch = msg.ReadBoolean();

            if (launch)
            {
                ushort userId = msg.ReadUInt16();
                User = Entity.FindEntityByID(userId) as Character;
                Vector2 simPosition = new Vector2(msg.ReadSingle(), msg.ReadSingle());
                float   rotation    = msg.ReadSingle();
                if (User != null)
                {
                    Shoot(User, simPosition, simPosition, rotation, ignoredBodies: User.AnimController.Limbs.Where(l => !l.IsSevered).Select(l => l.body.FarseerBody).ToList(), createNetworkEvent: false);
                }
                else
                {
                    Launch(User, simPosition, rotation);
                }
            }

            bool isStuck = msg.ReadBoolean();

            if (isStuck)
            {
                ushort  submarineID = msg.ReadUInt16();
                ushort  hullID      = msg.ReadUInt16();
                Vector2 simPosition = new Vector2(
                    msg.ReadSingle(),
                    msg.ReadSingle());
                Vector2 axis = new Vector2(
                    msg.ReadSingle(),
                    msg.ReadSingle());
                UInt16 entityID = msg.ReadUInt16();

                Entity    entity    = Entity.FindEntityByID(entityID);
                Submarine submarine = Entity.FindEntityByID(submarineID) as Submarine;
                Hull      hull      = Entity.FindEntityByID(hullID) as Hull;
                item.Submarine   = submarine;
                item.CurrentHull = hull;
                item.body.SetTransform(simPosition, item.body.Rotation);
                if (entity is Character character)
                {
                    byte limbIndex = msg.ReadByte();
                    if (limbIndex >= character.AnimController.Limbs.Length)
                    {
                        DebugConsole.ThrowError($"Failed to read a projectile update from the server. Limb index out of bounds ({limbIndex}, character: {character.ToString()})");
                        return;
                    }
                    if (character.Removed)
                    {
                        return;
                    }
                    var limb = character.AnimController.Limbs[limbIndex];
                    StickToTarget(limb.body.FarseerBody, axis);
                }
                else if (entity is Structure structure)
                {
                    byte bodyIndex = msg.ReadByte();
                    if (bodyIndex == 255)
                    {
                        bodyIndex = 0;
                    }
                    if (bodyIndex >= structure.Bodies.Count)
                    {
                        DebugConsole.ThrowError($"Failed to read a projectile update from the server. Structure body index out of bounds ({bodyIndex}, structure: {structure.ToString()})");
                        return;
                    }
                    var body = structure.Bodies[bodyIndex];
                    StickToTarget(body, axis);
                }
                else if (entity is Item item)
                {
                    if (item.Removed)
                    {
                        return;
                    }
                    var door = item.GetComponent <Door>();
                    if (door != null)
                    {
                        StickToTarget(door.Body.FarseerBody, axis);
                    }
                    else if (item.body != null)
                    {
                        StickToTarget(item.body.FarseerBody, axis);
                    }
                }
                else if (entity is  Submarine sub)
                {
                    StickToTarget(sub.PhysicsBody.FarseerBody, axis);
                }
                else
                {
                    DebugConsole.ThrowError($"Failed to read a projectile update from the server. Invalid stick target ({entity?.ToString() ?? "null"}, {entityID})");
                }
            }
            else
            {
                Unstick();
            }
        }
Ejemplo n.º 28
0
        public void ServerReadCrew(IReadMessage msg, Client sender)
        {
            int[] pendingHires = null;

            bool updatePending = msg.ReadBoolean();

            if (updatePending)
            {
                ushort pendingHireLength = msg.ReadUInt16();
                pendingHires = new int[pendingHireLength];
                for (int i = 0; i < pendingHireLength; i++)
                {
                    pendingHires[i] = msg.ReadInt32();
                }
            }

            bool validateHires = msg.ReadBoolean();

            bool   renameCharacter    = msg.ReadBoolean();
            int    renamedIdentifier  = -1;
            string newName            = null;
            bool   existingCrewMember = false;

            if (renameCharacter)
            {
                renamedIdentifier  = msg.ReadInt32();
                newName            = msg.ReadString();
                existingCrewMember = msg.ReadBoolean();
            }

            bool fireCharacter   = msg.ReadBoolean();
            int  firedIdentifier = -1;

            if (fireCharacter)
            {
                firedIdentifier = msg.ReadInt32();
            }

            Location             location        = map?.CurrentLocation;
            List <CharacterInfo> hiredCharacters = new List <CharacterInfo>();
            CharacterInfo        firedCharacter  = null;

            if (location != null && AllowedToManageCampaign(sender))
            {
                if (fireCharacter)
                {
                    firedCharacter = CrewManager.CharacterInfos.FirstOrDefault(info => info.GetIdentifier() == firedIdentifier);
                    if (firedCharacter != null && (firedCharacter.Character?.IsBot ?? true))
                    {
                        CrewManager.FireCharacter(firedCharacter);
                    }
                    else
                    {
                        DebugConsole.ThrowError($"Tried to fire an invalid character ({firedIdentifier})");
                    }
                }

                if (renameCharacter)
                {
                    CharacterInfo characterInfo = null;
                    if (existingCrewMember && CrewManager != null)
                    {
                        characterInfo = CrewManager.CharacterInfos.FirstOrDefault(info => info.GetIdentifierUsingOriginalName() == renamedIdentifier);
                    }
                    else if (!existingCrewMember && location.HireManager != null)
                    {
                        characterInfo = location.HireManager.AvailableCharacters.FirstOrDefault(info => info.GetIdentifierUsingOriginalName() == renamedIdentifier);
                    }

                    if (characterInfo != null && (characterInfo.Character?.IsBot ?? true))
                    {
                        if (existingCrewMember)
                        {
                            CrewManager.RenameCharacter(characterInfo, newName);
                        }
                        else
                        {
                            location.HireManager.RenameCharacter(characterInfo, newName);
                        }
                    }
                    else
                    {
                        DebugConsole.ThrowError($"Tried to rename an invalid character ({renamedIdentifier})");
                    }
                }

                if (location.HireManager != null)
                {
                    if (validateHires)
                    {
                        foreach (CharacterInfo hireInfo in location.HireManager.PendingHires)
                        {
                            if (TryHireCharacter(location, hireInfo))
                            {
                                hiredCharacters.Add(hireInfo);
                            }
                            ;
                        }
                    }

                    if (updatePending)
                    {
                        List <CharacterInfo> pendingHireInfos = new List <CharacterInfo>();
                        foreach (int identifier in pendingHires)
                        {
                            CharacterInfo match = location.GetHireableCharacters().FirstOrDefault(info => info.GetIdentifierUsingOriginalName() == identifier);
                            if (match == null)
                            {
                                DebugConsole.ThrowError($"Tried to add a character that doesn't exist ({identifier}) to pending hires");
                                continue;
                            }

                            pendingHireInfos.Add(match);
                            if (pendingHireInfos.Count + CrewManager.CharacterInfos.Count() >= CrewManager.MaxCrewSize)
                            {
                                break;
                            }
                        }
                        location.HireManager.PendingHires = pendingHireInfos;
                    }

                    location.HireManager.AvailableCharacters.ForEachMod(info =>
                    {
                        if (!location.HireManager.PendingHires.Contains(info))
                        {
                            location.HireManager.RenameCharacter(info, info.OriginalName);
                        }
                    });
                }
            }

            // bounce back
            if (renameCharacter && existingCrewMember)
            {
                SendCrewState(hiredCharacters, (renamedIdentifier, newName), firedCharacter);
            }
            else
            {
                SendCrewState(hiredCharacters, default, firedCharacter);
Ejemplo n.º 29
0
        public void ServerRead(IReadMessage msg, Client sender)
        {
            UInt16 selectedLocIndex      = msg.ReadUInt16();
            byte   selectedMissionIndex  = msg.ReadByte();
            bool   purchasedHullRepairs  = msg.ReadBoolean();
            bool   purchasedItemRepairs  = msg.ReadBoolean();
            bool   purchasedLostShuttles = msg.ReadBoolean();
            UInt16 purchasedItemCount    = msg.ReadUInt16();

            List <PurchasedItem> purchasedItems = new List <PurchasedItem>();

            for (int i = 0; i < purchasedItemCount; i++)
            {
                string itemPrefabIdentifier = msg.ReadString();
                int    itemQuantity         = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
                purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
            }

            if (!sender.HasPermission(ClientPermissions.ManageCampaign))
            {
                DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign");
                return;
            }

            if (purchasedHullRepairs != this.PurchasedHullRepairs)
            {
                if (purchasedHullRepairs && Money >= HullRepairCost)
                {
                    this.PurchasedHullRepairs = true;
                    Money -= HullRepairCost;
                }
                else if (!purchasedHullRepairs)
                {
                    this.PurchasedHullRepairs = false;
                    Money += HullRepairCost;
                }
            }
            if (purchasedItemRepairs != this.PurchasedItemRepairs)
            {
                if (purchasedItemRepairs && Money >= ItemRepairCost)
                {
                    this.PurchasedItemRepairs = true;
                    Money -= ItemRepairCost;
                }
                else if (!purchasedItemRepairs)
                {
                    this.PurchasedItemRepairs = false;
                    Money += ItemRepairCost;
                }
            }
            if (purchasedLostShuttles != this.PurchasedLostShuttles)
            {
                if (GameMain.GameSession?.SubmarineInfo != null &&
                    GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied)
                {
                    GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("ReplaceShuttleDockingPortOccupied"), sender, ChatMessageType.MessageBox);
                }
                else if (purchasedLostShuttles && Money >= ShuttleReplaceCost)
                {
                    this.PurchasedLostShuttles = true;
                    Money -= ShuttleReplaceCost;
                }
                else if (!purchasedItemRepairs)
                {
                    this.PurchasedLostShuttles = false;
                    Money += ShuttleReplaceCost;
                }
            }

            Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
            if (Map.SelectedLocation == null)
            {
                Map.SelectRandomLocation(preferUndiscovered: true);
            }
            if (Map.SelectedConnection != null)
            {
                Map.SelectMission(selectedMissionIndex);
            }

            List <PurchasedItem> currentItems = new List <PurchasedItem>(CargoManager.PurchasedItems);

            foreach (PurchasedItem pi in currentItems)
            {
                CargoManager.SellItem(pi, pi.Quantity);
            }

            foreach (PurchasedItem pi in purchasedItems)
            {
                CargoManager.PurchaseItem(pi.ItemPrefab, pi.Quantity);
            }
        }
Ejemplo n.º 30
0
        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, 4);
                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.type, causeOfDeath.affliction);
                    }
                    break;

                case 3:         // NetEntityEvent.Type.UpdateTalents
                    if (c.Character != this)
                    {
#if DEBUG
                        DebugConsole.Log("Received a character update message from a client who's not controlling the character");
#endif
                        return;
                    }

                    // get the full list of talents from the player, only give the ones
                    // that are not already given (or otherwise not viable)
                    ushort        talentCount     = msg.ReadUInt16();
                    List <string> talentSelection = new List <string>();
                    for (int i = 0; i < talentCount; i++)
                    {
                        UInt32 talentIdentifier = msg.ReadUInt32();
                        var    prefab           = TalentPrefab.TalentPrefabs.Find(p => p.UIntIdentifier == talentIdentifier);
                        if (prefab != null)
                        {
                            talentSelection.Add(prefab.Identifier);
                        }
                    }
                    talentSelection = TalentTree.CheckTalentSelection(this, talentSelection);

                    foreach (string talent in talentSelection)
                    {
                        GiveTalent(talent);
                    }

                    break;
                }
                break;
            }
            msg.ReadPadBits();
        }