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

FREE WorldQuarry : 1.0.0 1.0.0

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
// Reference: Newtonsoft.Json
// Reference: Oxide.Ext.Rust

// #define DEBUG

using System;
using System.Collections.Generic;
using System.Linq;

using Newtonsoft.Json;

using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;

using UnityEngine;

using Random = UnityEngine.Random;

// Oxide requires your "main plugin" class to reside in Oxide.Plugins.It will not be able to be loaded otherwise.(Will compile fine, as it should, but the actual loader will fail
// because it can't find the plugin class) https://github.com/OxideMod/Oxide/blob/master/Oxide.Ext.CSharp/CompilablePlugin.cs#L102 is the offending code.// ReSharper disable once CheckNamespace
namespace Oxide.Plugins
{
	[Info("World Quarry", "ApocDev", "1.0.0")]
	public class WorldQuarry : RustPlugin
	{
		internal readonly List<Quarry> Quarries = new List<Quarry>();
		public DynamicConfigFile QuarryData { get; set; }

		private void Loaded()
		{
			QuarryData = Interface.GetMod().DataFileSystem.GetDatafile("WorldQuarryInstances");
		}

		[HookMethod("OnServerInitialized")]
		private void OnServerInitialized()
		{
			LoadQuarries();
		}

		[ChatCommand("quarry")]
		private void HandleQuarryCommand(BasePlayer player, string command, string[] args)
		{
			if (args.Length == 0)
			{
				player.ChatMessage("To create a quarry, place a 3x3 of boxes on the ground, without a building nearby and smack the middle box with a torch!");
				return;
			}

			switch (args[0].ToLowerInvariant())
			{
				case "clearall":
					if (player.IsAdmin())
					{
						var count = Quarries.Count;
						Quarries.Clear();
						SaveQuarries();
						player.ChatMessage(count + " quarr" + (count > 1 ? "ies" : "y") + " cleared!");
					}
					else
					{
						player.ChatMessage("You do not have permission for that command!");
					}
					break;
			}
		} // 185, 170, 134

		#region Nested type: Quarry

		internal class Quarry : IEquatable<Quarry>
		{
			[JsonIgnore]
			private static uint TickUpdateCounter = 1;

			/// <summary>
			///     Simply helps track how many ticks have passed since we updated this quarry.///     Default value has this spread across multiple ticks to avoid having all quarries ticked at once
			///     on server startup./// </summary>
			[JsonIgnore]
			internal uint TicksSinceUpdate = unchecked(TickUpdateCounter++) % NumTicksToThrottle;

			/// <summary>
			///     Initializes a new instance of the <see cref="T:System.Object" /> class./// </summary>
			public Quarry(Guid id, uint mainContainerId, List<uint> entityIds)
			{
				Id = id;
				EntityIds = entityIds;
				QuarryContainerId = mainContainerId;
			}

			public Quarry(uint mainContainerId, List<uint> entityIds)
				: this(Guid.NewGuid(), mainContainerId, entityIds)
			{
				TicksSinceUpdate = 0;
			}

			// Paramless ctor for json object creation.public Quarry()
			{
				EntityIds = new List<uint>();
			}

			public uint QuarryContainerId { get; set; }
			public List<uint> EntityIds { get; set; }
			public Guid Id { get; set; }

			#region IEquatable<Quarry> Members

			/// <summary>
			///     Indicates whether the current object is equal to another object of the same type./// </summary>
			/// <returns>
			///     true if the current object is equal to the <paramref name="other" /> parameter; otherwise, false./// </returns>
			/// <param name="other">An object to compare with this object.</param>
			public bool Equals(Quarry other)
			{
				if (ReferenceEquals(null, other))
				{
					return false;
				}
				if (ReferenceEquals(this, other))
				{
					return true;
				}
				return Id.Equals(other.Id);
			}

			#endregion

			/// <summary>
			///     Returns a string that represents the current object./// </summary>
			/// <returns>
			///     A string that represents the current object./// </returns>
			public override string ToString()
			{
				return string.Format("Id: {0}, QuarryContainerId: {1}, EntityIds: {2}, TicksSinceUpdate: {3}",
					Id,
					QuarryContainerId,
					string.Join(", ", EntityIds.Select(i => i.ToString()).ToArray()),
					TicksSinceUpdate);
			}

			public IEnumerable<BaseEntity> GetEntities()
			{
				return EntityIds.Select(entityId => BaseNetworkable.serverEntities.Find(entityId)).OfType<BaseEntity>();
			}

			public BaseEntity GetQuarryEntity()
			{
				return BaseNetworkable.serverEntities.Find(QuarryContainerId) as BaseEntity;
			}

			/// <summary>
			///     Determines whether the specified <see cref="T:System.Object" /> is equal to the current
			///     <see cref="T:System.Object" />./// </summary>
			/// <returns>
			///     true if the specified <see cref="T:System.Object" /> is equal to the current <see cref="T:System.Object" />;
			///     otherwise, false./// </returns>
			/// <param name="obj">The <see cref="T:System.Object" /> to compare with the current <see cref="T:System.Object" />.</param>
			public override bool Equals(object obj)
			{
				if (ReferenceEquals(null, obj))
				{
					return false;
				}
				if (ReferenceEquals(this, obj))
				{
					return true;
				}
				if (obj.GetType() != GetType())
				{
					return false;
				}
				return Equals((Quarry) obj);
			}

			/// <summary>
			///     Serves as a hash function for a particular type./// </summary>
			/// <returns>
			///     A hash code for the current <see cref="T:System.Object" />./// </returns>
			public override int GetHashCode()
			{
				return Id.GetHashCode();
			}

			public static bool operator ==(Quarry left, Quarry right)
			{
				return Equals(left, right);
			}

			public static bool operator !=(Quarry left, Quarry right)
			{
				return !Equals(left, right);
			}
		}

		#endregion

		#region Quarry Persistence

		private void LoadQuarries()
		{
			// Note: This doesn't use Oxide's default "DynamicData/ConfigFile" API, because it's pretty restrictive on datatypes allowed
			// And causes us to cast things all over the place.// Instead, we'll shove some json serialized strings into the data file that we can deserialize later
			// using Json.Net's awesome serialization.var quarryData = QuarryData.Get<string>("Quarries");

			if (string.IsNullOrEmpty(quarryData))
			{
				Quarries.Clear();
				return;
			}
			var settings = new JsonSerializerSettings
			{
				Formatting = Formatting.None,
				DefaultValueHandling = DefaultValueHandling.Populate,
				TypeNameHandling = TypeNameHandling.Auto,
				ObjectCreationHandling = ObjectCreationHandling.Replace
			};

			// Populate the actual quarry list now please.JsonConvert.PopulateObject(quarryData, Quarries, settings);
		}

		private void SaveQuarries()
		{
			QuarryData.Clear();
			var settings = new JsonSerializerSettings
			{
				Formatting = Formatting.None,
				DefaultValueHandling = DefaultValueHandling.Populate,
				TypeNameHandling = TypeNameHandling.Auto
			};

			string json = JsonConvert.SerializeObject(Quarries, settings);
			QuarryData["Quarries"] = json;
			Interface.GetMod().DataFileSystem.SaveDatafile("WorldQuarryInstances");
		}

		#endregion

		#region Config

		protected override void LoadDefaultConfig()
		{
			AmountToCreatePerTick = 2;
			TicksToInclude = 0.25f;
			StoneChance = 0.25f;
			MetalChance = 0.1f;
			SulfurChance = 0.05f;
		}

		/// <summary>
		///     The minimum number of ticks before a quarry can be updated.Raise this value to alleviate some server load.///     Lower values will cause client-side lag while players are looking inside quarry boxes.Suggested: 10+, Default: 10
		/// </summary>
		private const byte NumTicksToThrottle = 10;

		/// <summary>
		///     The base amount of each item to create per tick.Default: 2
		/// </summary>
		private int AmountToCreatePerTick { get { return Config.Get<int>("AmountToCreatePerTick"); } set { Config["AmountToCreatePerTick"] = value; } }

		/// <summary>
		///     How many of the total ticks should be included when updating the quarry.(0.0-1.0 [0%-100%]) Default: 0.25
		/// </summary>
		private float TicksToInclude { get { return Config.Get<float>("TicksToInclude"); } set { Config["TicksToInclude"] = value; } }

		// These are just the chances of each item to be created each tick.private float StoneChance { get { return Config.Get<float>("StoneChance"); } set { Config["StoneChance"] = value; } }
		private float SulfurChance { get { return Config.Get<float>("SulfurChance"); } set { Config["SulfurChance"] = value; } }
		private float MetalChance { get { return Config.Get<float>("MetalChance"); } set { Config["MetalChance"] = value; } }

		#endregion

		#region Updating Quarries

		[HookMethod("OnTick")]
		// ReSharper disable once UnusedMember.Local
		private void OnTick()
		{
			// Note: This spreads the updates across multiple ticks.// We don't want to hammer the server with tons of quarry updates
			// when it isn't necessary.for (int index = Quarries.Count - 1; index >= 0; index--)
			{
				var quarry = Quarries[index];
				
				// Is this quarry ready for an update?
				// Make sure we increase TicksSinceUpdate so we're not forgetting to actually update this quarry.if (quarry.TicksSinceUpdate++ < NumTicksToThrottle)
				{
					continue;
				}

				// Ensure the quarry is still in a valid state.// TODO: Check for nearby building blocks (avoids sneaky people building the quarry, then immediately dropping floors on top of it)
				if (quarry.EntityIds == null || quarry.EntityIds.Count != 9 || quarry.GetEntities().Any(e => !e.IsValid()))
				{
					Quarries.RemoveAt(index);
					Puts("Removing quarry [" + quarry + "] because it is missing required nearby entities.");
					SaveQuarries();
					continue;
				}

				if (quarry.GetQuarryEntity() != null)
				{
					var quarryBox = quarry.GetQuarryEntity();
					var container = quarryBox.GetComponent<StorageContainer>();

					if (container != null)
					{
						int numStones = 0;
						int numMetal = 0;
						int numSulfur = 0;

						// Figure out the totals for each tick
						// The only reason we're throttling ticks is because of the inventory update actually lagging
						// the client-side of things when the inventory is open, and being updated.for (int i = 0; i < (int) Math.Floor(quarry.TicksSinceUpdate * TicksToInclude); i++)
						{
							float createChance = Random.Range(0f, 1f);

							if (createChance < StoneChance)
							{
								numStones += AmountToCreatePerTick;
							}
							if (createChance < MetalChance)
							{
								numMetal += AmountToCreatePerTick;
							}
							if (createChance < SulfurChance)
							{
								numSulfur += AmountToCreatePerTick;
							}
						}

						if (numStones > 0)
						{
							var stones = ItemManager.CreateByName("stones", numStones);
							InsertIntoInventory(container.inventory, stones);
						}
						if (numMetal > 0)
						{
							var metal = ItemManager.CreateByName("metal_ore", numMetal);
							InsertIntoInventory(container.inventory, metal);
						}
						if (numSulfur > 0)
						{
							var sulfur = ItemManager.CreateByName("sulfur_ore", numSulfur);
							InsertIntoInventory(container.inventory, sulfur);
						}
					}
				}

				quarry.TicksSinceUpdate = 0;
			}
		}

		private void InsertIntoInventory(ItemContainer container, Item item)
		{
			if (item != null && container != null && item.IsValid())
			{
				if (!item.MoveToContainer(container))
				{
					item.Drop(container.dropPosition, container.dropVelocity);
				}
			}
		}

		#endregion

		#region Add/Remove Quarries

		[HookMethod("OnPlayerAttack")]
		// ReSharper disable once UnusedMember.Local
		private object OnPlayerAttack(BasePlayer player, HitInfo hitInfo)
		{
			if (hitInfo.HitEntity != null)
			{
				if (hitInfo.Weapon.GetItem().info.shortname == "torch")
				{
					TryUpdateQuarry(player, hitInfo);
				}
			}

			return null;
		}

		private Quarry GetQuarryForPart(BaseEntity ent)
		{
			var id = ent.net.ID;
			foreach (var quarry in Quarries)
			{
				if (quarry.EntityIds.Contains(id))
				{
					return quarry;
				}
			}
			return null;
		}

		private void TryUpdateQuarry(BasePlayer player, HitInfo hitInfo)
		{
			var hitEntity = hitInfo.HitEntity;

			if (hitEntity.GetComponentInParent<BaseEntity>() == null || hitEntity.GetComponentInParent<BaseEntity>().GetComponent<StorageContainer>() == null)
			{
				return;
			}

			var owningQuarry = GetQuarryForPart(hitEntity);
			if (owningQuarry != null)
			{
				Quarries.Remove(owningQuarry);
				SaveQuarries();
				player.ChatMessage("Quarry Removed!");
				return;
			}

			List<BaseEntity> containers;
			bool nearBuilding;
			if (!HasValidQuarryConstruction(hitEntity.transform.position, out containers, out nearBuilding))
			{
				if (nearBuilding)
				{
					player.ChatMessage("Cannot build quarry near buildings!");
				}
				else
				{
					player.ChatMessage("Invalid quarry construction! There must be a 3x3 area of wooden boxes (small or large).Smack the middle with a torch!");
				}
				return;
			}

			HashSet<uint> containerIds = new HashSet<uint>(containers.Select(c => c.net.ID));

			for (int i = Quarries.Count - 1; i >= 0; i--)
			{
				var q = Quarries[i];
				if (q.EntityIds.Any(id => containerIds.Contains(id)))
				{
					// Quarry already exists.// There's nothing to do here.Quarries.RemoveAt(i);
					SaveQuarries();
					player.ChatMessage("Quarry Removed!");
					return;
				}
			}

			var quarry = new Quarry(hitEntity.net.ID, containers.Select(c => c.net.ID).ToList());
			Quarries.Add(quarry);
			SaveQuarries();

#if DEBUG
			player.ChatMessage("Quarry Created! ID: " + quarry.Id + ", Entities: " + string.Join(", ", quarry.EntityIds.Select(i => i.ToString()).ToArray()));
#else
			player.ChatMessage("Quarry Created!");
#endif
		}

		private bool HasValidQuarryConstruction(Vector3 position, out List<BaseEntity> storageContainers, out bool isNearBuilding)
		{
			isNearBuilding = false;
			storageContainers = new List<BaseEntity>();
			var hits = Physics.OverlapSphere(position, 2f);
			var collisions = new List<Collider>();
			foreach (var hit in hits)
			{
				if (collisions.Contains(hit))
				{
					continue;
				}

				collisions.Add(hit);

				var storage = hit.GetComponentInParent<BaseEntity>();

				if (storage == null)
				{
					continue;
				}

				if (storageContainers.Contains(storage))
				{
					continue;
				}

				// Make sure we're not building on a...building
				// We can only quarry into the ground.(This makes quarries a tiny bit harder to protect)
				if (storage.GetComponent<BuildingBlock>() != null)
				{
					isNearBuilding = true;
					return false;
				}

				if (hit.GetComponentInParent<BasePlayer>() == null)
				{
					var prefab = storage.LookupShortPrefabName();
					// Matches both small and large boxes!
					// TODO: Make this check for something other than a 3x3 of boxes.// Maybe something cooler looking? Not sure what yet.if (prefab.EndsWith("woodbox_deployed"))
					{
						storageContainers.Add(storage);
					}
				}
			}

			return storageContainers.Count == 9;
		}

		#endregion
	}
}

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