using System.Collections.Generic; using System.Linq; using UnityEngine; namespace Oxide.Plugins { [Info("Inventory Viewer", "Mughisi", "3.0.3", ResourceId = 871)] [Description("Allows players with permission assigned to view anyone's inventory")] public class InventoryViewer : RustPlugin { private readonly string RequiredPermission = "inventoryviewer.allowed"; private readonly Dictionary> matches = new Dictionary>(); /// /// UnityEngine script to be attached to the player viewing someone's inventory. /// private class Inspector : MonoBehaviour { /// /// The player doing the inspecting. /// private BasePlayer player; /// /// The player being inspected. /// private BasePlayer target; /// /// The tick counter used by the Inspector. /// private int ticks; /// /// Instantiates the Inspector script. /// public void Instantiate(BasePlayer player, BasePlayer target) { this.player = player; this.target = target; BeginLooting(); InvokeRepeating("UpdateLoot", 0f, 0.1f); } /// /// Updates the loot. /// private void UpdateLoot() { if (!target) { return; } if (!target.inventory) { return; } ticks++; if (!player.inventory.loot.IsLooting()) { BeginLooting(); } player.inventory.loot.SendImmediate(); player.SendNetworkUpdateImmediate(); } /// /// Stops inspecting. /// private void StopInspecting(bool forced = false) { if (ticks < 5 && !forced) { return; } CancelInvoke("UpdateLoot"); EndLooting(); } /// /// Starts the looting. /// private void BeginLooting() { player.inventory.loot.Clear(); if (!target) { return; } if (!target.inventory) { return; } player.inventory.loot.AddContainer(target.inventory.containerMain); player.inventory.loot.AddContainer(target.inventory.containerWear); player.inventory.loot.AddContainer(target.inventory.containerBelt); player.inventory.loot.PositionChecks = false; player.inventory.loot.entitySource = target; player.inventory.loot.itemSource = null; player.inventory.loot.MarkDirty(); player.inventory.loot.SendImmediate(); player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", "player_corpse"); player.SendNetworkUpdateImmediate(); } /// /// Ends the looting. /// private void EndLooting() { player.inventory.loot.MarkDirty(); if (player.inventory.loot.entitySource) { player.inventory.loot.entitySource.SendMessage("PlayerStoppedLooting", player, SendMessageOptions.DontRequireReceiver); } foreach (ItemContainer container in player.inventory.loot.containers) { if (container != null) { container.onDirty -= player.inventory.loot.MarkDirty; } } player.inventory.loot.containers.Clear(); player.inventory.loot.entitySource = null; player.inventory.loot.itemSource = null; } /// /// Destroys the script /// public void Remove(bool forced = false) { if (ticks < 5 && !forced) { return; } StopInspecting(forced); Destroy(this); } } /// /// Oxide hook that is triggered when the plugin is loaded. /// private void Loaded() { permission.RegisterPermission(RequiredPermission, this); } /// /// Oxide hook that is triggered after the plugin is loaded to setup localized messages. /// private new void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { { "InvalidArguments", "Invalid argument(s) supplied! Use '/{0} ' or '/{0} list '." }, { "InvalidSelection", "Invalid number, use the number in front of the player's name. Use '/{0} list' to check the list of players again." }, { "MultiplePlayersFound", "Multiple players found with that name, please select one of these players by using '/{0} list ':" }, { "NoListAvailable", "You do not have a players list available, use '/{0} ' instead." }, { "NoPlayersFound", "Couldn't find any players matching that name." }, { "NotAllowed", "You are not allowed to use this command." }, { "TooManyPlayersFound", "Too many players were found, the list of matches is only showing the first 5. Try to be more specific." } }, this); } /// /// Oxide hook that is triggered when the plugin is unloaded. /// private void Unload() { Inspector[] inspectors = UnityEngine.Object.FindObjectsOfType(); foreach (Inspector inspector in inspectors) inspector.Remove(); } /// /// Oxide hook that is triggered when a console command is executed. /// private void OnServerCommand(ConsoleSystem.Arg arg) { if (arg.cmd.FullName == "inventory.endloot") { BasePlayer player = arg.Player(); player.GetComponent()?.Remove(); } } /// /// Oxide hook that is triggered when a player attempts to loot another player /// private object CanLootPlayer(BasePlayer target, BasePlayer looter) { if (looter.GetComponent() == null) { return null; } return true; } /// /// Handles the /inspect command /// [ChatCommand("inspect")] private void InspectCommand(BasePlayer player, string command, string[] args) { ViewInventoryCommand(player, command, args); } /// /// Handles the /viewinv command /// [ChatCommand("viewinv")] private void ViewInvCommand(BasePlayer player, string command, string[] args) { ViewInventoryCommand(player, command, args); } /// /// Handles the /viewinventory command /// [ChatCommand("viewinventory")] private void ViewInventoryCommand(BasePlayer player, string command, string[] args) { if (!CanUseCommand(player)) { SendChatMessage(player, "NotAllowed"); return; } if (args.Length < 1) { SendChatMessage(player, "InvalidArguments", command); return; } if (args[0] == "list") { if (args.Length == 1) { if (!matches.ContainsKey(player) || matches[player] == null) { SendChatMessage(player, "NoListAvailable", command); return; } ShowMatches(player); return; } int num; if (int.TryParse(args[1], out num)) { if (!matches.ContainsKey(player) || matches[player] == null) { SendChatMessage(player, "NoListAvailable", command); return; } if (num > matches[player].Count) { SendChatMessage(player, "InvalidSelection", command); ShowMatches(player); return; } StartInspecting(player, matches[player][num - 1]); return; } SendChatMessage(player, "InvalidArguments", command); } else { string name = string.Join(" ", args); List players = FindPlayersByNameOrId(name); switch (players.Count) { case 0: SendChatMessage(player, "NoPlayersFound", command); break; case 1: StartInspecting(player, players[0]); break; default: SendChatMessage(player, "MultiplePlayersFound", command); if (!matches.ContainsKey(player)) { matches.Add(player, players); } else { matches[player] = players; } ShowMatches(player); break; } } } /// /// Looks up all players (active and sleeping) by a given (partial) name or steam id. /// private List FindPlayersByNameOrId(string nameOrId) { List matches = new List(); foreach (BasePlayer player in BasePlayer.activePlayerList) { if (!string.IsNullOrEmpty(player.displayName)) { if (player.displayName.ToLower().Contains(nameOrId.ToLower())) { matches.Add(player); } } if (player.UserIDString == nameOrId) { matches.Add(player); } } foreach (BasePlayer player in BasePlayer.sleepingPlayerList) { if (!string.IsNullOrEmpty(player.displayName)) { if (player.displayName.ToLower().Contains(nameOrId.ToLower())) { matches.Add(player); } } if (player.UserIDString == nameOrId) { matches.Add(player); } } return matches.OrderBy(p => p.displayName).ToList(); } /// /// Shows the cached matches for the player. /// private void ShowMatches(BasePlayer player) { for (int i = 0; i < matches[player].Count; i++) { SendChatMessage(player, $"{i + 1}. {matches[player][i].displayName}"); if (i == 4 && i < matches[player].Count) { SendChatMessage(player, "TooManyPlayersFound"); break; } } } /// /// Initializes the inspector for the given player and target. /// private void StartInspecting(BasePlayer player, BasePlayer target) { Inspector inspector = player.gameObject.GetComponent(); inspector?.Remove(); inspector = player.gameObject.AddComponent(); inspector.Instantiate(player, target); } /// /// Checks if the specified BasePlayer has the required permission. /// private bool CanUseCommand(BasePlayer player) { return permission.UserHasPermission(player.UserIDString, RequiredPermission); } /// /// Sends a localized chat message using the key to the specified player /// private void SendChatMessage(BasePlayer player, string key, params string[] args) { if (args == null || args.Length == 0) { Player.Reply(player, lang.GetMessage(key, this, player.UserIDString)); } else { Player.Reply(player, string.Format(lang.GetMessage(key, this, player.UserIDString), args)); } } } }