Иконка ресурса

FREE BuildCost : 0.0.2 0.0.2

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Oxide.Plugins
{
	[Info("BuildCost", "ignignokt84", "0.0.2", ResourceId = 2388)]
	[Description("Build cost utility")]
	class BuildCost : RustPlugin
	{
		#region Variables

		// usage permission
		const string PermCanUse = "buildcost.canuse";

		// layer mask
		int layerMasks = LayerMask.GetMask("Construction", "Construction Trigger", "Trigger");

		// deployable -> item lookup map
		Dictionary<uint, int> deployableLookup = new Dictionary<uint, int>();
		// aggregation helper
		CostAggregator aggregator = new CostAggregator();

		// groups
		enum Group { All, BuildingBlocks, Deployables }

		#endregion


		#region Lang

		// load default messages to Lang
		void LoadDefaultMessages()
		{
			var messages = new Dictionary<string, string>
			{
				{"Prefix", "<color=orange>[ BuildCost ]</color> "},
				{"BuildingBlockCost", "<color=cyan>Building Blocks ({0})</color>" + Environment.NewLine + "<size=12>{1}</size>" },
				{"DeployablesCost", "<color=cyan>Deployables ({0})</color>" + Environment.NewLine + "<size=12>{1}</size>" },
				{"NoBuildingFound", "No building found" }
			};
			lang.RegisterMessages(messages, this);
		}

		// get message from Lang
		string GetMessage(string key, string userId = null) => lang.GetMessage(key, this, userId);

		#endregion

		#region Loading/Unloading

		// on load
		void Init()
		{
			permission.RegisterPermission(PermCanUse, this);
			cmd.AddChatCommand("cost", this, "CalculateCost");
		}

		// server initialized
		void OnServerInitialized()
		{
			BuildDeployableLookups();
		}

		#endregion

		#region Messaging

		// send reply to a player
		void SendMessage(BasePlayer player, string message, object[] options = null)
		{
			string msg = GetMessage(message, player.UserIDString);
			if (options != null && options.Length > 0)
				msg = string.Format(msg, options);
			SendReply(player, GetMessage("Prefix", player.UserIDString) + msg);
		}

		#endregion

		#region Helper Procedures

		// build reference map of prefab IDs to item IDs
		void BuildDeployableLookups()
		{
			foreach (ItemDefinition i in ItemManager.GetItemDefinitions())
			{
				if (i == null) continue;
				ItemModDeployable m = i.GetComponent<ItemModDeployable>();
				if (m != null)
					deployableLookup[m.entityPrefab.resourceID] = i.itemid;
			}
		}

		// handle command
		void CalculateCost(BasePlayer player, string command, string[] args)
		{
			if (!hasPermission(player, PermCanUse)) return;
			aggregator.Reset();
			object closestEntity;
			if (!GetRaycastTarget(player, out closestEntity))
			{
				SendMessage(player, "NoBuildingFound");
				return;
			}
			BaseEntity initialBlock = closestEntity as BaseEntity;
			if (initialBlock == null)
			{
				SendMessage(player, "NoBuildingFound");
				return;
			}

			HashSet<BuildingBlock> blocks;
			HashSet<BaseEntity> deployables;
			if (GetStructure(initialBlock, out blocks, out deployables))
			{
				CalculateBuildingBlockCost(blocks);
				CalculateDeployableCost(deployables);
			}
			if (aggregator.counter.Values.Sum() == 0)
			{
				SendMessage(player, "NoBuildingFound");
				return;
			}

			if (aggregator.costs.ContainsKey(Group.BuildingBlocks))
				SendMessage(player, "BuildingBlockCost", aggregator.GetCost(Group.BuildingBlocks));
			if (aggregator.costs.ContainsKey(Group.Deployables))
				SendMessage(player, "DeployablesCost", aggregator.GetCost(Group.Deployables));
		}

		// raycasting
		bool GetRaycastTarget(BasePlayer player, out object closestEntity)
		{
			closestEntity = false;
			RaycastHit hit;
			if (!Physics.Raycast(player.eyes.HeadRay(), out hit, 100f))
				return false;
			closestEntity = hit.GetEntity();
			return true;
		}

		// builds a list of entities which make up a structure
		bool GetStructure(BaseEntity initialBlock, out HashSet<BuildingBlock> structure, out HashSet<BaseEntity> deployables)
		{
			structure = new HashSet<BuildingBlock>();
			deployables = new HashSet<BaseEntity>();
			List<Vector3> checkFrom = new List<Vector3>();
			BuildingBlock block;

			checkFrom.Add(initialBlock.transform.position);
			if (initialBlock is BuildingBlock)
				structure.Add(initialBlock as BuildingBlock);

			int current = 0;
			while (true)
			{
				current++;
				if (current > checkFrom.Count)
					break;
				List<BaseEntity> list = new List<BaseEntity>();
				Vis.Entities(checkFrom[current - 1], 3f, list);
				for (int i = 0; i < list.Count; i++)
				{
					BaseEntity hit = list[i];
					if (hit.GetComponentInParent<BuildingBlock>() != null)
					{
						block = hit.GetComponentInParent<BuildingBlock>();
						if (!(structure.Contains(block)))
						{
							checkFrom.Add(block.transform.position);
							structure.Add(block);
						}
					}
					else if (hit != null)
					{
						deployables.Add(hit);
						if (hit.HasSlot(BaseEntity.Slot.Lock))
						{
							BaseEntity l = hit.GetSlot(BaseEntity.Slot.Lock);
							if (l != null)
								deployables.Add(l);
						}
					}
				}
			}

			return true;
		}

		// aggregate all building block costs
		void CalculateBuildingBlockCost(HashSet<BuildingBlock> blocks)
		{
			foreach (BuildingBlock block in blocks)
			{
				if (block == null) continue;
				// only calculate twig and current grade
				aggregator.AddCosts(block.blockDefinition.grades[(int)block.grade].costToBuild, Group.BuildingBlocks);
				if (block.grade != BuildingGrade.Enum.Twigs)
					aggregator.AddCosts(block.blockDefinition.grades[(int)BuildingGrade.Enum.Twigs].costToBuild, Group.BuildingBlocks, false);
			}
		}

		// aggregate all deployable costs
		void CalculateDeployableCost(HashSet<BaseEntity> deployables)
		{
			foreach (BaseEntity deployable in deployables)
			{
				if (deployable == null) continue;
				if (!deployableLookup.ContainsKey(deployable.prefabID)) continue;
				int itemId = deployableLookup[deployable.prefabID];
				ItemBlueprint b = ItemManager.FindItemDefinition(itemId)?.Blueprint;
				if (b == null) continue;
				aggregator.AddCosts(b.ingredients, Group.Deployables);
			}
		}

		// permission check
		private bool hasPermission(BasePlayer player, string permname)
		{
			return player.IsAdmin || permission.UserHasPermission(player.UserIDString, permname);
		}

		#endregion

		#region Subclasses

		// entity cost aggregation helper class
		class CostAggregator
		{
			public Dictionary<Group, List<ItemAmount>> costs = new Dictionary<Group, List<ItemAmount>>();
			public Dictionary<Group, int> counter = new Dictionary<Group, int>();

			public void Reset()
			{
				costs = new Dictionary<Group, List<ItemAmount>>();
				counter = new Dictionary<Group, int>();
			}

			public void AddCosts(List<ItemAmount> amounts, Group group = Group.All, bool increment = true)
			{
				if (increment)
				{
					if (counter.ContainsKey(group))
						counter[group]++;
					else
						counter[group] = 1;
				}
				foreach (ItemAmount amount in amounts)
					AddCost(amount, group);
			}

			public void AddCost(ItemAmount amount, Group group = Group.All)
			{
				if (!costs.ContainsKey(group))
					costs[group] = new List<ItemAmount>();
				List<ItemAmount> groupCosts = costs[group];

				ItemAmount existing = groupCosts.SingleOrDefault(i => i.itemid == amount.itemid);
				if (existing == null)
					groupCosts.Add(new ItemAmount(amount.itemDef, amount.amount));
				else
					existing.amount += amount.amount;
			}

			public object[] GetCost(Group group = Group.All)
			{
				if (!costs.ContainsKey(group) || costs[group] == null || costs[group].Count == 0)
				{
					return null;
				}
				List<ItemAmount> itemList = costs[group];
				List<string> costStrings = new List<string>();
				foreach (ItemAmount amount in itemList)
					if (amount != null)
						costStrings.Add(amount.itemDef.displayName.translated + ": " + amount.amount);

				return new object[] { counter[group], string.Join(Environment.NewLine, costStrings.ToArray()) };
			}
		}

		#endregion
	}
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху