C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using Rust;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Building Grades", "Default/Arainrr/Dana", "1.0.10")]
[Description("Allows players to easily upgrade or downgrade an entire building")]
public class BuildingGrades : RustPlugin
{
#region Fields
[PluginReference]
private readonly Plugin Friends, Clans, NoEscape, RustTranslationAPI;
private const string PermissionUpPrefix = "buildinggrades.up.";
private const string PermissionDownPrefx = "buildinggrades.down.";
private const string PermissionUse = "buildinggrades.use";
private const string PermissionUpAll = PermissionUpPrefix + "all";
private const string PermissionDownAll = PermissionDownPrefx + "all";
private const string PermissionNoCost = "buildinggrades.nocost";
private const string PermissionAdmin = "buildinggrades.admin";
private static BuildingGrades _instance;
private BuildingGradeAssistant _assistant = new BuildingGradeAssistant();
private readonly Dictionary<string, HashSet<uint>> _categories = new Dictionary<string, HashSet<uint>>(StringComparer.OrdinalIgnoreCase);
private static readonly List<BuildingGrade.Enum> ValidGrades = new List<BuildingGrade.Enum>
{
BuildingGrade.Enum.Twigs, BuildingGrade.Enum.Wood, BuildingGrade.Enum.Stone, BuildingGrade.Enum.Metal, BuildingGrade.Enum.TopTier
};
#endregion Fields
#region Oxide Hooks
private void Init()
{
_instance = this;
foreach (var kvp in _configData.Permissions)
{
if (!permission.PermissionExists(kvp.Key, this))
{
permission.RegisterPermission(kvp.Key, this);
}
}
permission.RegisterPermission(PermissionUpAll, this);
permission.RegisterPermission(PermissionDownAll, this);
permission.RegisterPermission(PermissionNoCost, this);
permission.RegisterPermission(PermissionAdmin, this);
if (!permission.PermissionExists(PermissionUse, this))
{
permission.RegisterPermission(PermissionUse, this);
}
foreach (var validGrade in ValidGrades)
{
if (validGrade > BuildingGrade.Enum.Twigs)
{
permission.RegisterPermission(PermissionUpPrefix + (int)validGrade, this);
}
if (validGrade < BuildingGrade.Enum.TopTier)
{
permission.RegisterPermission(PermissionDownPrefx + (int)validGrade, this);
}
}
cmd.AddChatCommand(_configData.Chat.UpgradeCommand, this, nameof(CmdUpgrade));
cmd.AddChatCommand(_configData.Chat.DowngradeCommand, this, nameof(CmdDowngrade));
cmd.AddChatCommand(_configData.Chat.UpgradeAllCommand, this, nameof(CmdUpgradeAll));
cmd.AddChatCommand(_configData.Chat.DowngradeAllCommand, this, nameof(CmdDowngradeAll));
if (!_configData.Global.UseRaidBlocker)
{
Unsubscribe(nameof(OnRaidBlock));
}
if (!_configData.Global.UseCombatBlocker)
{
Unsubscribe(nameof(OnCombatBlock));
}
}
private void OnServerInitialized()
{
foreach (var entry in _configData.Categories)
{
var values = new HashSet<uint>();
foreach (var prefab in entry.Value)
{
var item = StringPool.Get(prefab);
if (item == 0u)
{
continue;
}
values.Add(item);
}
_categories.Add(entry.Key, values);
}
}
private void Unload()
{
_assistant.Unload();
_instance = null;
}
private void OnRaidBlock(BasePlayer player)
{
OnCombatBlock(player);
}
private void OnCombatBlock(BasePlayer player)
{
if (_assistant.IsRunning())
{
_assistant.BlockPlayer(player.userID);
}
}
#endregion Oxide Hooks
#region Chat Commands
private void CmdUpgrade(BasePlayer player, string command, string[] args)
{
HandleCommand(player, args, true, false);
}
private void CmdDowngrade(BasePlayer player, string command, string[] args)
{
HandleCommand(player, args, false, false);
}
private void CmdUpgradeAll(BasePlayer player, string command, string[] args)
{
HandleCommand(player, args, true, true);
}
private void CmdDowngradeAll(BasePlayer player, string command, string[] args)
{
HandleCommand(player, args, false, true);
}
#endregion Chat Commands
#region Methods
private void HandleCommand(BasePlayer player, string[] args, bool isUpgrade, bool isAll)
{
if (!permission.UserHasPermission(player.UserIDString, PermissionUse))
{
Print(player, Lang("NotAllowed", player.UserIDString));
return;
}
if (_assistant.IsRunning())
{
Print(player, Lang("AlreadyProcess", player.UserIDString));
return;
}
if (IsPlayerBlocked(player))
{
return;
}
HashSet<uint> filter = null;
var targetGrade = BuildingGrade.Enum.None;
if (args.Length > 0)
{
if (!_categories.TryGetValue(args[0], out filter))
{
if (!Enum.TryParse(args[0], true, out targetGrade) || !ValidGrades.Contains(targetGrade) || isUpgrade ? targetGrade <= BuildingGrade.Enum.Twigs : targetGrade >= BuildingGrade.Enum.TopTier)
{
Print(player, Lang("UnknownGrade", player.UserIDString));
return;
}
if (!HasGradePermission(player, targetGrade, isUpgrade))
{
Print(player, Lang("NotAllowed", player.UserIDString));
return;
}
if (args.Length > 1 && !_categories.TryGetValue(args[1], out filter))
{
Print(player, Lang("UnknownCategory", player.UserIDString, string.Join(", ", _configData.Categories.Keys)));
return;
}
}
}
else
{
if (!_assistant.FindPlayerGrantedGrades(player, isUpgrade))
{
Print(player, Lang("NotAllowed", player.UserIDString));
return;
}
}
var permissionSettings = GetPermissionSettings(player);
if (permissionSettings.Cooldown > 0f && !(_configData.Global.CooldownExclude && player.IsAdmin))
{
var timeLeft = _assistant.GetCooldownLeft(player.userID, permissionSettings.Cooldown);
if (timeLeft > 0f)
{
Print(player, Lang("OnCooldown", player.UserIDString, Mathf.CeilToInt(timeLeft)));
return;
}
}
var targetBuildingBlock = GetBuildingBlockLookingAt(player, permissionSettings);
if (targetBuildingBlock == null)
{
Print(player, Lang("NotLookingAt", player.UserIDString));
return;
}
var isAdmin = permission.UserHasPermission(player.UserIDString, PermissionAdmin);
if (!isAdmin && player.IsBuildingBlocked(targetBuildingBlock.WorldSpaceBounds()))
{
Print(player, Lang("BuildingBlocked", player.UserIDString));
return;
}
_assistant.Run(targetBuildingBlock, player, targetGrade, filter, permissionSettings, isUpgrade, isAll, isAdmin);
}
private PermissionSettings GetPermissionSettings(BasePlayer player)
{
var priority = 0;
PermissionSettings permissionSettings = null;
foreach (var entry in _configData.Permissions)
{
if (entry.Value.Priority >= priority && permission.UserHasPermission(player.UserIDString, entry.Key))
{
priority = entry.Value.Priority;
permissionSettings = entry.Value;
}
}
return permissionSettings ?? new PermissionSettings();
}
private bool HasGradePermission(BasePlayer player, BuildingGrade.Enum grade, bool isUpgrade)
{
return isUpgrade
? permission.UserHasPermission(player.UserIDString, PermissionUpAll) ||
permission.UserHasPermission(player.UserIDString, PermissionUpPrefix + (int)grade)
: permission.UserHasPermission(player.UserIDString, PermissionDownAll) ||
permission.UserHasPermission(player.UserIDString, PermissionDownPrefx + (int)grade);
}
#region AreFriends
private bool AreFriends(ulong playerId, ulong friendId)
{
if (!playerId.IsSteamId())
{
return false;
}
if (playerId == friendId)
{
return true;
}
if (_configData.Global.UseTeams && SameTeam(playerId, friendId))
{
return true;
}
if (_configData.Global.UseFriends && HasFriend(playerId, friendId))
{
return true;
}
if (_configData.Global.UseClans && SameClan(playerId, friendId))
{
return true;
}
return false;
}
private static bool SameTeam(ulong playerId, ulong friendId)
{
if (!RelationshipManager.TeamsEnabled())
{
return false;
}
var playerTeam = RelationshipManager.ServerInstance.FindPlayersTeam(playerId);
if (playerTeam == null)
{
return false;
}
var friendTeam = RelationshipManager.ServerInstance.FindPlayersTeam(friendId);
if (friendTeam == null)
{
return false;
}
return playerTeam == friendTeam;
}
private bool HasFriend(ulong playerId, ulong friendId)
{
if (Friends == null)
{
return false;
}
return (bool)Friends.Call("HasFriend", playerId, friendId);
}
private bool SameClan(ulong playerId, ulong friendId)
{
if (Clans == null)
{
return false;
}
//Clans
var isMember = Clans.Call("IsClanMember", playerId.ToString(), friendId.ToString());
if (isMember != null)
{
return (bool)isMember;
}
//Rust:IO Clans
var playerClan = Clans.Call("GetClanOf", playerId);
if (playerClan == null)
{
return false;
}
var friendClan = Clans.Call("GetClanOf", friendId);
if (friendClan == null)
{
return false;
}
return (string)playerClan == (string)friendClan;
}
#endregion AreFriends
#region PlayerIsBlocked
private bool IsPlayerBlocked(BasePlayer player)
{
if (NoEscape == null)
{
return false;
}
if (_configData.Global.UseRaidBlocker && IsRaidBlocked(player.UserIDString))
{
Print(player, Lang("RaidBlocked", player.UserIDString));
return true;
}
if (_configData.Global.UseCombatBlocker && IsCombatBlocked(player.UserIDString))
{
Print(player, Lang("CombatBlocked", player.UserIDString));
return true;
}
return false;
}
private bool IsRaidBlocked(string playerId)
{
return (bool)NoEscape.Call("IsRaidBlocked", playerId);
}
private bool IsCombatBlocked(string playerId)
{
return (bool)NoEscape.Call("IsCombatBlocked", playerId);
}
#endregion PlayerIsBlocked
#region RustTranslationAPI
private string GetItemTranslationByShortName(string language, string itemShortName)
{
return (string)RustTranslationAPI.Call("GetItemTranslationByShortName", language, itemShortName);
}
private string GetItemDisplayName(string language, ItemDefinition itemDefinition)
{
if (RustTranslationAPI != null)
{
var displayName = GetItemTranslationByShortName(language, itemDefinition.shortname);
if (!string.IsNullOrEmpty(displayName))
{
return displayName;
}
}
return itemDefinition.displayName.english;
}
#endregion RustTranslationAPI
#endregion Methods
#region Assistant
private class BuildingGradeAssistant
{
private BuildingGrades Plugin => _instance;
private Coroutine _changeGradeCoroutine;
private readonly Dictionary<ulong, bool> _tempFriends = new Dictionary<ulong, bool>();
private readonly HashSet<BuildingBlock> _allBuildingBlocks = new HashSet<BuildingBlock>();
private readonly List<BuildingGrade.Enum> _tempGrantedGrades = new List<BuildingGrade.Enum>();
private readonly List<Item> _collect = new List<Item>();
private readonly Hash<int, float> _takeOutItems = new Hash<int, float>();
private readonly Hash<ItemDefinition, int> _missingItems = new Hash<ItemDefinition, int>();
private HashSet<ulong> _blockedPlayers = new HashSet<ulong>();
private readonly Dictionary<ulong, float> _cooldowns = new Dictionary<ulong, float>();
private BuildingBlock _processingBuildingBlock;
internal bool IsRunning()
{
return _changeGradeCoroutine != null;
}
internal void Unload()
{
if (_changeGradeCoroutine != null)
{
ServerMgr.Instance.StopCoroutine(_changeGradeCoroutine);
}
}
internal void BlockPlayer(ulong playerId)
{
_blockedPlayers.Add(playerId);
}
internal bool IsProcessingBuildingBlock(BuildingBlock buildingBlock)
{
if (buildingBlock == null)
{
return false;
}
return _processingBuildingBlock == buildingBlock;
}
internal void Run(BuildingBlock sourceEntity, BasePlayer player, BuildingGrade.Enum targetGrade, HashSet<uint> filter, PermissionSettings permissionSettings, bool isUpgrade, bool isAll, bool isAdmin)
{
if (IsRunning())
{
return;
}
_changeGradeCoroutine = ServerMgr.Instance.StartCoroutine(StartChangeBuildingGrade(sourceEntity, player, targetGrade, filter, permissionSettings, isUpgrade, isAll, isAdmin));
}
internal float GetCooldownLeft(ulong playerId, float cooldown)
{
float lastUse;
if (_cooldowns.TryGetValue(playerId, out lastUse))
{
return cooldown - (Time.realtimeSinceStartup - lastUse);
}
return 0f;
}
internal bool FindPlayerGrantedGrades(BasePlayer player, bool isUpgrade)
{
var all = Plugin.permission.UserHasPermission(player.UserIDString, isUpgrade ? PermissionUpAll : PermissionDownAll);
if (all)
{
_tempGrantedGrades.AddRange(ValidGrades);
return _tempGrantedGrades.Count > 0;
}
foreach (var validGrade in ValidGrades)
{
if (isUpgrade)
{
if (validGrade > BuildingGrade.Enum.Twigs && Plugin.permission.UserHasPermission(player.UserIDString, PermissionUpPrefix + (int)validGrade))
{
_tempGrantedGrades.Add(validGrade);
}
}
else
{
if (validGrade < BuildingGrade.Enum.TopTier && Plugin.permission.UserHasPermission(player.UserIDString, PermissionDownPrefx + (int)validGrade))
{
_tempGrantedGrades.Add(validGrade);
}
}
}
return _tempGrantedGrades.Count > 0;
}
private IEnumerator StartChangeBuildingGrade(BuildingBlock sourceEntity, BasePlayer player, BuildingGrade.Enum targetGrade, HashSet<uint> filter, PermissionSettings permissionSettings, bool isUpgrade, bool isAll, bool isAdmin)
{
_blockedPlayers.Clear();
yield return GetAllBuildingBlocks(sourceEntity, filter, isAll);
//if (pay) {
// FindUpgradeCosts(targetGrade);
// if (!CanAffordUpgrade(player)) {
// Clear();
// yield break;
// }
// PayForUpgrade(costs, player);
//}
Plugin.Print(player, Plugin.Lang(isUpgrade ? "StartUpgrade" : "StartDowngrade", player.UserIDString));
var playerId = player.userID;
yield return isUpgrade ? UpgradeBuildingBlocks(player, targetGrade, permissionSettings, isAdmin) : DowngradeBuildingBlocks(player, targetGrade, permissionSettings, isAdmin);
_tempFriends.Clear();
_allBuildingBlocks.Clear();
_tempGrantedGrades.Clear();
_blockedPlayers.Clear();
_cooldowns[playerId] = Time.realtimeSinceStartup;
_processingBuildingBlock = null;
_changeGradeCoroutine = null;
}
private bool ShouldInterrupt(ulong playerId)
{
return _blockedPlayers.Contains(playerId);
}
#region Upgrade
private IEnumerator UpgradeBuildingBlocks(BasePlayer player, BuildingGrade.Enum targetGrade, PermissionSettings permissionSettings, bool isAdmin)
{
var pay = permissionSettings.Pay && !Plugin.permission.UserHasPermission(player.UserIDString, PermissionNoCost);
int current = 0, success = 0;
var autoGrade = targetGrade == BuildingGrade.Enum.None;
foreach (var buildingBlock in _allBuildingBlocks)
{
if (buildingBlock == null || buildingBlock.IsDestroyed)
{
continue;
}
if (ShouldInterrupt(player.userID))
{
break;
}
var grade = targetGrade;
if (CheckBuildingGrade(buildingBlock, true, ref grade))
{
if (!autoGrade || _tempGrantedGrades.Contains(grade))
{
_processingBuildingBlock = buildingBlock;
if (TryUpgradeToGrade(buildingBlock, player, grade, pay, isAdmin))
{
success++;
}
_processingBuildingBlock = null;
}
}
if (++current % Plugin._configData.Global.PerFrame == 0)
{
yield return CoroutineEx.waitForEndOfFrame;
}
}
foreach (var item in _collect)
{
_takeOutItems[item.info.itemid] += item.amount;
item.Remove();
}
foreach (var entry in _takeOutItems)
{
player.Command("note.inv " + entry.Key + " " + entry.Value * -1f);
}
if (player != null && player.IsConnected)
{
if (_missingItems.Count > 0)
{
var stringBuilder = Pool.Get<StringBuilder>();
stringBuilder.Clear();
var language = Plugin.lang.GetLanguage(player.UserIDString);
foreach (var entry in _missingItems)
{
stringBuilder.AppendLine(Plugin.Lang("MissingItemsFormat", player.UserIDString, Plugin.GetItemDisplayName(language, entry.Key), entry.Value));
}
var missingResources = stringBuilder.ToString();
stringBuilder.Clear();
Pool.Free(ref stringBuilder);
Plugin.Print(player, success > 0 ? Plugin.Lang("UpgradeNotEnoughItemsSuccess", player.UserIDString, success, missingResources) : Plugin.Lang("UpgradeNotEnoughItems", player.UserIDString, missingResources));
}
else
{
Plugin.Print(player, success > 0 ? Plugin.Lang("FinishedUpgrade", player.UserIDString, success) : Plugin.Lang("NotUpgraded", player.UserIDString));
}
}
_collect.Clear();
_takeOutItems.Clear();
_missingItems.Clear();
}
private bool TryUpgradeToGrade(BuildingBlock buildingBlock, BasePlayer player, BuildingGrade.Enum targetGrade, bool pay, bool isAdmin)
{
if (!CanUpgrade(buildingBlock, player, targetGrade, pay, isAdmin))
{
return false;
}
var oldGrade = buildingBlock.grade;
SetBuildingBlockGrade(buildingBlock, targetGrade);
Interface.CallHook("OnStructureGradeUpdated", buildingBlock, player, oldGrade, targetGrade);
return true;
}
private bool CanUpgrade(BuildingBlock buildingBlock, BasePlayer player, BuildingGrade.Enum targetGrade, bool pay, bool isAdmin)
{
if (player == null || !player.CanInteract())
{
return false;
}
var constructionGrade = buildingBlock.blockDefinition.GetGrade(targetGrade, 0);
if (constructionGrade == null)
{
return false;
}
if (!isAdmin)
{
if (Interface.CallHook("OnStructureUpgrade", buildingBlock, player, targetGrade, 0) != null)
{
return false;
}
if (buildingBlock.SecondsSinceAttacked < 30f)
{
return false;
}
if (!buildingBlock.CanChangeToGrade(targetGrade, 0, player))
{
return false;
}
if (!HasAccess(player, buildingBlock))
{
return false;
}
}
if (pay)
{
//if (!buildingBlock.CanAffordUpgrade(targetGrade, player)) {
// return false;
//}
//buildingBlock.PayForUpgrade(constructionGrade, player);
if (!CanAffordUpgrade(buildingBlock, constructionGrade, player, targetGrade))
{
return false;
}
PayForUpgrade(buildingBlock, constructionGrade, player);
}
return true;
}
public bool CanAffordUpgrade(BuildingBlock buildingBlock, ConstructionGrade constructionGrade, BasePlayer player, BuildingGrade.Enum grade)
{
var obj = Interface.CallHook("CanAffordUpgrade", player, buildingBlock, grade);
if (obj is bool)
{
return (bool)obj;
}
var flag = true;
foreach (var item in constructionGrade.costToBuild)
{
var missingAmount = item.amount - player.inventory.GetAmount(item.itemid);
if (missingAmount > 0f)
{
flag = false;
_missingItems[item.itemDef] += (int)missingAmount;
}
}
return flag;
}
public void PayForUpgrade(BuildingBlock buildingBlock, ConstructionGrade constructionGrade, BasePlayer player)
{
if (Interface.CallHook("OnPayForUpgrade", player, buildingBlock, constructionGrade) != null)
{
return;
}
foreach (var item in constructionGrade.costToBuild)
{
player.inventory.Take(_collect, item.itemid, (int)item.amount);
//player.Command("note.inv " + item.itemid + " " + item.amount * -1f);
}
}
#endregion Upgrade
#region Downgrade
private IEnumerator DowngradeBuildingBlocks(BasePlayer player, BuildingGrade.Enum targetGrade, PermissionSettings permissionSettings, bool isAdmin)
{
int current = 0, success = 0;
var autoGrade = targetGrade == BuildingGrade.Enum.None;
foreach (var buildingBlock in _allBuildingBlocks)
{
if (buildingBlock == null || buildingBlock.IsDestroyed)
{
continue;
}
if (ShouldInterrupt(player.userID))
{
break;
}
var grade = targetGrade;
if (CheckBuildingGrade(buildingBlock, false, ref grade))
{
if (!autoGrade || _tempGrantedGrades.Contains(grade))
{
_processingBuildingBlock = buildingBlock;
if (TryDowngradeToGrade(buildingBlock, player, grade /*, permissionSettings.Refund*/, isAdmin: isAdmin))
{
success++;
}
_processingBuildingBlock = null;
}
}
if (current++ % Plugin._configData.Global.PerFrame == 0)
{
yield return CoroutineEx.waitForEndOfFrame;
}
}
if (player != null && player.IsConnected)
{
Plugin.Print(player, success > 0 ? Plugin.Lang("FinishedDowngrade", player.UserIDString, success) : Plugin.Lang("NotDowngraded", player.UserIDString));
}
}
private bool TryDowngradeToGrade(BuildingBlock buildingBlock, BasePlayer player, BuildingGrade.Enum targetGrade, bool refund = false, bool isAdmin = false)
{
if (!CanDowngrade(buildingBlock, player, targetGrade, refund, isAdmin))
{
return false;
}
//if (refund)
//{
// foreach (var itemAmount in buildingBlock.currentGrade.costToBuild)
// {
// var item = ItemManager.CreateByItemID(itemAmount.itemid, (int)itemAmount.amount);
// player.GiveItem(item);
// }
//}
var oldGrade = buildingBlock.grade;
SetBuildingBlockGrade(buildingBlock, targetGrade);
Interface.CallHook("OnStructureGradeUpdated", buildingBlock, player, oldGrade, targetGrade);
return true;
}
private bool CanDowngrade(BuildingBlock buildingBlock, BasePlayer player, BuildingGrade.Enum targetGrade, bool refund, bool isAdmin)
{
if (player == null || !player.CanInteract())
{
return false;
}
var constructionGrade = buildingBlock.blockDefinition.GetGrade(targetGrade, 0);
if (constructionGrade == null)
{
return false;
}
if (!isAdmin)
{
if (Interface.CallHook("OnStructureUpgrade", buildingBlock, player, targetGrade, 0) != null)
{
return false;
}
if (buildingBlock.SecondsSinceAttacked < 30f)
{
return false;
}
var obj = Interface.CallHook("CanChangeGrade", player, buildingBlock, targetGrade);
if (obj is bool)
{
return (bool)obj;
}
if (player.IsBuildingBlocked(buildingBlock.transform.position, buildingBlock.transform.rotation, buildingBlock.bounds))
{
return false;
}
if (buildingBlock.IsUpgradeBlocked())
{
return false;
}
if (!HasAccess(player, buildingBlock))
{
return false;
}
}
return true;
}
#endregion Downgrade
#region Methods
private bool HasAccess(BasePlayer player, BuildingBlock buildingBlock)
{
bool flag;
if (_tempFriends.TryGetValue(buildingBlock.OwnerID, out flag))
{
return flag;
}
var areFriends = Plugin.AreFriends(buildingBlock.OwnerID, player.userID);
_tempFriends.Add(buildingBlock.OwnerID, areFriends);
return areFriends;
}
private IEnumerator GetAllBuildingBlocks(BuildingBlock sourceEntity, HashSet<uint> filter, bool isAll)
{
Func<BuildingBlock, bool> func = x => filter == null || filter.Contains(x.prefabID);
if (isAll)
{
yield return GetNearbyEntities(sourceEntity, _allBuildingBlocks, Layers.Mask.Construction, func);
}
else
{
var building = sourceEntity.GetBuilding();
if (building != null)
{
foreach (var buildingBlock in building.buildingBlocks)
{
if (func(buildingBlock))
{
_allBuildingBlocks.Add(buildingBlock);
}
}
}
}
}
//#region TryPay
//private readonly Hash<int, int> costs = new Hash<int, int>();
//private readonly Hash<string , int> missingDictionary = new Hash<string, int>();
//private readonly HashSet<BuildingBlock> toRemove = new HashSet<BuildingBlock>();
//private bool TryPay(BasePlayer player, BuildingGrade.Enum targetGrade, out string missingResources) {
// FindUpgradeCosts(player, targetGrade);
// if (!CanPay(player, out missingResources)) {
// return false;
// }
// var collect = Pool.GetList<Item>();
// foreach (var entry in costs) {
// player.inventory.Take(collect, entry.Key, entry.Value);
// player.Command(string.Concat("note.inv ", entry.Key, " ", entry.Value * -1f));
// }
// foreach (var item in collect) {
// item.Remove();
// }
// Pool.FreeList(ref collect);
// missingResources = null;
// return true;
//}
//private bool CanPay(BasePlayer player, out string missingResources) {
// foreach (var entry in costs) {
// if (entry.Value <= 0) continue;
// var missingAmount = entry.Value - player.inventory.GetAmount(entry.Key);
// if (missingAmount <= 0) continue;
// var displayName= ItemManager.FindItemDefinition(entry.Key)?.displayName.english;
// if (string.IsNullOrEmpty(displayName)) displayName = entry.Key.ToString();
// missingDictionary[displayName] += missingAmount;
// }
// if (missingDictionary.Count > 0) {
// StringBuilder stringBuilder = Pool.Get<StringBuilder>();
// stringBuilder.Clear();
// foreach (var entry in missingDictionary) {
// stringBuilder.AppendLine(Lang("MissingResourceFormat", player.UserIDString, entry.Key, entry.Value));
// }
// missingResources = stringBuilder.ToString();
// stringBuilder.Clear();
// missingDictionary.Clear();
// Pool.Free(ref stringBuilder);
// return false;
// }
// missingResources = null;
// return true;
//}
//private void FindUpgradeCosts(BasePlayer player, BuildingGrade.Enum targetGrade) {
// var autoGrade = targetGrade == BuildingGrade.Enum.None;
// foreach (var buildingBlock in allBuildingBlocks) {
// if (buildingBlock == null || buildingBlock.IsDestroyed) {
// toRemove.Add(buildingBlock);
// continue;
// }
// BuildingGrade.Enum grade = targetGrade;
// if (CheckBuildingGrade(buildingBlock, false, ref grade)) {
// if (!autoGrade || tempGrantedGrades.Contains(grade)) {
// if (!CanUpgrade(buildingBlock, player, grade)) {
// toRemove.Add(buildingBlock);
// continue;
// }
// }
// }
// var costToBuild = buildingBlock.blockDefinition.grades[(int)grade].costToBuild;
// foreach (var itemAmount in costToBuild) {
// costs[itemAmount.itemid] += (int)itemAmount.amount;
// }
// }
// foreach (var buildingBlock in toRemove) {
// allBuildingBlocks.Remove(buildingBlock);
// }
// toRemove.Clear();
//}
//#endregion TryPay
#endregion Methods
}
#endregion Assistant
#region Helpers
private static BuildingBlock GetBuildingBlockLookingAt(BasePlayer player, PermissionSettings permissionSettings)
{
RaycastHit raycastHit;
var flag = Physics.Raycast(player.eyes.HeadRay(), out raycastHit, permissionSettings.Distance, Layers.Mask.Construction);
return flag ? raycastHit.GetEntity() as BuildingBlock : null;
}
private static bool CheckBuildingGrade(BuildingBlock buildingBlock, bool isUpgrade, ref BuildingGrade.Enum targetGrade)
{
if (buildingBlock.blockDefinition == null)
{
return false;
}
var grades = buildingBlock.blockDefinition.grades;
if (grades == null)
{
return false;
}
var grade = buildingBlock.grade;
if (IsValidGrade(grades, (int)targetGrade))
{
return isUpgrade ? grade < targetGrade : grade > targetGrade;
}
targetGrade = grade + (isUpgrade ? 1 : -1);
return IsValidGrade(grades, (int)targetGrade);
}
private static bool IsValidGrade(ConstructionGrade[] grades, int targetGrade)
{
return targetGrade >= 0 && targetGrade < grades.Length && grades[targetGrade] != null;
}
private static void SetBuildingBlockGrade(BuildingBlock buildingBlock, BuildingGrade.Enum targetGrade)
{
buildingBlock.SetGrade(targetGrade);
buildingBlock.SetHealthToMax();
buildingBlock.StartBeingRotatable();
buildingBlock.SendNetworkUpdate();
buildingBlock.UpdateSkin();
buildingBlock.ResetUpkeepTime();
buildingBlock.UpdateSurroundingEntities();
BuildingManager.server.GetBuilding(buildingBlock.buildingID)?.Dirty();
if (targetGrade > BuildingGrade.Enum.Twigs)
{
Effect.server.Run("assets/bundled/prefabs/fx/build/promote_" + targetGrade.ToString().ToLower() + ".prefab", buildingBlock, 0u, Vector3.zero, Vector3.zero);
}
}
private static IEnumerator GetNearbyEntities<T>(T sourceEntity, HashSet<T> entities, int layers, Func<T, bool> filter = null) where T : BaseEntity
{
var current = 0;
var checkFrom = Pool.Get<Queue<Vector3>>();
var nearbyEntities = Pool.GetList<T>();
checkFrom.Enqueue(sourceEntity.transform.position);
while (checkFrom.Count > 0)
{
nearbyEntities.Clear();
var position = checkFrom.Dequeue();
Vis.Entities(position, 3f, nearbyEntities, layers);
for (var i = 0; i < nearbyEntities.Count; i++)
{
var entity = nearbyEntities[i];
if (filter != null && !filter(entity))
{
continue;
}
if (!entities.Add(entity))
{
continue;
}
checkFrom.Enqueue(entity.transform.position);
}
if (++current % _instance._configData.Global.PerFrame == 0)
{
yield return CoroutineEx.waitForEndOfFrame;
}
}
Pool.Free(ref checkFrom);
Pool.FreeList(ref nearbyEntities);
}
#endregion Helpers
#region API
private bool IsProcessingBuildingBlock(BuildingBlock buildingBlock)
{
return _assistant.IsProcessingBuildingBlock(buildingBlock);
}
#endregion
#region ConfigurationFile
private ConfigData _configData;
private class ConfigData
{
[JsonProperty(PropertyName = "Settings")]
public GlobalSettings Global { get; set; } = new GlobalSettings();
[JsonProperty(PropertyName = "Chat Settings")]
public ChatSettings Chat { get; set; } = new ChatSettings();
[JsonProperty(PropertyName = "Permission Settings")]
public Dictionary<string, PermissionSettings> Permissions { get; set; } = new Dictionary<string, PermissionSettings>
{
[PermissionUse] = new PermissionSettings
{
Priority = 0,
Pay = true,
//Refund = false,
Cooldown = 60,
Distance = 10
}
};
[JsonProperty(PropertyName = "Building Block Categories", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, HashSet<string>> Categories { get; set; } = new Dictionary<string, HashSet<string>>
{
["foundation"] = new HashSet<string>
{
"assets/prefabs/building core/foundation/foundation.prefab",
"assets/prefabs/building core/foundation.steps/foundation.steps.prefab",
"assets/prefabs/building core/foundation.triangle/foundation.triangle.prefab"
},
["wall"] = new HashSet<string>
{
"assets/prefabs/building core/wall/wall.prefab",
"assets/prefabs/building core/wall.doorway/wall.doorway.prefab",
"assets/prefabs/building core/wall.frame/wall.frame.prefab",
"assets/prefabs/building core/wall.half/wall.half.prefab",
"assets/prefabs/building core/wall.low/wall.low.prefab",
"assets/prefabs/building core/wall.window/wall.window.prefab"
},
["floor"] = new HashSet<string>
{
"assets/prefabs/building core/floor/floor.prefab",
"assets/prefabs/building core/floor.frame/floor.frame.prefab",
"assets/prefabs/building core/floor.triangle/floor.triangle.prefab",
"assets/prefabs/building core/floor.triangle.frame/floor.triangle.frame.prefab"
},
["stair"] = new HashSet<string>
{
"assets/prefabs/building core/stairs.l/block.stair.lshape.prefab",
"assets/prefabs/building core/stairs.spiral/block.stair.spiral.prefab",
"assets/prefabs/building core/stairs.spiral.triangle/block.stair.spiral.triangle.prefab",
"assets/prefabs/building core/stairs.u/block.stair.ushape.prefab"
},
["roof"] = new HashSet<string>
{
"assets/prefabs/building core/roof/roof.prefab",
"assets/prefabs/building core/roof.triangle/roof.triangle.prefab"
},
["ramp"] = new HashSet<string>
{
"assets/prefabs/building core/ramp/ramp.prefab"
}
};
}
private class GlobalSettings
{
[JsonProperty(PropertyName = "Use Teams")]
public bool UseTeams { get; set; }
[JsonProperty(PropertyName = "Use Clans")]
public bool UseClans { get; set; } = true;
[JsonProperty(PropertyName = "Use Friends")]
public bool UseFriends { get; set; } = true;
[JsonProperty(PropertyName = "Use Raid Blocker (Need NoEscape Plugin)")]
public bool UseRaidBlocker { get; set; }
[JsonProperty(PropertyName = "Use Combat Blocker (Need NoEscape Plugin)")]
public bool UseCombatBlocker { get; set; }
[JsonProperty(PropertyName = "Cooldown Exclude Admins")]
public bool CooldownExclude { get; set; } = true;
[JsonProperty(PropertyName = "Upgrade/Downgrade Per Frame")]
public int PerFrame { get; set; } = 10;
}
private class ChatSettings
{
[JsonProperty(PropertyName = "Upgrade Chat Command")]
public string UpgradeCommand { get; set; } = "up";
[JsonProperty(PropertyName = "Downgrade Chat Command")]
public string DowngradeCommand { get; set; } = "down";
[JsonProperty(PropertyName = "Upgrade All Chat Command")]
public string UpgradeAllCommand { get; set; } = "upall";
[JsonProperty(PropertyName = "Downgrade All Chat Command")]
public string DowngradeAllCommand { get; set; } = "downall";
[JsonProperty(PropertyName = "Chat Prefix")]
public string Prefix { get; set; } = "<color=#00FFFF>[BuildingGrades]</color>: ";
[JsonProperty(PropertyName = "Chat SteamID Icon")]
public ulong SteamIdIcon { get; set; } = 0;
}
public class PermissionSettings
{
[JsonProperty(PropertyName = "Priority")]
public int Priority { get; set; }
[JsonProperty(PropertyName = "Distance")]
public float Distance { get; set; } = 4f;
[JsonProperty(PropertyName = "Cooldown")]
public float Cooldown { get; set; } = 60f;
[JsonProperty(PropertyName = "Pay")]
public bool Pay { get; set; } = true;
// [JsonProperty(PropertyName = "Refund")]
// public bool Refund { get; set; }
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_configData = Config.ReadObject<ConfigData>();
if (_configData == null)
{
LoadDefaultConfig();
}
}
catch (Exception ex)
{
PrintError($"The configuration file is corrupted.\n{ex}");
LoadDefaultConfig();
}
SaveConfig();
}
protected override void LoadDefaultConfig()
{
PrintWarning("Creating a new configuration file");
_configData = new ConfigData();
}
protected override void SaveConfig()
{
Config.WriteObject(_configData);
}
#endregion ConfigurationFile
#region LanguageFile
private void Print(BasePlayer player, string message)
{
Player.Message(player, message, _configData.Chat.Prefix, _configData.Chat.SteamIdIcon);
}
private string Lang(string key, string id = null, params object[] args)
{
try
{
return string.Format(lang.GetMessage(key, this, id), args);
}
catch (Exception)
{
PrintError($"Error in the language formatting of '{key}'.(userid: {id}.lang: {lang.GetLanguage(id)}.args: {string.Join(" ,", args)})");
throw;
}
}
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["NotAllowed"] = "<color=#FF1919>You do not have permission to use this comm
// ... [Code preview truncated due to length. Full source in attached file] ...