using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Oxide.Core; using UnityEngine; using Oxide.Core.Plugins; namespace Oxide.Plugins { [Info("RedeemStorageAPI", "ThePitereq", "1.1.2")] public class RedeemStorageAPI : RustPlugin { [PluginReference] private readonly Plugin PopUpAPI; private static readonly Dictionary openedInventories = new Dictionary(); private void Init() { LoadConfig(); LoadMessages(); LoadData(); } private void OnServerInitialized() { permission.RegisterPermission("redeemstorageapi.admin", this); foreach (var command in config.commands) cmd.AddChatCommand(command, this, nameof(RedeemCommand)); if (config.itemReminder > 0) timer.Every(config.itemReminder, () => { foreach (var player in BasePlayer.activePlayerList) foreach (var storage in storedItems) if (storage.Value.ContainsKey(player.userID) && storage.Value[player.userID].Any()) PopUpAPI?.Call("ShowPopUp", player, config.popUpPreset, Lang("UnredeemedItemsRemind", player.UserIDString, config.commands.First(), storage.Key)); }); } private void Unload() { SaveData(); foreach (var inventory in openedInventories) inventory.Value?.Kill(); } private void OnNewSave() { LoadConfig(); LoadData(); bool changed = false; foreach (var inv in config.inventories) { if (inv.Value.wipeInventory) { storedItems[inv.Key].Clear(); changed = true; Puts($"Cleared content of the {inv.Key} redeem inventory!"); } } if (changed) SaveData(); } private void RedeemCommand(BasePlayer player, string command, string[] args) { if (args.Length == 0) { foreach (var storage in config.inventories) if (storage.Value.defaultInventory) { OpenRedeemInventory(player, storage.Key); return; } } else if (args.Length == 1) { string toLower = args[0].ToLower(); if (config.inventories.ContainsKey(toLower)) OpenRedeemInventory(player, toLower); else SendReply(player, Lang("StorageNotFound", player.UserIDString, toLower)); } else if (args.Length == 2) { if (!permission.UserHasPermission(player.UserIDString, "redeemstorageapi.admin")) { SendReply(player, Lang("NoPermission", player.UserIDString)); return; } string toLower = args[0].ToLower(); if (!config.inventories.ContainsKey(toLower)) SendReply(player, Lang("StorageNotFound", player.UserIDString, toLower)); ulong userId; if (ulong.TryParse(args[1], out userId)) { SendReply(player, Lang("AdminOpening", player.UserIDString, toLower, userId)); OpenRedeemInventory(player, toLower, userId); return; } else { string userToLower = args[1].ToLower(); foreach (var oPlayer in BasePlayer.activePlayerList) if (oPlayer.displayName.ToLower().Contains(userToLower)) { SendReply(player, Lang("AdminOpening", player.UserIDString, toLower, oPlayer.userID)); OpenRedeemInventory(player, toLower, oPlayer.userID); return; } } SendReply(player, Lang("UserNotFound", player.UserIDString)); } } private void OnLootEntityEnd(BasePlayer player, BoxStorage storage) { if (!openedInventories.ContainsKey(player.userID)) return; openedInventories[player.userID]?.Kill(); openedInventories.Remove(player.userID); } private void OpenRedeemInventory(BasePlayer player, string name, ulong ownerId = 0) { if (!permission.UserHasPermission(player.UserIDString, "redeemstorageapi.admin")) { bool privil = false; bool safeZone = player.InSafeZone(); BuildingPrivlidge priv = player.GetBuildingPrivilege(); if (priv != null && priv.IsAuthed(player.userID)) privil = true; else if (priv == null && config.inventories[name].authedNoTc) privil = true; int trueCount = 0; if (config.inventories[name].authed && privil) trueCount++; if (config.inventories[name].safezone && safeZone) trueCount++; if (trueCount == 0 && (config.inventories[name].authed || config.inventories[name].safezone)) { if (config.inventories[name].authed && !privil) PopUpAPI?.Call("ShowPopUp", player, config.popUpPreset, Lang("NotAuthToRefund", player.UserIDString)); else if (config.inventories[name].safezone && !safeZone) PopUpAPI?.Call("ShowPopUp", player, config.popUpPreset, Lang("NotInSafeZone", player.UserIDString)); return; } } ulong id = ownerId == 0 ? player.userID : ownerId; if (!storedItems[name].ContainsKey(id) || !storedItems[name][id].Any()) { SendReply(player, Lang("StorageEmpty", player.UserIDString)); return; } BoxStorage container = GameManager.server.CreateEntity("assets/prefabs/deployable/large wood storage/box.wooden.large.prefab", player.transform.position + new Vector3(0, -400)) as BoxStorage; UnityEngine.Object.DestroyImmediate(container.GetComponent()); UnityEngine.Object.DestroyImmediate(container.GetComponent()); container.Spawn(); openedInventories.TryAdd(player.userID, container); openedInventories[player.userID] = container; container.inventory.capacity = 48; foreach (var dataItem in storedItems[name][id]) { Item item = dataItem.ToItem(); item?.MoveToContainer(container.inventory); } player.EndLooting(); container.inventory.onDirty += () => { List items = new List(); items.Clear(); foreach (var item in container.inventory.itemList.ToList()) items.Add(ItemData.FromItem(item)); storedItems[name][id] = items; }; container.inventory.canAcceptItem = (item, i) => false; timer.Once(0.3f, () => { player.inventory.loot.AddContainer(container.inventory); player.inventory.loot.entitySource = container; player.inventory.loot.PositionChecks = false; player.inventory.loot.MarkDirty(); player.inventory.loot.SendImmediate(); player.ClientRPC(RpcTarget.Player("RPC_OpenLootPanel", player), "generic_resizable"); if (config.inventories[name].message) PopUpAPI?.Call("ShowPopUp", player, config.popUpPreset, Lang($"OpenMessage_{name}", player.UserIDString)); }); } private void AddItem(ulong userId, string name, Item item, bool popUp = false) { if (!storedItems.ContainsKey(name)) { PrintWarning($"Player {userId} tried to add item to storage named '{name}' but it doesn't exist in configuration file!"); return; } storedItems[name].TryAdd(userId, new List()); if (storedItems[name][userId].Count >= 48) { BasePlayer player = BasePlayer.FindByID(userId); string itemName = item.name != null && item.name != "" ? item.name : item.info.displayName.english; if (config.inventories[name].overflowDrop) { PopUpAPI?.Call("ShowPopUp", player, config.popUpPreset, Lang("ItemStorageFullDrop", player.UserIDString, name, itemName)); item.Drop(player.GetDropPosition(), player.GetDropVelocity()); } else PopUpAPI?.Call("ShowPopUp", player, config.popUpPreset, Lang("ItemStorageFullLost", player.UserIDString, name, itemName)); return; } storedItems[name][userId].Add(ItemData.FromItem(item)); if (popUp) { BasePlayer player = BasePlayer.FindByID(userId); if (player != null) { string itemName = item.name != null && item.name != "" ? item.name : item.info.displayName.english; PopUpAPI?.Call("ShowPopUp", player, config.popUpPreset, Lang("NewItemInStorage", player.UserIDString, name, itemName, config.commands.First())); } } } private void LoadMessages() { Dictionary langFile = new Dictionary() { ["StorageNotFound"] = "Storage with name {0} has not been found.", ["NoPermission"] = "You don't have permission to use this command!", ["AdminOpening"] = "Opening {0} inventory of {1}...", ["UserNotFound"] = "User has not been found.", ["NotAuthToRefund"] = "You are not authorized in Cupboard. You cannot open this redeem inventory!", ["NotInSafeZone"] = "You are not in safe zone. You cannot open this redeem inventory!", ["StorageEmpty"] = "This storage is empty...", ["NewItemInStorage"] = "You've got new item!\nIt's {1}! You can redeem it by typing /{2} {0}.", ["UnredeemedItemsRemind"] = "You have unredeemed items in your storage!\nRun /{0} {1} to get your items.", ["ItemStorageFullDrop"] = "You've got new item!\nIt's {1}! It should land in your {0} storage but it was full, so it dropped on to the ground.", ["ItemStorageFullLost"] = "You've got new item!\nIt was {1}! But your storage {0} was full and item disappeared!\nClear your storage first." }; foreach (var storage in config.inventories) if (storage.Value.message) langFile.TryAdd($"OpenMessage_{storage.Key}", "Default Open Message!"); lang.RegisterMessages(langFile, this); } private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args); private PluginConfig config = new PluginConfig(); protected override void LoadConfig() { base.LoadConfig(); config = Config.ReadObject(); Config.WriteObject(config); } protected override void LoadDefaultConfig() { Config.WriteObject(config = new PluginConfig() { commands = new List() { "redeem", "red" }, inventories = new Dictionary() { { "default", new InventoryConfig() { defaultInventory = true, safezone = true, authed = true } }, { "shop", new InventoryConfig() { message = true } } } }, true); } private class PluginConfig { [JsonProperty("Redeem Commands")] public List commands = new List(); [JsonProperty("PopUp API Preset")] public string popUpPreset = "Legacy"; [JsonProperty("Redeem Storage Item Reminder (in seconds, 0 to disable)")] public int itemReminder = 600; [JsonProperty("Redeem Inventories")] public Dictionary inventories = new Dictionary(); } private class InventoryConfig { [JsonProperty("Default Redeem Inventory (only one)")] public bool defaultInventory = false; [JsonProperty("PopUp Message (configurable in lang file)")] public bool message = false; [JsonProperty("Redeem Only In Safezone")] public bool safezone = false; [JsonProperty("Redeem Only If Authed")] public bool authed = false; [JsonProperty("Allow When No Cupboard (works is option above is true)")] public bool authedNoTc = false; [JsonProperty("Drop Overflow Items Onto Ground (true = drop, false = delete)")] public bool overflowDrop = true; [JsonProperty("Wipe Storage Content On Server Wipe")] public bool wipeInventory = false; } private static readonly Dictionary>> storedItems = new Dictionary>>(); private void LoadData() { foreach (var storage in config.inventories) { storedItems.TryAdd(storage.Key, new Dictionary>()); storedItems[storage.Key] = Interface.Oxide.DataFileSystem.ReadObject>>($"{Name}/{storage.Key}"); } timer.Every(Core.Random.Range(500, 700), SaveData); } private void SaveData() { foreach (var storage in config.inventories) Interface.Oxide.DataFileSystem.WriteObject($"{Name}/{storage.Key}", storedItems[storage.Key]); } private class ItemData { public string Shortname; public int Amount; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool IsBlueprint; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public int BlueprintTarget; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public ulong Skin; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public float Fuel; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public int FlameFuel; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public float Condition; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public float MaxCondition = -1; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public int Ammo; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public int AmmoType; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public int DataInt; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public string Name; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public string Text; [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public List Contents = new List(); public Item ToItem() { if (Amount == 0) return null; Item item = ItemManager.CreateByName(Shortname, Amount, Skin); if (IsBlueprint) { item.blueprintTarget = BlueprintTarget; return item; } item.fuel = Fuel; item.condition = Condition; if (MaxCondition != -1) item.maxCondition = MaxCondition; if (Contents != null) { if (Contents.Count > 0) { if (item.contents == null) { item.contents = new ItemContainer(); item.contents.ServerInitialize(null, Contents.Count); item.contents.GiveUID(); item.contents.parent = item; } foreach (var contentItem in Contents) contentItem.ToItem().MoveToContainer(item.contents); } } else item.contents = null; BaseProjectile.Magazine magazine = item.GetHeldEntity()?.GetComponent()?.primaryMagazine; FlameThrower flameThrower = item.GetHeldEntity()?.GetComponent(); if (magazine != null) { magazine.contents = Ammo; magazine.ammoType = ItemManager.FindItemDefinition(AmmoType); } if (flameThrower != null) flameThrower.ammo = FlameFuel; if (DataInt > 0) { item.instanceData = new ProtoBuf.Item.InstanceData { ShouldPool = false, dataInt = DataInt }; } item.text = Text; if (Name != null) item.name = Name; return item; } public static ItemData FromItem(Item item) => new ItemData { Shortname = item.info.shortname, Ammo = item.GetHeldEntity()?.GetComponent()?.primaryMagazine?.contents ?? 0, AmmoType = item.GetHeldEntity()?.GetComponent()?.primaryMagazine?.ammoType?.itemid ?? 0, Amount = item.amount, Condition = item.condition, MaxCondition = item.maxCondition, Fuel = item.fuel, Skin = item.skin, Contents = item.contents?.itemList?.Select(FromItem).ToList(), FlameFuel = item.GetHeldEntity()?.GetComponent()?.ammo ?? 0, IsBlueprint = item.IsBlueprint(), BlueprintTarget = item.blueprintTarget, DataInt = item.instanceData?.dataInt ?? 0, Name = item.name, Text = item.text }; } } }