Ejemplo n.º 1
0
            public void AddOrUpdateBag(uint bagID, ulong playerID, List <ulong> players)
            {
                bool          isPublic = players == null || players.Count == 0;
                SharedBagInfo i        = sharedBags.FirstOrDefault(s => s.bagId == bagID);

                if (i == null)
                {
                    sharedBags.Add(i = new SharedBagInfo(bagID, playerID, isPublic));
                }
                if (!i.isPublic && !isPublic)
                {
                    i.sharedWith.UnionWith(players);
                }
            }
Ejemplo n.º 2
0
            public bool RemoveOrUpdateBag(uint bagID, List <ulong> players, bool all = false)
            {
                if (sharedBags == null || sharedBags.Count == 0)
                {
                    return(false);
                }
                SharedBagInfo i = sharedBags.FirstOrDefault(s => s.bagId == bagID);

                if (i == null)
                {
                    return(false);
                }
                if (i.isPublic || all)
                {
                    return(sharedBags.Remove(i));
                }
                i.sharedWith.ExceptWith(players);
                if (i.sharedWith.Count == 0)
                {
                    sharedBags.Remove(i);
                }
                return(true);
            }
Ejemplo n.º 3
0
        // command delegator
        void CommandDelegator(BasePlayer player, string command, string[] args)
        {
            if (!hasPermission(player, PermCanUse))
            {
                return;
            }

            string message = "InvalidCommand";

            // assume args[0] is the command (beyond /bed)
            if (args != null && args.Length > 0)
            {
                command = args[0];
            }
            // shift arguments
            if (args != null)
            {
                if (args.Length > 1)
                {
                    args = args.Skip(1).ToArray();
                }
                else
                {
                    args = new string[] { }
                };
            }
            object[] opts = new object[] { command };
            if (Enum.IsDefined(typeof(Command), command))
            {
                Command cmd = (Command)Enum.Parse(typeof(Command), command);
                if ((!hasPermission(player, PermCanSharePublic) && (cmd == Command.share || cmd == Command.unshare)) ||
                    (!hasPermission(player, PermCanSharePrivate) && (cmd == Command.sharewith || cmd == Command.unsharewith)))
                {
                    return;
                }
                switch (cmd)
                {
                case Command.clear:
                    if (hasPermission(player, PermCanClear))
                    {
                        HandleClear(out message, out opts);
                    }
                    else
                    {
                        message = "NoClearPerm";
                    }
                    break;

                case Command.share:
                    HandleShare(player, true, null, out message, out opts);
                    break;

                case Command.sharewith:
                    if (args == null && args.Length == 0)
                    {
                        message = "InvalidArguments";
                        break;
                    }
                    HandleShare(player, true, args, out message, out opts);
                    break;

                case Command.status:
                    HandleStatus(player, out message, out opts);
                    break;

                case Command.unshare:
                    HandleShare(player, false, null, out message, out opts);
                    break;

                case Command.unsharewith:
                    if (args == null && args.Length == 0)
                    {
                        message = "InvalidArguments";
                        break;
                    }
                    HandleShare(player, false, args, out message, out opts);
                    break;

                default:
                    break;
                }
            }
            else
            {
                ShowCommands(out message, out opts);
            }
            if (message != null && message != "")
            {
                SendMessage(player, message, opts);
            }
        }

        // handle sharing/unsharing
        void HandleShare(BasePlayer player, bool share, string[] args, out string message, out object[] opts)
        {
            message = "ShareSuccess";
            opts    = new object[] { "bag", share ? "shared" : "unshared" };

            bool          with    = args != null;
            bool          all     = false;
            List <ulong>  players = new List <ulong>();
            List <string> names   = new List <string>();

            if (with)
            {
                foreach (string s in args)
                {
                    if (!share && s == "all")
                    {
                        all = true;
                        break;
                    }
                    BasePlayer p = rust.FindPlayer(s);
                    if (p == null)
                    {
                        names.Add(s);
                        continue;
                    }
                    players.Add(p.userID);
                }
            }

            if (with && !all && (players.Count == 0 || players.Count != args.Length))
            {
                message = "PlayersNotFound";
                opts    = new object[] { string.Join(", ", names.ToArray()) };
                return;
            }

            object entity;

            if (GetRaycastTarget(player, out entity) && entity is SleepingBag)
            {
                SleepingBag bag = entity as SleepingBag;
                if (bag.ShortPrefabName == BedPrefabName)
                {
                    opts[0] = "bed";
                }
                if (bag.deployerUserID != player.userID && !isAdmin(player))
                {
                    message = "CannotShareOther";
                    opts[1] = "share";
                    return;
                }
                else
                {
                    if (share)
                    {
                        bag.secondsBetweenReuses = 0f;
                        data.AddOrUpdateBag(bag.net.ID, bag.deployerUserID, players);
                        playerNameCache[player.userID] = player.displayName;
                    }
                    else
                    {
                        if (!data.RemoveOrUpdateBag(bag.net.ID, players, all))
                        {
                            message = "NotShared";
                        }
                    }
                }
            }
            else
            {
                message = "NoBag";
                opts    = new object[] { };
            }
        }

        // handle checking status of a bed/bag
        void HandleStatus(BasePlayer player, out string message, out object[] opts)
        {
            message = "Status";
            opts    = new object[] { "bag", "unshared" };
            object entity;

            if (GetRaycastTarget(player, out entity) && entity is SleepingBag)
            {
                SleepingBag bag = entity as SleepingBag;
                if (bag.ShortPrefabName == BedPrefabName)
                {
                    opts[0] = "bed";
                }
                SharedBagInfo i = data.sharedBags.FirstOrDefault(s => s.bagId == bag.net.ID);
                if (i != null)
                {
                    opts[1] = "shared " + (i.isPublic ? " (public)" : " (private)");
                }
            }
            else
            {
                message = "NoBag";
                opts    = new object[] { };
            }
        }

        // handle clearing shared bag/beds
        void HandleClear(out string message, out object[] opts)
        {
            message = "ClearSuccess";
            opts    = new object[] { data.sharedBags.Count };
            data.sharedBags.Clear();
            SaveData();
        }

        #endregion

        #region Hooks

        // on player death, wait for 1s then rebuild respawnInformation including shared beds/bags
        object OnPlayerDie(BasePlayer player, HitInfo hitinfo)
        {
            if (!data.HasSharedBags() || hasPermission(player, PermNoShare, false))
            {
                return(null);
            }
            // after 1 second, send player updated respawn info
            timer.Once(1f, () => {
                using (RespawnInformation respawnInformation = Pool.Get <RespawnInformation>())
                {
                    respawnInformation.spawnOptions = Pool.Get <List <RespawnInformation.SpawnOptions> >();
                    SleepingBag[] sleepingBagArray  = SleepingBag.FindForPlayer(player.userID, true);
                    for (int i = 0; i < (int)sleepingBagArray.Length; i++)
                    {
                        SleepingBag sleepingBag = sleepingBagArray[i];
                        if (data.sharedBags.Count(s => s.bagId == sleepingBag.net.ID) > 0 || dummyBags.ContainsKey(sleepingBag.net.ID))
                        {
                            continue;
                        }
                        RespawnInformation.SpawnOptions d = Pool.Get <RespawnInformation.SpawnOptions>();
                        d.id            = sleepingBag.net.ID;
                        d.name          = sleepingBag.niceName;
                        d.type          = RespawnInformation.SpawnOptions.RespawnType.SleepingBag;
                        d.unlockSeconds = sleepingBag.unlockSeconds;
                        respawnInformation.spawnOptions.Add(d);
                    }
                    respawnInformation.previousLife = SingletonComponent <ServerMgr> .Instance.persistance.GetLastLifeStory(player.userID);
                    respawnInformation.fadeIn       = (respawnInformation.previousLife == null ? false : respawnInformation.previousLife.timeDied > (Epoch.Current - 5));
                    player.ClientRPCPlayer(null, player, "OnRespawnInformation", respawnInformation);
                }
            });
            // after 6 seconds, build/display shared bag/bed UI
            if (data.HasSharedBags())
            {
                timer.Once(6f, () => ShowGUI(player));
            }
            return(null);
        }

        // on respawn, destroy dummy bags and gui
        object OnPlayerRespawn(BasePlayer player)
        {
            DestroyDummyBags(player);
            DestroyGUI(player);
            return(null);
        }

        #endregion

        #region GUI

        // find or create a PlayerUI
        PlayerUI FindPlayerUI(BasePlayer player)
        {
            PlayerUI ui = playerUIs.FirstOrDefault(u => u.UserId == player.userID);

            if (ui == null)
            {
                playerUIs.Add(ui = new PlayerUI(player));
            }
            return(ui);
        }

        void ShowGUI(BasePlayer player)
        {
            PlayerUI ui      = FindPlayerUI(player);
            bool     dirty   = false;
            int      counter = 0;

            foreach (SharedBagInfo entry in data.sharedBags.Where(i => i.isPublic || i.sharedWith.Contains(player.userID)))
            {
                SleepingBag sleepingBag = SleepingBag.FindForPlayer(entry.owner, entry.bagId, true);
                if (sleepingBag == null)
                {
                    dirty = true;                     // no longer a valid shared bag
                    continue;
                }
                uint bagId;
                if (SpawnDummyBag(sleepingBag, player, out bagId))
                {
                    string messageName = "SharedBagNameText";
                    if (!entry.isPublic)
                    {
                        messageName = "SharedBagNameTextPrivate";
                    }
                    string bagName = string.Format(GetMessage(messageName, player.UserIDString), new object[] { sleepingBag.niceName, GetPlayerName(sleepingBag.deployerUserID) });
                    CreateRespawnButton(ui, bagId, bagName, counter++);
                }
            }
            // save changes to shared mappings
            if (dirty)
            {
                ValidateSharedBags();
            }
        }

        void RefreshUI(PlayerUI ui, uint bagId)
        {
            BagUIInfo bag = ui.FindBagInfo(bagId);

            if (bag == null || !ui.IsPanelOpen(bagId))
            {
                return;
            }

            CreateRespawnButton(ui, bag.id, bag.name, bag.index);
        }

        // build respawn button
        void CreateRespawnButton(PlayerUI ui, uint bagId, string bagName, int index)
        {
            BagUIInfo bag = new BagUIInfo()
            {
                id    = bagId,
                index = index,
                name  = bagName
            };
            // set up button position
            float xPosMin = data.ui.screenMarginX;
            float yPosMin = data.ui.screenMarginY + ((data.ui.verticalSpacer + data.ui.buttonHeight) * index);
            float xPosMax = xPosMin + data.ui.buttonWidth;
            float yPosMax = yPosMin + data.ui.buttonHeight;

            Vector2 buttonAnchorMin = new Vector2(xPosMin, yPosMin);
            Vector2 buttonAnchorMax = new Vector2(xPosMax, yPosMax);

            // set up icon layout
            float iconXMin = data.ui.iconPaddingX - data.ui.iconWidth;
            float iconYMin = data.ui.iconPaddingY;
            float iconXMax = data.ui.iconPanelWidth - data.ui.iconWidth;
            float iconYMax = 1f - iconYMin;

            Vector2 iconPosMin = new Vector2(iconXMin, iconYMin);
            Vector2 iconPosMax = new Vector2(iconXMax, iconYMax);

            // set up text layout
            float spawnTextYMin = data.ui.spawnTextPaddingY;

            Vector2 spawnTextPosMin = new Vector2(iconXMax, spawnTextYMin);
            Vector2 spawnTextPosMax = Vector2.one;

            float bagNameTextYMin = data.ui.bagNameTextPaddingY;

            Vector2 bagNameTextPosMin = new Vector2(iconXMax, bagNameTextYMin);
            Vector2 bagNameTextPosMax = new Vector2(1f, spawnTextYMin);

            string headerText = GetMessage("SharedHeaderText", ui.Player?.UserIDString);

            // build GUI elements

            string elementName = UIElementPrefix + bagId;
            string message     = ui.Message(bagId);

            CuiElementContainer container = UI.CreateElementContainer(elementName, data.ui.buttonColor, buttonAnchorMin, buttonAnchorMax);

            UI.CreateLabel(ref container, elementName, headerText, 16, spawnTextPosMin, spawnTextPosMax, TextAnchor.MiddleLeft);
            UI.CreateLabel(ref container, elementName, bagName, 12, bagNameTextPosMin, bagNameTextPosMax, TextAnchor.UpperLeft, "RobotoCondensed-Regular.ttf");
            UI.CreateImage(ref container, elementName, data.ui.bagIcon, data.ui.bagIconColor, iconPosMin, iconPosMax);
            UI.CreateButton(ref container, elementName, new Color(1f, 1f, 1f, 0.05f), string.Empty, 1, Vector2.zero, Vector2.one, ui.BuildCommand(GUIRespawnCommand, bagId));

            ui.CreateUI(bag, container);
            if (!string.IsNullOrEmpty(message))
            {
                OverlayMessageUI(ui, bagId, message, buttonAnchorMin, buttonAnchorMax);
            }
        }

        // create a message overlay on a button
        void OverlayMessageUI(PlayerUI ui, uint id, string message, Vector2 aMin, Vector2 aMax, float displayTime = 5f)
        {
            string panelName = UIElementPrefix + id + "_Message";
            CuiElementContainer container = UI.CreateElementContainer(panelName, new Color(0.7f, 0.3f, 0.3f, 0.9f), aMin, aMax, fadeIn: 0f);

            UI.CreateLabel(ref container, panelName, $"<color=white>{message}</color>", 14, Vector2.zero, Vector2.one, fadeIn: 0f);
            ui.CreateMessageUI(id, container);
            timer.In(displayTime, () => ui.DestroyMessageUI(id));
        }

        // destroy a player's GUI elements
        void DestroyGUI(BasePlayer player, bool kill = false)
        {
            if (kill)
            {
                FindPlayerUI(player).Kill();
            }
            else
            {
                FindPlayerUI(player).DestroyUI();
            }
        }

        // destroy all player GUI elements
        void DestroyAllGUI()
        {
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                DestroyGUI(player, true);
            }
        }

        #endregion

        #region Helper Procedures

        // spawn a dummy bag at location of shared bag/bed to be used as a respawn point
        bool SpawnDummyBag(SleepingBag bag, BasePlayer player, out uint bagId)
        {
            bagId = 0;
            BaseEntity entity = GameManager.server.CreateEntity(bag.PrefabName, bag.transform.position, bag.transform.rotation, false);

            entity.limitNetworking = true;
            entity.Spawn();
            if (entity != null && entity is SleepingBag)
            {
                SleepingBag newBag = entity as SleepingBag;
                newBag.model.enabled        = false;
                newBag.deployerUserID       = player.userID;
                newBag.secondsBetweenReuses = 0f;
                bagId            = newBag.net.ID;
                dummyBags[bagId] = player.userID;
                return(true);
            }
            return(false);
        }

        // Destroy all dummy bags for a player
        void DestroyDummyBags(BasePlayer player)
        {
            uint[] bags = dummyBags.Where(x => x.Value == player.userID).Select(pair => pair.Key).ToArray();
            if (bags == null || bags.Length == 0)
            {
                return;
            }
            foreach (uint bagId in bags)
            {
                SleepingBag.DestroyBag(player, bagId);
            }
        }

        // Destroy all dummy bags
        void DestroyAllDummyBags()
        {
            foreach (KeyValuePair <uint, ulong> entry in dummyBags)
            {
                SleepingBag bag = SleepingBag.FindForPlayer(entry.Value, entry.Key, true);
                if (bag != null)
                {
                    bag.Kill(BaseNetworkable.DestroyMode.None);
                }
            }
            dummyBags.Clear();
        }

        // validate shared bag list
        void ValidateSharedBags()
        {
            if (!data.HasSharedBags())
            {
                return;
            }
            List <uint> toRemove = new List <uint>();

            // check each bag in the shared bags list and remove any invalid bags
            foreach (SharedBagInfo entry in data.sharedBags)
            {
                SleepingBag sleepingBag = SleepingBag.FindForPlayer(entry.owner, entry.bagId, true);
                if (sleepingBag == null)
                {
                    toRemove.Add(entry.bagId);                     // no longer a valid shared bag
                }
            }

            if (data.sharedBags.RemoveWhere(i => toRemove.Contains(i.bagId)) > 0)
            {
                Puts(GetMessage("Prefix") + string.Format(GetMessage("ValidateStats"), new object[] { toRemove.Count }));
                SaveData();
            }
        }

        // handle raycast from player
        bool GetRaycastTarget(BasePlayer player, out object closestEntity)
        {
            closestEntity = false;

            RaycastHit hit;

            if (!Physics.Raycast(player.eyes.HeadRay(), out hit, 5f))
            {
                return(false);
            }

            closestEntity = hit.GetEntity();
            return(true);
        }

        // get a player name (using cache if possible)
        string GetPlayerName(ulong userID)
        {
            if (playerNameCache.ContainsKey(userID))
            {
                return(playerNameCache[userID]);
            }
            else
            {
                BasePlayer player = BasePlayer.FindByID(userID);
                if (player == null)
                {
                    player = BasePlayer.FindSleeping(userID);
                }

                if (player != null)
                {
                    playerNameCache[userID] = player.displayName;
                    return(player.displayName);
                }
            }
            return("unknown");
        }