USER
refatore e mande o código COMPLETO:
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Quarry Computer", "Marte6", "1.0.0")]
[Description("Manages quarry operations and configurations with in-game UI")]
public class QuarryComputer : CovalencePlugin
{
[PluginReference]
private Plugin ImageLibrary = null,
LangAPI = null,
Notify = null;
#region Constants
private const string BaseItemName = "arcade.machine.chippy";
private const string BaseDeployedItemName = "chippyarcademachine";
private const string QuarryPrefab = "assets/content/structures/excavator/prefabs/excavatorsignalcomputer.prefab";
private const string QuarryOutputStoragePrefab = "assets/prefabs/deployable/hot air balloon/subents/hab_storage.prefab";
private const string QuarryFuelStoragePrefab = "assets/content/vehicles/boats/rowboat/subents/rowboat_storage.prefab";
private const string StorageAdaptorPrefab = "assets/prefabs/deployable/playerioents/industrialadaptors/storageadaptor.deployed.prefab";
private const ulong QuarrySkinId = 3341965622;
private const string UiBackground = "6iYcl0UppZxwaotNu6kghxTF7s8a4r4d";
private const string UiMainPanel = "VsUNAYUweeIfW5qvG1zHcQ09hy06GGFi";
private const string UiLeftPanel = "6k3PPUUOyd8A6RgqGBan9cMLn59GTzRS";
private const string UiRightPanel = "o9C5OcIYWCoOsRpcULoyfKPGGxb8LAoJ";
private const string UiPopupOverlayBlock = "Mu8AqzfN17Djw3TstzIsjnJqKi4W5n5j";
private const string UiPopupShadow = "JVQZBnIR9vmF844dkfYsuOymwWBTCeJV";
private const string UiPopupBorder = "tmZZ1WqIBuBlqvNeabQH6D6wvK5Gfz7u";
private const string UiPopupBackground = "3kNfPEASr9RkcBTB9vtMLoxkpKfqc4FU";
private const string CommandUiClose = "3bizteteO5ic8z82GJHeQx77hlDMLcI9";
private const string CommandUiRemove = "fl6n4DHugCuZKCrLHpZUF4ZNvEGIW2px";
private const string CommandUiConfirmRemove = "PTZdQzOalxnZFiwDkiKgMdk1wbuG6T64";
private const string CommandUiCancelRemove = "09stuljgGWtJzQBvFevq2chgWvZNvodr";
private const string CommandUiUpgrade = "mSjiZxaTD4hdq9hUHcLGdQviIPzfksgK";
private const string CommandUiConfirm = "gTpJiMwJn7JSbSWFr8fSjY4nHg72Fryl";
private const string CommandUiCancelUpgrade = "B3xei8Zq8VVr4zptxJxYxEfW3sh40x82";
private const Item.Flag ExtractedItemFlag = (Item.Flag)(1 << 78);
#endregion
#region Fields
private static QuarryComputer _instance;
private readonly List<string> _permissions = new() { "quarrycomputer.give", "quarrycomputer.industrial", "quarrycomputer.vip" };
private static readonly HashSet<ulong> PlayersWithPopup = new();
private static readonly Dictionary<ulong, QuarryComputerBehaviour> OpenedQuarryInterfaces = new();
private static readonly HashSet<QuarryComputerBehaviour> QuarryCheckStatusList = new();
private static readonly Dictionary<BaseEntity, QuarryComputerBehaviour> ContainerQuarryMap = new();
#endregion
#region Initialization
private void OnServerInitialized()
{
_instance = this;
RegisterPermissions();
RegisterCommands();
InitializeExistingQuarries();
}
private void Unload()
{
DestroyAllUi();
UnloadAllQuarryBehaviours();
}
#endregion
#region Configuration
private Configuration _config;
private class Configuration
{
[JsonProperty("Use LangAPI Plugin")]
public bool UseLangAPI { get; set; }
[JsonProperty("Use Notify Plugin")]
public bool UseNotify { get; set; }
[JsonProperty("Give Quarry Command")]
public string[] GiveQuarryCommand { get; set; }
[JsonProperty("Remove Quarry Command")]
public string[] RemoveQuarryCommand { get; set; }
[JsonProperty("Fuel Configuration")]
public FuelConfiguration FuelConfiguration { get; set; }
[JsonProperty("No Upgrades (Level 1)")]
public NoUpgrades NoUpgrades { get; set; }
[JsonProperty("Upgrades (Level 2+)")]
public List<UpgradeOption> Upgrades { get; set; }
[JsonProperty("Keep Upgrades On Remove Quarry")]
public bool KeepUpgradesOnRemoval { get; set; }
[JsonProperty("Profiles")]
public UserProfiles Profiles { get; set; }
[JsonProperty("Version")]
public VersionNumber Version { get; set; }
}
private class FuelConfiguration
{
[JsonProperty("Shortname")]
public string Shortname { get; set; }
[JsonProperty("Resource Extraction Interval In Seconds")]
public int ResourceExtractionInterval { get; set; }
[JsonProperty("Fuel Required Per Extraction")]
public int FuelRequiredPerExtraction { get; set; }
}
private class NoUpgrades
{
[JsonProperty("Storage Slots")]
public StorageSlots StorageSlots { get; set; }
[JsonProperty("Resources Output Per Extraction")]
public List<ResourceItem> ResourcesOutput { get; set; }
}
private class StorageSlots
{
[JsonProperty("Fuel")]
public int FuelSlots { get; set; }
[JsonProperty("Resources")]
public int OutputSlots { get; set; }
}
private class ResourceItem
{
[JsonProperty("Shortname")]
public string Shortname { get; set; }
[JsonProperty("Amount")]
public int Amount { get; set; }
}
private class UpgradeOption
{
[JsonProperty("Storage Slots")]
public StorageSlots StorageSlots { get; set; }
[JsonProperty("Resources Output Per Extraction")]
public List<ResourceItem> ResourcesOutput { get; set; }
[JsonProperty("Required Items To Upgrade")]
public List<ResourceItem> UpgradeItems { get; set; }
}
private class UserProfiles
{
[JsonProperty("Default (No Permission)")]
public UserProfile Default { get; set; }
[JsonProperty("VIP (quarrycomputer.vip Permission)")]
public UserProfile VIP { get; set; }
}
private class UserProfile
{
[JsonProperty("Quarry Limit")]
public int QuarryLimit { get; set; }
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
if (_config != null)
{
if (_config.Version < Version)
UpdateConfigValues();
SaveConfig();
}
else
{
throw new Exception();
}
}
catch
{
PrintError("Your configuration file contains an error. Using default configuration values.");
LoadDefaultConfig();
}
}
protected override void LoadDefaultConfig() => _config = CreateDefaultConfig();
protected override void SaveConfig() => Config.WriteObject(_config);
private void UpdateConfigValues()
{
PrintWarning("Config update detected! Updating config values...");
_config.Version = Version;
PrintWarning("Config update completed!");
}
private Configuration CreateDefaultConfig()
{
return new Configuration
{
GiveQuarryCommand = new[] { "gq", "givequarry" },
RemoveQuarryCommand = new[] { "rq", "removequarry" },
UseLangAPI = false,
UseNotify = true,
FuelConfiguration = new FuelConfiguration
{
Shortname = "charcoal",
ResourceExtractionInterval = 6,
FuelRequiredPerExtraction = 1,
},
NoUpgrades = new NoUpgrades
{
StorageSlots = new StorageSlots { FuelSlots = 6, OutputSlots = 24 },
ResourcesOutput = new List<ResourceItem>
{
new ResourceItem { Shortname = "crude.oil", Amount = 1 },
new ResourceItem { Shortname = "stones", Amount = 1 },
},
},
Upgrades = new List<UpgradeOption>
{
new UpgradeOption
{
StorageSlots = new StorageSlots { FuelSlots = 6, OutputSlots = 24 },
ResourcesOutput = new List<ResourceItem>
{
new ResourceItem { Shortname = "crude.oil", Amount = 2 },
new ResourceItem { Shortname = "metal.ore", Amount = 1 },
new ResourceItem { Shortname = "stones", Amount = 2 },
},
UpgradeItems = new List<ResourceItem>
{
new ResourceItem { Shortname = "scrap", Amount = 1000 },
new ResourceItem { Shortname = "pumpkin", Amount = 1000 },
new ResourceItem { Shortname = "bone.fragments", Amount = 1000 },
},
},
new UpgradeOption
{
StorageSlots = new StorageSlots { FuelSlots = 6, OutputSlots = 24 },
ResourcesOutput = new List<ResourceItem>
{
new ResourceItem { Shortname = "crude.oil", Amount = 3 },
new ResourceItem { Shortname = "hq.metal.ore", Amount = 3 },
new ResourceItem { Shortname = "metal.ore", Amount = 3 },
new ResourceItem { Shortname = "stones", Amount = 3 },
new ResourceItem { Shortname = "sulfur.ore", Amount = 3 },
},
UpgradeItems = new List<ResourceItem>
{
new ResourceItem { Shortname = "scrap", Amount = 5000 },
new ResourceItem { Shortname = "pumpkin", Amount = 1000 },
new ResourceItem { Shortname = "cloth", Amount = 10000 },
new ResourceItem { Shortname = "red.berry", Amount = 1000 },
new ResourceItem { Shortname = "bone.fragments", Amount = 1000 },
},
},
},
KeepUpgradesOnRemoval = true,
Profiles = new UserProfiles
{
Default = new UserProfile { QuarryLimit = 1 },
VIP = new UserProfile { QuarryLimit = 3 },
},
};
}
#endregion
#region Localization
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(
new Dictionary<string, string>
{
["NoPermission"] = "You don't have permissions to use this command",
["NoBuildingAuth"] = "You must have building auth to use this",
["NotMiningQuarry"] = "This object is not a Mining Quarry",
["NotOwner"] = "This object belongs to another owner",
["QuarryRemoved"] = "Mining Quarry Removed",
["NoQuarriesFound"] = "No quarries found",
},
this
);
}
public string GetItemDisplayName(BasePlayer player, string itemShortName)
{
ItemDefinition itemDefinition = ItemManager.FindItemDefinition(itemShortName);
var displayName = itemDefinition.displayName.translated;
if (_config.UseLangAPI && LangAPI != null && LangAPI.Call<bool>("IsDefaultDisplayName", displayName))
{
var displayNameTranslated = LangAPI.Call<string>("GetItemDisplayName", itemShortName, displayName, player.UserIDString);
if (!string.IsNullOrEmpty(displayNameTranslated))
{
return displayNameTranslated;
}
}
return displayName;
}
#endregion
#region UiCommands
[Command(CommandUiClose)]
private void UiCloseCommand(IPlayer player)
{
var basePlayer = player.Object as BasePlayer;
DestroyUi(basePlayer);
}
[Command(CommandUiRemove)]
private void UiRemoveCommand(IPlayer player)
{
var basePlayer = player.Object as BasePlayer;
ToggleConfirmationPopup(basePlayer, "Remove the Quarry?", CommandUiConfirmRemove, CommandUiCancelRemove);
}
[Command(CommandUiConfirmRemove)]
private void UiConfirmRemoveCommand(IPlayer player)
{
var basePlayer = player.Object as BasePlayer;
ClosePopup(basePlayer);
}
[Command(CommandUiCancelRemove)]
private void UiCancelRemoveCommand(IPlayer player)
{
var basePlayer = player.Object as BasePlayer;
ClosePopup(basePlayer);
}
[Command(CommandUiUpgrade)]
private void UiUpgradeCommand(IPlayer player)
{
var basePlayer = player.Object as BasePlayer;
ToggleConfirmationPopup(basePlayer, "Upgrade the Quarry?", CommandUiConfirm, CommandUiCancelUpgrade);
}
[Command(CommandUiConfirm)]
private void UiConfirmCommand(IPlayer player)
{
var basePlayer = player.Object as BasePlayer;
ClosePopup(basePlayer);
}
[Command(CommandUiCancelUpgrade)]
private void UiCancelUpgradeCommand(IPlayer player)
{
var basePlayer = player.Object as BasePlayer;
ClosePopup(basePlayer);
}
#endregion
#region Commands
private void GiveQuarryCommand(IPlayer iplayer, string command, string[] args)
{
var player = iplayer?.Object as BasePlayer;
if (player == null || args == null || args.Length < 1)
return;
if (!iplayer.HasPermission("quarrycomputer.give"))
{
NotifyPlayer(iplayer, "NoPermission", 1);
return;
}
var targetPlayer = BasePlayer.Find(args[0]);
if (targetPlayer == null)
{
NotifyPlayer(iplayer, "PlayerNotFound", 1);
return;
}
if (GiveQuarryItem(targetPlayer))
{
NotifyPlayer(iplayer, "QuarrySend", 0);
NotifyPlayer(targetPlayer, "QuarryReceived", 0);
}
else
{
NotifyPlayer(iplayer, "QuarrySend", 0);
NotifyPlayer(targetPlayer, "QuarryReceived", 0);
NotifyPlayer(targetPlayer, "QuarryDropped", 1);
}
}
private void RemoveQuarryCommand(IPlayer iplayer, string command, string[] args)
{
var player = iplayer?.Object as BasePlayer;
if (player == null)
return;
if (!TryFindQuarryInCrosshair(player, out var quarryEntity))
{
NotifyPlayer(iplayer, "NotMiningQuarry", 1);
return;
}
if (quarryEntity.OwnerID != player.userID)
{
NotifyPlayer(iplayer, "NotOwner", 1);
return;
}
quarryEntity.Kill();
NotifyPlayer(iplayer, "QuarryRemoved", 0);
}
#endregion
#region UI Handling
private void CreateUi(BasePlayer player, int quarryLevel)
{
var fuelName = GetItemDisplayName(player, _config.FuelConfiguration.Shortname);
var container = new CuiElementContainer();
AddBackground(container);
AddMainPanel(container, fuelName);
AddLeftPanel(container, quarryLevel);
AddRightPanel(container);
CuiHelper.AddUi(player, container);
}
private void AddBackground(CuiElementContainer container)
{
AddPanel(container, "0 0", "1 1", UiBackground, "Overlay", "0 0 0 0.9", true);
}
private void AddMainPanel(CuiElementContainer container, string fuelName)
{
AddPanel(container, "0.235 0.18", "0.765 0.784", UiMainPanel, UiBackground, "0.6 0.6 0.6 0.95", true);
AddInnerSquare(container, UiMainPanel, "0 0.9570", "1 1", "0.39 0.39 0.39 1");
AddText(
container,
UiMainPanel,
"0.02 0.96",
"1 1",
$"Extraction Interval: {_config.FuelConfiguration.ResourceExtractionInterval} sec | Fuel per extraction: {_config.FuelConfiguration.FuelRequiredPerExtraction} {fuelName}",
13,
TextAnchor.MiddleLeft
);
AddCloseButton(container, UiMainPanel);
}
private void AddLeftPanel(CuiElementContainer container, int quarryLevel)
{
var parent = UiLeftPanel;
AddPanel(container, "0 0", "0.5 0.94", parent, UiMainPanel, "0 0 0 0");
AddPanelStructure(container, parent, $"Quarry Level {quarryLevel}", "0 0 1 1");
AddText(container, parent, "0.38 0.679", "1 1", "Storage", 13, TextAnchor.MiddleLeft);
AddText(container, parent, "0.09 0.590", "1 1", "Fuel: 3 slots", 13, TextAnchor.MiddleLeft);
AddText(container, parent, "0.45 0.590", "1 1", "Resource: 6 slots", 13, TextAnchor.MiddleLeft);
AddHorizontalLine(container, parent, "0.06 0.769", "0.89 0.77");
AddText(container, parent, "0.34 0.490", "1 1", "Extraction", 13, TextAnchor.MiddleLeft);
Dictionary<string, string> extractionTexts = new Dictionary<string, string>
{
{ "charcoal", "10" },
{ "blueberries", "10" },
{ "hazmatsuit.arcticsuit", "10" },
{ "crude.oil", "10" },
{ "hq.metal.ore", "60" },
{ "grenade.f1", "10" },
};
AddDictionaryWithSpacing(container, parent, extractionTexts, 0.18f, 0.725f, 0.065f);
AddRemoveButton(container, parent);
}
private void AddRightPanel(CuiElementContainer container)
{
var parent = UiRightPanel;
AddPanel(container, "0.5 0", "1 0.94", parent, UiMainPanel, "0 0 0 0");
AddPanelStructure(container, parent, "Upgrade to Level 2", "0.5 0 0 1");
AddText(container, parent, "0.38 0.679", "1 1", "Storage", 13, TextAnchor.MiddleLeft);
AddText(container, parent, "0.09 0.590", "1 1", "Fuel: 3 slots", 13, TextAnchor.MiddleLeft);
AddText(container, parent, "0.45 0.590", "1 1", "Resource: 6 slots", 13, TextAnchor.MiddleLeft);
AddHorizontalLine(container, parent, "0.06 0.769", "0.89 0.77");
AddText(container, parent, "0.34 0.490", "1 1", "Extraction", 13, TextAnchor.MiddleLeft);
Dictionary<string, string> extractionTexts = new Dictionary<string, string>
{
{ "abovegroundpool", "10" },
{ "blueberries", "10" },
{ "hazmatsuit.arcticsuit", "10" },
{ "crude.oil", "10" },
{ "hq.metal.ore", "60" },
{ "grenade.f1", "10" },
{ "metal.ore", "100" },
{ "stones", "250" },
{ "sulfur.ore", "160" },
{ "explosive.timed", "2" },
{ "explosive.satchel", "2" },
{ "grenade.beancan", "4" },
};
AddDictionaryWithSpacing(container, parent, extractionTexts, 0.18f, 0.725f, 0.065f);
AddHorizontalLine(container, parent, "0.06 0.464", "0.89 0.465");
AddText(container, parent, "0.34 0.0", "1 0.88", "Requirements", 13, TextAnchor.MiddleLeft);
Dictionary<string, string> requirementsTexts = new Dictionary<string, string>
{
{ "abovegroundpool", "10" },
{ "blueberries", "10" },
{ "hazmatsuit.arcticsuit", "10" },
{ "crude.oil", "10" },
{ "hq.metal.ore", "60" },
{ "grenade.f1", "10" },
{ "metal.ore", "100" },
{ "stones", "250" },
{ "sulfur.ore", "160" },
{ "explosive.timed", "2" },
{ "explosive.satchel", "2" },
{ "grenade.beancan", "4" },
};
AddDictionaryWithSpacing(container, parent, requirementsTexts, 0.18f, 0.419f, 0.065f);
AddUpgradeButton(container, parent);
}
private void AddPanelStructure(CuiElementContainer container, string parent, string title, string titleColor)
{
AddInnerSquare(container, parent, "0.10 0.05", "0.95 0.90", "0 0 0 0.97");
AddInnerSquare(container, parent, "0.054 0.1033", "0.895 0.945", "0.8 0.8 0.8 1");
AddInnerSquare(container, parent, "0.06 0.108", "0.89 0.94", titleColor);
AddHorizontalLine(container, parent, "0.06 0.865", "0.89 0.865");
AddText(container, parent, "0.1 0.84", "0.84 0.98", title, 15, TextAnchor.MiddleCenter);
}
private void AddDictionaryWithSpacing(CuiElementContainer container, string parent, Dictionary<string, string> texts, float initialAnchorX, float initialAnchorY, float spacing)
{
float anchorX = initialAnchorX;
int i = 0;
foreach (var item in texts)
{
i++;
float anchorY = initialAnchorY - (spacing * i);
if (i >= 5 && i < 9)
{
anchorY = initialAnchorY - (spacing * (i - 4));
anchorX = initialAnchorX + 0.23F;
}
if (i >= 9)
{
anchorY = initialAnchorY - (spacing * (i - 8));
anchorX = initialAnchorX + 0.47F;
}
float imageSize = 0.07f;
float imageAnchorMinX = anchorX - (imageSize / 2);
float imageAnchorMaxX = anchorX + (imageSize / 2);
float imageAnchorMinY = anchorY + 0.04f - (imageSize / 2);
float imageAnchorMaxY = anchorY + 0.02f + (imageSize / 2);
AddImage(container, parent, item.Key, $"{imageAnchorMinX} {imageAnchorMinY}", $"{imageAnchorMaxX} {imageAnchorMaxY}", "ResourceImage");
AddText(container, parent, $"{anchorX + 0.05f} {anchorY}", $"{anchorX + 0.05f + 0.8f} {anchorY + 0.06}", item.Value, 12, TextAnchor.MiddleLeft);
}
}
private void AddTextsWithSpacing(CuiElementContainer container, string parent, string[] texts, float anchorX, float initialAnchorY, float spacing)
{
for (int i = 0; i < texts.Length; i++)
{
float anchorY = initialAnchorY - (spacing * i);
AddText(container, parent, $"{anchorX} {anchorY}", $"{anchorX + 0.8f} {anchorY + 0.06}", texts[i], 12, TextAnchor.MiddleLeft);
}
}
private void AddHorizontalLine(CuiElementContainer container, string parent, string anchorMin, string anchorMax)
{
AddInnerSquare(container, parent, anchorMin, anchorMax, "0.8 0.8 0.8 1");
}
private void AddImage(CuiElementContainer container, string parent, string resourceName, string anchorMin, string anchorMax, string imageName)
{
string imageUrl = ImageLibrary?.Call("GetImage", resourceName) as string;
if (string.IsNullOrEmpty(imageUrl))
{
PrintWarning($"Failed to get image for item: {resourceName}");
return;
}
container.Add(
new CuiElement
{
Name = imageName,
Parent = parent,
Components =
{
new CuiRawImageComponent { Png = imageUrl },
new CuiRectTransformComponent { AnchorMin = anchorMin, AnchorMax = anchorMax },
},
}
);
}
private void AddCloseButton(CuiElementContainer container, string parent)
{
container.Add(
new CuiButton
{
Button =
{
Color = "1 0 0 1",
Command = CommandUiClose,
Close = UiBackground,
},
RectTransform = { AnchorMin = "0.965 0.957", AnchorMax = "1 1" },
Text =
{
Text = "✖",
FontSize = 13,
Align = TextAnchor.MiddleCenter,
Color = "1 1 1 0.5",
},
},
parent
);
}
private void AddRemoveButton(CuiElementContainer container, string parent)
{
AddButton(container, parent, "Remove Quarry", CommandUiRemove, "0.28", "0.11", "0.70", "0.16", "0.6 0.6 0.6 0.95", "1 0 0 1");
}
private void AddUpgradeButton(CuiElementContainer container, string parent)
{
AddButton(container, parent, "Upgrade", CommandUiUpgrade, "0.35", "0.11", "0.65", "0.16", "0.6 0.6 0.6 0.95", "0 1 0 1");
}
private void DestroyUi(BasePlayer player)
{
if (player == null)
return;
CuiHelper.DestroyUi(player, UiBackground);
CuiHelper.DestroyUi(player, UiMainPanel);
CuiHelper.DestroyUi(player, UiLeftPanel);
CuiHelper.DestroyUi(player, UiRightPanel);
CuiHelper.DestroyUi(player, UiPopupOverlayBlock);
CuiHelper.DestroyUi(player, UiPopupShadow);
CuiHelper.DestroyUi(player, UiPopupBorder);
CuiHelper.DestroyUi(player, UiPopupBackground);
OpenedQuarryInterfaces.Remove(player.userID);
PlayersWithPopup.Remove(player.userID);
}
private void DestroyAllUi()
{
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
DestroyUi(player);
}
}
private void ToggleConfirmationPopup(BasePlayer player, string message, string confirmCommand, string cancelCommand)
{
if (player != null && !PlayersWithPopup.Contains(player.userID))
{
PlayersWithPopup.Add(player.userID);
ShowConfirmationPopup(player, message, confirmCommand, cancelCommand);
}
}
private void ShowConfirmationPopup(BasePlayer player, string message, string confirmCommand, string cancelCommand)
{
var container = new CuiElementContainer();
AddPanel(container, "0 0", "1 1", UiPopupOverlayBlock, "Overlay", "0 0 0 0.9", true);
AddPanel(container, "0.4 0.4", "0.6 0.6", UiPopupShadow, UiPopupOverlayBlock, "0 0 0 0.85");
AddPanel(container, "0.0 0.09", "0.95 1.0", UiPopupBorder, UiPopupShadow, "1 1 1 1");
AddPanel(container, "0.01 0.01", "0.991 0.985", UiPopupBackground, UiPopupBorder, "0 0 0 1");
AddText(container, UiPopupBackground, "0 0", "1 1", message, 14, TextAnchor.MiddleCenter);
AddButton(container, UiPopupBackground, "Yes", confirmCommand, "0.25", "0.05", "0.45", "0.20", "0.6 0.6 0.6 0.95", "0 1 0 1");
AddButton(container, UiPopupBackground, "No", cancelCommand, "0.55", "0.05", "0.75", "0.20", "0.6 0.6 0.6 0.95", "1 0 0 1");
CuiHelper.AddUi(player, container);
}
private void ClosePopup(BasePlayer player)
{
if (player != null)
{
CuiHelper.DestroyUi(player, UiPopupOverlayBlock);
CuiHelper.DestroyUi(player, UiPopupShadow);
CuiHelper.DestroyUi(player, UiPopupBorder);
CuiHelper.DestroyUi(player, UiPopupBackground);
PlayersWithPopup.Remove(player.userID);
}
}
#endregion
#region UI Helpers
private void AddPanel(CuiElementContainer container, string anchorMin, string anchorMax, string panelName, string parent, string color, bool isCursorEnabled = false)
{
var panel = new CuiPanel
{
Image = { Color = color },
RectTransform = { AnchorMin = anchorMin, AnchorMax = anchorMax },
CursorEnabled = isCursorEnabled,
};
container.Add(panel, parent, panelName);
}
private void AddInnerSquare(CuiElementContainer container, string parent, string anchorMin, string anchorMax, string color)
{
container.Add(new CuiPanel { Image = { Color = color }, RectTransform = { AnchorMin = anchorMin, AnchorMax = anchorMax } }, parent);
}
private void AddText(CuiElementContainer container, string parent, string anchorMin, string anchorMax, string text, int fontSize, TextAnchor alignment)
{
container.Add(
new CuiLabel
{
Text =
{
Text = text,
FontSize = fontSize,
Font = "DroidSansMono.ttf",
Align = alignment,
Color = "1 1 1 1",
},
RectTransform = { AnchorMin = anchorMin, AnchorMax = anchorMax },
},
parent
);
}
private void AddButton(
CuiElementContainer container,
string parent,
string text,
string command,
string anchorMinX,
string anchorMinY,
string anchorMaxX,
string anchorMaxY,
string bgColor,
string textColor
)
{
container.Add(
new CuiButton
{
Button =
{
Color = bgColor,
Command = command,
Close = "",
},
RectTransform = { AnchorMin = $"{anchorMinX} {anchorMinY}", AnchorMax = $"{anchorMaxX} {anchorMaxY}" },
Text =
{
Text = text,
FontSize = 14,
Font = "DroidSansMono.ttf",
Align = TextAnchor.MiddleCenter,
Color = textColor,
},
},
parent
);
}
#endregion
#region Game Hooks
private void OnEntityBuilt(Planner planner, GameObject builtObject)
{
var player = planner?.GetOwnerPlayer();
var entity = builtObject.GetComponent<BaseEntity>();
if (player == null || entity == null || entity.ShortPrefabName != BaseDeployedItemName || entity.skinID != QuarrySkinId)
return;
var playerQuarryCount = BaseNetworkable.serverEntities.OfType<ExcavatorSignalComputer>().Count(x => x.OwnerID == player.userID);
var playerQuarryLimit = _config.Profiles.Default.QuarryLimit;
if (permission.UserHasPermission(player.UserIDString, "quarrycomputer.vip"))
{
playerQuarryLimit = _config.Profiles.VIP.QuarryLimit;
}
if (!player.IsBuildingAuthed() || playerQuarryCount >= playerQuarryLimit)
{
if (entity)
entity.Kill();
NotifyPlayer(player.IPlayer, !player.IsBuildingAuthed() ? "NoBuildingAuth" : "QuarryLimitReached", 1);
timer.Once(1, () => GiveQuarryItem(player));
return;
}
DeployQuarry(player, entity);
NextTick(() =>
{
entity?.Kill();
});
}
private ItemContainer.CanAcceptResult? CanAcceptItem(ItemContainer container, Item item)
{
if (container.entityOwner is not StorageContainer || container.entityOwner.name == null)
return null;
QuarryComputerBehaviour quarryComputer;
if (!ContainerQuarryMap.TryGetValue(container.entityOwner, out quarryComputer))
{
quarryComputer = container.entityOwner.GetComponentInParent<QuarryComputerBehaviour>();
if (quarryComputer == null)
return null;
ContainerQuarryMap[container.entityOwner] = quarryComputer;
}
if (container.entityOwner.name == QuarryFuelStoragePrefab)
{
if (item.info.shortname == _config.FuelConfiguration.Shortname)
QuarryCheckStatusList.Add(quarryComputer);
else
return ItemContainer.CanAcceptResult.CannotAccept;
}
if (container.entityOwner.name == QuarryOutputStoragePrefab && !item.flags.HasFlag(ExtractedItemFlag))
return ItemContainer.CanAcceptResult.CannotAccept;
return null;
}
private object CanPickupEntity(BasePlayer player, IndustrialStorageAdaptor entity)
{
return entity.GetComponentInParent<QuarryComputerBehaviour>() != null ? (object)false : null;
}
private object OnExcavatorSuppliesRequest(ExcavatorSignalComputer computer, BasePlayer player)
{
return computer.GetComponent<QuarryComputerBehaviour>() != null ? (object)true : null;
}
private object OnButtonPress(PressButton button, BasePlayer player)
{
var outputContainer = button.GetParentEntity();
if (outputContainer is not StorageContainer)
return null;
var quarry = outputContainer.GetComponentInParent<QuarryComputerBehaviour>();
if (quarry == null || quarry.OwnerID != player.userID)
{
Puts("Belongs to another user");
return null;
}
Puts($"quarry level: {quarry.Level}");
OpenedQuarryInterfaces.Add(player.userID, quarry);
CreateUi(player, quarry.Level);
return null;
}
#endregion
#region Quarry Management Methods
private bool TryFindQuarryInCrosshair(BasePlayer player, out BaseEntity quarryEntity)
{
quarryEntity = null;
int layerMask = LayerMask.GetMask("Default", "TransparentFX", "IgnoreRaycast", "Water");
if (!Physics.Raycast(player.eyes.HeadRay(), out var hitInfo, 3f, layerMask, QueryTriggerInteraction.Ignore))
return false;
quarryEntity = hitInfo.collider.ToBaseEntity();
return quarryEntity != null && quarryEntity.name == QuarryPrefab;
}
private bool GiveQuarryItem(BasePlayer player)
{
var item = CreateQuarryItem();
if (player.inventory.GiveItem(item))
{
player.Command("note.inv", item.info.itemid, 1, item.name, (int)BaseEntity.GiveItemReason.PickedUp);
return true;
}
item.Drop(player.inventory.containerMain.dropPosition, player.inventory.containerMain.dropVelocity);
return false;
}
private Item CreateQuarryItem()
{
var item = ItemManager.CreateByName(BaseItemName, 1, QuarrySkinId);
item.name = "Quarry Computer";
return item;
}
private void DeployQuarry(BasePlayer player, BaseEntity entity)
{
var position = entity.transform.position;
var rotation = Quaternion.Euler(0, entity.transform.rotation.eulerAngles.y + 90, 0);
var quarry = GameManager.server.CreateEntity(QuarryPrefab, position, rotation);
quarry.OwnerID = player.userID;
quarry.Spawn();
quarry.SendNetworkUpdateImmediate();
AttachContainer(quarry, QuarryOutputStoragePrefab, new Vector3(0.05f, 0.75f, -0.21f), new Vector3(0, 180, 0), false, player);
AttachContainer(quarry, QuarryFuelStoragePrefab, new Vector3(0.05f, 0.75f, 0.32f), new Vector3(90, 0, 0), true, player);
quarry.gameObject.AddComponent<QuarryComputerBehaviour>();
}
private void AttachContainer(BaseEntity entity, string prefab, Vector3 localPosition, Vector3 localEulerAngles, bool isFuelContainer, BasePlayer player)
{
var container = GameManager.server.CreateEntity(prefab) as StorageContainer;
container.SetParent(entity);
container.transform.localPosition = localPosition;
container.transform.localRotation = Quaternion.Euler(localEulerAngles);
container.Spawn();
container.SendNetworkUpdateImmediate();
if (permission.UserHasPermission(player.UserIDString, "quarrycomputer.industrial"))
{
var adaptor = GameManager.server.CreateEntity(StorageAdaptorPrefab, container.transform.position, container.transform.rotation) as IndustrialStorageAdaptor;
adaptor.SetParent(container, true, true);
adaptor.transform.localPosition = isFuelContainer ? new Vector3(0.00f, -0.06f, -0.26f) : new Vector3(0.00f, 0.26f, 0.05f);
adaptor.transform.rotation = container.transform.rotation * Quaternion.Euler(isFuelContainer ? new Vector3(0, 270, 90) : new Vector3(0, 90, 0));
adaptor.Spawn();
adaptor.SendNetworkUpdateImmediate();
}
if (!isFuelContainer)
{
var button = GameManager.server.CreateEntity("assets/prefabs/io/electric/switches/pressbutton/pressbutton.prefab") as PressButton;
button.SetParent(container, true, true);
button.transform.localPosition = new Vector3(0.40f, 1.60f, -0.13f);
button.transform.rotation = container.transform.rotation * Quaternion.Euler(new Vector3(10, 90, 180));
button.Spawn();
button.SendNetworkUpdateImmediate();
}
}
public bool CanTransferAllResources(StorageContainer outputContainer)
{
foreach (var resource in _config.NoUpgrades.ResourcesOutput)
{
if (!TryTransferResourceItem(outputContainer, resource.Shortname, resource.Amount))
{
return false;
}
}
return true;
}
public void HandleFuelConsumption(Item fuel, int requiredFuelAmount)
{
if (fuel.amount > requiredFuelAmount)
{
SafelyRemoveItem(fuel.SplitItem(requiredFuelAmount));
}
else
{
SafelyRemoveItem(fuel);
}
}
public void TransferResources(StorageContainer outputContainer)
{
foreach (var resource in _config.NoUpgrades.ResourcesOutput)
{
TryTransferResourceItem(outputContainer, resource.Shortname, resource.Amount, true);
}
}
public bool TryTransferResourceItem(StorageContainer container, string itemShortName, int amount, bool transfer = false)
{
if (amount <= 0)
return false;
var item = ItemManager.CreateByName(itemShortName, amount, 0uL);
if (item == null)
return false;
if (transfer)
item.SetFlag(ExtractedItemFlag, true);
return TransferItem(container, item, transfer);
}
private bool TransferItem(StorageContainer container, Item item, bool transfer)
{
for (int i = 0; i < container.inventory.capacity; i++)
{
var slotItem = container.inventory.GetSlot(i);
if (slotItem != null && slotItem.info == item.info && slotItem.CanStack(item) && TryStackToSlot(slotItem, item, transfer, container))
{
return true;
}
}
return PlaceInEmptySlot(container, item, transfer);
}
private bool TryStackToSlot(Item slotItem, Item item, bool transfer, StorageContainer container)
{
int availableSpace = slotItem.MaxStackable() - slotItem.amount;
if (availableSpace <= 0)
return false;
if (availableSpace >= item.amount)
{
if (transfer && item.MoveToContainer(container.inventory, slotItem.position))
item.SetFlag(ExtractedItemFlag, false);
return true;
}
else
{
UpdateItemStacks(item, slotItem, availableSpace);
return false;
}
}
private bool PlaceInEmptySlot(StorageContainer container, Item item, bool transfer)
{
for (int i = 0; i < container.inventory.capacity; i++)
{
if (container.inventory.GetSlot(i) == null && container.inventory.canAcceptItem(item, i))
{
if (transfer && item.MoveToContainer(container.inventory, i))
{
item.SetFlag(ExtractedItemFlag, false);
return true;
}
return true;
}
}
return false;
}
private void UpdateItemStacks(Item item, Item slotItem, int spaceToFill)
{
item.amount -= spaceToFill;
slotItem.amount += spaceToFill;
slotItem.MarkDirty();
}
#endregion
#region Utility Methods
private string Msg(string userid, string key, params object[] obj)
{
return string.Format(lang.GetMessage(key, this, userid), obj);
}
private void NotifyPlayer(IPlayer player, string key, int type, params object[] obj)
{
var UserIDString = player.Id;
if (_config.UseNotify && Notify != null)
Interface.Oxide.CallHook("SendNotify", UserIDString, type, Msg(UserIDString, key, obj));
else
player.Message(Msg(player.Id, key, obj));
}
private void NotifyPlayer(BasePlayer player, string key, int type, params object[] obj)
{
var UserIDString = player.UserIDString;
if (_config.UseNotify && Notify != null)
Interface.Oxide.CallHook("SendNotify", UserIDString, type, Msg(UserIDString, key, obj));
else
player.ChatMessage(Msg(UserIDString, key, obj));
}
public void SafelyRemoveItem(Item item)
{
item?.RemoveFromWorld();
item?.RemoveFromContainer();
item?.Remove();
}
private void RegisterPermissions()
{
foreach (string permissionName in _permissions)
permission.RegisterPermission(permissionName, this);
}
private void RegisterCommands()
{
AddCovalenceCommand(_config.GiveQuarryCommand, nameof(GiveQuarryCommand));
AddCovalenceCommand(_config.RemoveQuarryCommand, nameof(RemoveQuarryCommand));
}
private void InitializeExistingQuarries()
{
foreach (var signalComputer in UnityEngine.Object.FindObjectsOfType<ExcavatorSignalComputer>())
{
if (signalComputer.OwnerID != 0)
{
signalComputer.gameObject.AddComponent<QuarryComputerBehaviour>();
}
}
timer.Every(30, InitializeQuarries);
}
private void InitializeQuarries()
{
foreach (var quarry in QuarryCheckStatusList)
{
if (!quarry.IsOn)
quarry.StartMining();
}
QuarryCheckStatusList.Clear();
}
private void UnloadAllQuarryBehaviours()
{
var behaviours = UnityEngine.Object.FindObjectsOfType<QuarryComputerBehaviour>();
foreach (var behaviour in behaviours)
{
behaviour.Unload();
UnityEngine.Object.Destroy(behaviour);
}
}
#endregion
#region Quarry Behaviour Class
private class QuarryComputerBehaviour : MonoBehaviour
{
private ExcavatorSignalComputer _signalComputer;
public StorageContainer OutputContainer { get; private set; }
public StorageContainer FuelContainer { get; private set; }
public int Level { get; private set; }
public ulong OwnerID { get; private set; }
public bool IsOn = true;
private void Awake()
{
InitializeSignalComputer();
UpdateQuarryOwnerID();
InitializeContainers();
ScheduleRoutineTasks();
UpdateQuarryLevel();
UpdateQuarryCapacity();
}
private void InitializeSignalComputer()
{
_signalComputer = GetComponent<ExcavatorSignalComputer>();
_signalComputer.SetFlag(BaseEntity.Flags.Reserved8, false);
_signalComputer.chargePower = 0f;
}
private void UpdateQuarryOwnerID()
{
OwnerID = _signalComputer.OwnerID;
}
private void InitializeContainers()
{
foreach (var container in _signalComputer.children.Cast<StorageContainer>())
{
if (container.name == QuarryOutputStoragePrefab)
OutputContainer = container;
else if (container.name == QuarryFuelStoragePrefab)
FuelContainer = container;
}
}
private void UpdateQuarryLevel()
{
if (OutputContainer.OwnerID == 0)
Level = 1;
else
Level = (int)OutputContainer.OwnerID;
}
private void UpdateQuarryCapacity()
{
OutputContainer.inventory.capacity = 12;
FuelContainer.inventory.capacity = 6;
}
private void ScheduleRoutineTasks()
{
InvokeRepeating(nameof(CheckGroundIntegrity), 30f, 30f);
InvokeRepeating(nameof(PerformResourceExtraction), 0f, _instance._config.FuelConfiguration.ResourceExtractionInterval);
}
public void StartMining()
{
CancelInvoke(nameof(PerformResourceExtraction));
InvokeRepeating(nameof(PerformResourceExtraction), 0f, _instance._config.FuelConfiguration.ResourceExtractionInterval);
}
private void PerformResourceExtraction()
{
_instance.Puts("PerformResourceExtraction: " + _signalComputer.net.ID); //
IsOn = true;
if (FuelContainer == null || OutputContainer == null)
return;
var fuelItem = FuelContainer.inventory.itemList.Find(item => item.info.shortname == _instance._config.FuelConfiguration.Shortname);
int fuelRequired = _instance._config.FuelConfiguration.FuelRequiredPerExtraction;
if (fuelItem == null || fuelItem.amount < fuelRequired)
{
SetSignalComputerState(false);
CancelInvoke(nameof(PerformResourceExtraction));
IsOn = false;
return;
}
if (_instance.CanTransferAllResources(OutputContainer))
{
_instance.HandleFuelConsumption(fuelItem, fuelRequired);
_instance.TransferResources(OutputContainer);
SetSignalComputerState(true);
}
else
{
SetSignalComputerState(false);
CancelInvoke(nameof(PerformResourceExtraction));
IsOn = false;
}
}
private void SetSignalComputerState(bool isActive)
{
_signalComputer.SetFlag(BaseEntity.Flags.Reserved8, isActive);
_signalComputer.chargePower = isActive ? 1 : 0;
}
private void CheckGroundIntegrity()
{
if (_signalComputer.HasParent() && _signalComputer.GetParentEntity() is Tugboat)
{
CancelInvoke(nameof(CheckGroundIntegrity));
return;
}
Vector3 origin = _signalComputer.transform.position + new Vector3(0, 0.1f, 0);
if (!Physics.Raycast(origin, Vector3.down, out var hitInfo, 4f, LayerMask.GetMask("Terrain", "Construction")) || hitInfo.distance > 0.2f)
{
HandleGroundLoss();
}
}
private void HandleGroundLoss()
{
CancelInvoke(nameof(PerformResourceExtraction));
CancelInvoke(nameof(CheckGroundIntegrity));
_signalComputer.Kill();
_instance.CreateQuarryItem()?.Drop(_signalComputer.transform.position, Vector3.zero);
Effect.server.Run("assets/prefabs/deployable/quarry/effects/mining-quarry-deploy.prefab", _signalComputer.transform.position);
}
private void OnDestroy()
{
CancelInvoke(nameof(PerformResourceExtraction));
CancelInvoke(nameof(CheckGroundIntegrity));
}
public void Unload()
{
_signalComputer.SetFlag(BaseEntity.Flags.Reserved8, false);
_signalComputer.chargePower = 0f;
}
}
#endregion
}
}