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

FREE RectZones : 0.1.0 0.1.0

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

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

using UnityEngine;

using Newtonsoft.Json;

/*
	TODO:
			- Make showing a zone better
			- Fix "nobuildex"
			- add deployables protection
			- what to do with ddraw?
*/

/* --------------------------------------------------------------------- */
/* --- Don't edit anything here if you don't know what you are doing --- */
/* --------------------------------------------------------------------- */

namespace Oxide.Plugins
{
	[Info("RectZones", "deer_SWAG", "0.1.0", ResourceId = 2029)]
	[Description("Creates polygonal zones")]
	public class RectZones : RustPlugin
	{
		#region Variables

		const int MaxPoints = 254;
		const int MinPoints = 6;
		const string PluginPermission = "rectzones.use";
		const string GameObjectPrefix = "rzone-";

		#endregion

		#region Data Classes

		class PluginData
		{
			[JsonProperty("zones")]
			public HashSet<ZoneDefinition> Zones = new HashSet<ZoneDefinition>();
		}

		class ZoneDefinition
		{
			[JsonProperty("id")]
			public string Id = string.Empty;
			[JsonProperty("n")]
			public string Name;
			[JsonProperty("v")]
			public List<JVector3> Vertices = new List<JVector3>();
			[JsonProperty("o")]
			public Dictionary<string, string> Options = new Dictionary<string, string>();
		}

		#endregion

		PluginData data;
		HashSet<GameObject> currentZones = new HashSet<GameObject>();

		class TemporaryStorage
		{
			public BasePlayer Player;
			public ZoneDefinition Zone;
			public Timer Timer;
			public bool Fixed;
			public float Height;
		}

		bool isEditing;
		List<TemporaryStorage> tempPlayers = new List<TemporaryStorage>();

		Dictionary<string, string> availableOptions = new Dictionary<string, string>()
		{
			{ "entermsg", "Shows message when a player enters a zone" },
			{ "exitmsg", "Shows message when a player exits a zone" },
			{ "nobuild", "Players can't build in zone" },
			//{ "nobuildex", "Players can't build in zone.All buildings in a zone will be demolished" },
			{ "nostability", "Removes stability from buildings" },
			{ "nodestroy", "Players will be unable to destroy buildings and deployables" },
			{ "nopvp", "Players won't get hurt by another player" }
		};

		protected override void LoadDefaultMessages()
		{
			lang.RegisterMessages(new Dictionary<string, string>()
			{
				{ "HelpText", "Rect Zones:\n/rect add <height> [fixed] [name]\n/rect finish\n/rect undo\n/rect remove <id/name>\n/rect list\n/rect options\n/rect show [zone id]\n/rect clear" },
				{ "AlreadyEditing", "You are editing a zone.Type /rect finish to finish editing" },
				{ "AddHelp", "Now you can start adding points by pressing \"USE\" button (default is \"E\").They will be added where your crosshair is pointing.To add options type /options <name> = [value].To finish type /rect finish" },
				{ "Done", "Zone <color=#ffff00ff>{name}</color> with id <color=#ffff00ff>{id}</color> was added" },
				{ "DonePointsCount", "Points count should be more than 2 and less than 128" },
				{ "RemoveHelp", "To remove a zone type /rect remove <id/name>" },
				{ "Removed", "Zone was removed" },
				{ "ZoneNotFound", "Zone was not found" },
				{ "Empty", "Empty.To add a zone type /rect add <height> [fixed]" },
				{ "OptionsHelp", "/rect options <zoneID>" },
				{ "NoOptions", "This zone has no options" },
				{ "Cleared", "All zones were removed" },
				{ "ShowEmpty", "Nothing to show" },
				{ "CurrentZone", "Currently you are in zone with ID {id}" },
				{ "CurrentZoneNoZone", "You are not in any zone" },
				{ "InvalidAddCommand", "/rect add <height> [fixed] [name]" },
				{ "HeightMustBeNumber", "Argument \"height\" must be a number.If you want to use floating point number then write it in the quotes" },
				{ "UndoComplete", "Last point was removed" },
				{ "List", "Zones:\n" }
			}, this);
		}

		Commander cmdr;

		void Init()
		{
			LoadData();
			permission.RegisterPermission(PluginPermission, this);

			cmdr = new Commander(/*PlayerHasPermission*/);

			cmdr.Add(null, null, (player, args) =>
			{
				player.ChatMessage(Lang("HelpText", player));
			});

			cmdr.Add("add", null, (player, args) =>
			{
				if (CheckIsEditing(player) != null)
				{
					player.ChatMessage(Lang("AlreadyEditing", player));
					return;
				}

				if (args["height"].Value == null)
				{
					player.ChatMessage(Lang("InvalidAddCommand", player));
					return;
				}

				if (args["height"].IsInvalid)
				{
					player.ChatMessage(Lang("HeightMustBeNumber", player));
					return;
				}

				if (args.Count == 1)
				{
					CommandAdd(player, args["height"].Get<float>());
					return;
				}

				if (args["fixed"].String == "fixed")
				{
					if (args["name"].Value == null)
						CommandAdd(player, args["height"].Single, null, true);
					else
						CommandAdd(player, args["height"].Single, args["name"].String, true);
				}
				else
				{
					CommandAdd(player, args["height"].Single, args["fixed"].String);
				}

			}).AddParam("height", Commander.ParamType.Float).AddParam("fixed").AddParam("name");

			cmdr.Add("finish", null, (player, args) =>
			{
				TemporaryStorage storage = CheckIsEditing(player);

				if (storage != null)
				{
					if (storage.Zone.Vertices.Count < MinPoints || storage.Zone.Vertices.Count > MaxPoints)
					{
						player.ChatMessage(Lang("DonePointsCount", player));
						return;
					}

					CommandFinish(player);
					player.ChatMessage(Lang("Done", player).Replace("{id}", storage.Zone.Id).Replace("{name}", storage.Zone.Name));
				}
			});

			cmdr.Add("undo", null, (player, args) =>
			{
				TemporaryStorage storage = CheckIsEditing(player);

				if (storage != null)
				{
					if (storage.Zone.Vertices.Count != 0)
					{
						storage.Zone.Vertices.RemoveRange(storage.Zone.Vertices.Count - 2, 2);
						player.ChatMessage(Lang("UndoComplete", player));
					}
				}
			});

			cmdr.Add("list", null, (player, args) =>
			{
				if (data.Zones.Count == 0)
				{
					player.ChatMessage(Lang("Empty", player));
					return;
				}

				var result = new StringBuilder(Lang("List", player).Length);
				result.Append(Lang("List", player));

				foreach (ZoneDefinition zd in data.Zones)
					result.Append(zd.Id + (zd.Name != null ? (" (" + zd.Name + ")") : "") + ", ");
				
				player.ChatMessage(result.Remove(result.Length - 2, 2).ToString());
			});

			cmdr.Add("current", null, (player, args) =>
			{
				RectZone zone = GetCurrentZoneForPlayer(player);

				if (zone != null)
					player.ChatMessage(Lang("CurrentZone", player).Replace("{id}", zone.Definition.Id));
				else
					player.ChatMessage(Lang("CurrentZoneNoZone", player));
			});

			cmdr.Add("clear", null, (player, args) =>
			{
				foreach (GameObject zone in currentZones)
					GameObject.Destroy(zone);

				currentZones.Clear();
				data.Zones.Clear();

				player.ChatMessage(Lang("Cleared", player));
			});

			cmdr.Add("show", null, (player, args) => // TODO show by name
			{
				if (args["id"].Value != null)
				{
					if (args["id"].String.Equals("current", StringComparison.CurrentCultureIgnoreCase))
					{
						RectZone zone = GetCurrentZoneForPlayer(player);
						zone.ShowZone(player, 10f);
					}
					else
					{
						var zone = currentZones.First((z) => z.GetComponent<RectZone>().Definition.Id.Equals(args["id"].String));

						if (zone != null)
							zone.GetComponent<RectZone>().ShowZone(player, 10f);
						else
							player.ChatMessage(Lang("ZoneNotFound", player));						
					}
				}
				else
				{
					if (currentZones.Count == 0)
					{
						player.ChatMessage(Lang("ShowEmpty", player));
						return;
					}

					foreach (GameObject zone in currentZones)
						zone.GetComponent<RectZone>().ShowZone(player, 10f);
				}

			}).AddParam("id");

			cmdr.Add("remove", null, (player, args) =>
			{
				if (CheckIsEditing(player) != null)
				{
					player.ChatMessage(Lang("AlreadyEditing", player));
					return;
				}

				if (args["nameOrId"].Value != null)
				{
					if (IsDigitsOnly(args["nameOrId"].String))
					{
						int removed = data.Zones.RemoveWhere(x => x.Id == args["nameOrId"].String);

						if (removed <= 0)
						{
							player.ChatMessage(Lang("ZoneNotFound", player));
							return;
						}

						currentZones.RemoveWhere((GameObject go) =>
						{
							RectZone rz = go.GetComponent<RectZone>();

							if (rz.Definition.Id == args["nameOrId"].String)
							{
								GameObject.Destroy(go);
								return true;
							}

							return false;
						});

						player.ChatMessage(Lang("Removed", player));
					}
					else
					{
						int removed = data.Zones.RemoveWhere((ZoneDefinition x) =>
						{
							if (x.Name == null)
								return false;

							return x.Name.Equals(args["nameOrId"].String, StringComparison.CurrentCultureIgnoreCase);
						});

						if (removed <= 0)
						{
							player.ChatMessage(Lang("ZoneNotFound", player));
							return;
						}

						currentZones.RemoveWhere((GameObject go) =>
						{
							RectZone rz = go.GetComponent<RectZone>();

							if (rz.Definition.Name.Equals(args["nameOrId"].String, StringComparison.CurrentCultureIgnoreCase))
							{
								GameObject.Destroy(go);
								return true;
							}

							return false;
						});

						player.ChatMessage(Lang("Removed", player));
					}
				}
				else
				{
					player.ChatMessage(Lang("RemoveHelp", player));
				}

			}).AddParam("nameOrId");

			cmdr.Add("options", null, (player, args) =>
			{
				TemporaryStorage storage = CheckIsEditing(player);

				if (storage == null)
				{
					if (args["command"].Value != null)
					{
						if (IsDigitsOnly(args["command"].String))
						{
							ZoneDefinition definition = null;

							foreach (ZoneDefinition d in data.Zones)
							{
								if (d.Id == args["command"].String)
								{
									definition = d;
									break;
								}
							}

							if (definition == null)
							{
								player.ChatMessage(Lang("ZoneNotFound", player));
								return;
							}

							if (definition.Options.Count == 0)
							{
								player.ChatMessage(Lang("NoOptions", player));
								return;
							}

							string result = string.Empty;
							foreach (KeyValuePair<string, string> option in definition.Options)
							{
								result += option.Key + (option.Value != null ? (" = " + option.Value) : "") + ", ";
							}

							player.ChatMessage(result.Substring(0, result.Length - 2));
						}
						else
						{
							player.ChatMessage(Lang("OptionsHelp", player));
						}
					}
					else
					{
						string result = string.Empty;

						foreach (KeyValuePair<string, string> option in availableOptions)
						{
							result += "<color=#ffa500ff>" + option.Key + "</color> - " + (option.Value ?? "No description") + "\n";
						}

						player.ChatMessage(result);
					}
				}
				else
				{
					if (args["command"].Value != null)
					{
						if (args["command"].String == "list")
						{
							string result = string.Empty;

							foreach (KeyValuePair<string, string> option in availableOptions)
							{
								result += "<color=#ffa500ff>" + option.Key + "</color> - " + (option.Value ?? "") + "\n";
							}

							player.ChatMessage(result);

							return;
						}

						string[] opts = args["command"].String.Split(' ');

						for (int i = 1; i < opts.Length; i++)
						{
							string[] option = opts[i].Split(new char[] { '=' }, 2);

							storage.Zone.Options.Add(option[0], (option.Length > 1 ? option[1] : null));
						}
					}
					else
					{
						if (storage.Zone.Options.Count != 0)
						{
							string result = string.Empty;
							foreach (KeyValuePair<string, string> option in storage.Zone.Options)
							{
								result += option.Key + " = " + option.Value + ", \n";
							}

							player.ChatMessage(result.Substring(0, result.Length - 2));
						}
						else
						{
							player.ChatMessage(Lang("NoOptions", player));
						}
					}
				}
			}).AddParam("command", Commander.ParamType.String, true);
		}

		void Unload()
		{
			foreach(GameObject zone in currentZones)
				GameObject.Destroy(zone);

			currentZones.Clear();
		}

		void OnServerInitialized()
		{
			foreach (ZoneDefinition definition in data.Zones)
				CreateZoneByDefinition(definition);

			Puts("{0} zones were created", data.Zones.Count);
		}

		void OnServerSave()
		{
			SaveData();
		}

		[ChatCommand("rect")]
		void CmdChat(BasePlayer player, string command, string[] args) => cmdr.Run(player, args);

		#region Point Addition

		void OnPlayerDisconnected(BasePlayer player, string reason)
		{
			foreach(GameObject zone in currentZones)
			{
				RectZone zoneComponent = zone.GetComponent<RectZone>();
				zoneComponent.Players.Remove(player);
			}

			if (isEditing)
				tempPlayers.RemoveAll(x => x.Player.userID == player.userID);
		}

		void OnPlayerInput(BasePlayer player, InputState input)
		{
			if (!isEditing)
				return;

			if (!input.WasJustPressed(BUTTON.USE))
				return;
	
			for (int i = 0; i < tempPlayers.Count; i++)
			{
				TemporaryStorage storage = tempPlayers[i];

				if (storage.Player.userID == player.userID)
				{
					Ray ray = player.eyes.HeadRay();
					RaycastHit hit;

					if(Physics.Raycast(ray, out hit, 10))
					{
						JVector3 bottomPoint = new JVector3(hit.point);
						JVector3 topPoint = storage.Fixed ? new JVector3(hit.point.x, storage.Height, hit.point.z) : new JVector3(hit.point.x, hit.point.y + storage.Height, hit.point.z);

						storage.Zone.Vertices.Add(bottomPoint);
						storage.Zone.Vertices.Add(topPoint);

						ShowPoint(player, bottomPoint.ToUnity(), topPoint.ToUnity(), 2f);
					}
				}
			}
		}

		#endregion Point Addition

		#region Commands

		TemporaryStorage CheckIsEditing(BasePlayer player)
		{
			if (tempPlayers.Count == 0)
				return null;

			return tempPlayers.Find(x => x.Player.userID == player.userID);
		}

		void CommandAdd(BasePlayer player, float height, string name = null, bool fixedHeight = false)
		{
			player.ChatMessage(Lang("AddHelp", player));

			isEditing = true;

			TemporaryStorage storage = new TemporaryStorage();
			storage.Player = player;
			storage.Zone = new ZoneDefinition
			{
				Id = GenerateId()
			};
			storage.Height = height;
			storage.Fixed = fixedHeight;
			storage.Zone.Name = name;

			storage.Timer = timer.Repeat(5f, 0, () =>
			{
				JVector3 prevVector = null;

				foreach(JVector3 vector in storage.Zone.Vertices)
				{
					if(prevVector == null)
					{
						prevVector = vector;
						continue;
					}

					ShowPoint(player, prevVector.ToUnity(), vector.ToUnity(), 5.5f);

					prevVector = null;
				}
			});

			tempPlayers.Add(storage);
		}

		void CommandFinish(BasePlayer player)
		{
			tempPlayers.RemoveAll((TemporaryStorage storage) =>
			{
				if(storage.Player.userID == player.userID)
				{
					storage.Timer.Destroy();
					storage.Timer = null;
					storage.Player = null;

					data.Zones.Add(storage.Zone);

					CreateZoneByDefinition(storage.Zone);

					return true;
				}

				return false;
			});

			SaveData();

			if(tempPlayers.Count == 0)
				isEditing = false;
		}

		void CreateZoneByDefinition(ZoneDefinition definition)
		{
			GameObject zoneObject = new GameObject(GameObjectPrefix + definition.Id);
			RectZone zoneComponent = zoneObject.AddComponent<RectZone>();
			zoneComponent.SetZone(definition);
			currentZones.Add(zoneObject);
		}

		RectZone GetCurrentZoneForPlayer(BasePlayer player)
		{
			foreach (GameObject zone in currentZones)
			{
				RectZone zoneComponent = zone.GetComponent<RectZone>();

				if (zoneComponent.Players.Contains(player))
				{
					return zoneComponent;
				}
			}

			return null;
		}

		#endregion Commands

		// For HelpText plugin

		void SendHelpText(BasePlayer player)
		{
			if(PlayerHasPermission(player, PluginPermission))
				player.ChatMessage(Lang("HelpText", player));
		}

		#region For Built-in Options

		void OnEntityBuilt(Planner plan, GameObject go)
		{
			foreach (GameObject zone in currentZones)
			{
				RectZone zoneComponent = zone.GetComponent<RectZone>();

				if (zoneComponent.Players.Count == 0)
					continue;

				if (zoneComponent.Definition.Options.ContainsKey("nobuild"))
				{
					if (zoneComponent.GetComponent<Collider>().bounds.Contains(go.transform.position))
					{
						go.GetComponentInParent<BaseCombatEntity>().Kill(BaseNetworkable.DestroyMode.Gib);

						if (zoneComponent.Definition.Options["nobuild"] != null)
							plan.GetOwnerPlayer().ChatMessage(zoneComponent.Definition.Options["nobuild"]);

						break;
					}
				}
				else if(zoneComponent.Definition.Options.ContainsKey("nobuildex"))
				{
					if (zoneComponent.GetComponent<Collider>().bounds.Contains(go.transform.position))
					{
						go.GetComponentInParent<BaseCombatEntity>().Kill(BaseNetworkable.DestroyMode.Gib);

						if (zoneComponent.Definition.Options["nobuildex"] != null)
							plan.GetOwnerPlayer().ChatMessage(zoneComponent.Definition.Options["nobuildex"]);

						break;
					}
				}
			}
		}

		void OnEntitySpawned(BaseNetworkable entity)
		{
			if (!(entity is BuildingBlock))
				return;

			BuildingBlock block = (BuildingBlock)entity;

			foreach(GameObject zone in currentZones)
			{
				RectZone zoneComponent = zone.GetComponent<RectZone>();

				if (zoneComponent.Definition.Options.ContainsKey("nostability"))
				{
					if (zoneComponent.GetComponent<Collider>().bounds.Contains(block.transform.position))
					{
						block.grounded = true;
					}
				}
			}
		}

		void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitinfo)
		{
			bool blockDamage = false;

			foreach (GameObject zone in currentZones)
			{
				RectZone zoneComponent = zone.GetComponent<RectZone>();

				if((entity is BuildingBlock && zoneComponent.Definition.Options.ContainsKey("nodestroy")) ||
				   (entity is BasePlayer && (hitinfo.Initiator is BasePlayer || hitinfo.Initiator is FireBall) && zoneComponent.Definition.Options.ContainsKey("nopvp")))
				{
					if(zoneComponent.GetComponent<Collider>().bounds.Contains(entity.transform.position))
					{
						blockDamage = true;
						break;
					}
				}
			}

			if(blockDamage)
			{
				hitinfo.damageTypes = new Rust.DamageTypeList();
				hitinfo.DoHitEffects = false;
				hitinfo.HitMaterial = 0;
			}
		}

		#endregion Options

		#region Hooks For Other Plugins

		[HookMethod("RegisterOption")]
		public bool RegisterOption(string name, string description = null)
		{
			if(availableOptions.Count > 0)
			{
				if (availableOptions.ContainsKey(name))
				{
					PrintWarning("There is already an option with name \"" + name + "\"");
					return false;
				}
			}

			availableOptions.Add(name, description);

			return true;
		}

		[HookMethod("UnregisterOption")]
		public void UnregisterOption(string name)
		{
			availableOptions.Remove(name);
		}

		// Hooks
		// void OnEnterZone(string id, BasePlayer player)
		// void OnExitZone(string id, BasePlayer player)
		// void OnEnterZoneWithOptions(string id, BasePlayer player, Dictionary<string, string> options)
		// void OnExitZoneWithOptions(string id, BasePlayer player, Dictionary<string, string> options)

		#endregion Hooks

		#region Utils

		static void ShowPoint(BasePlayer player, Vector3 from, Vector3 to, float duration = 5f)
		{
			DrawDebugLine(player, from, to, 4.8f);
			DrawDebugSphere(player, from, 0.1f, 4.8f);
			DrawDebugSphere(player, to, 0.1f, 4.8f);
		}

		void LoadData()
		{
			data = Interface.GetMod().DataFileSystem.ReadObject<PluginData>(Title);
		}

		void SaveData()
		{
			Interface.GetMod().DataFileSystem.WriteObject(Title, data);
		}

		static void DrawDebugLine(BasePlayer player, Vector3 from, Vector3 to, float duration = 1f)
		{
			player.SendConsoleCommand("ddraw.line", duration, Color.yellow, from, to);
		}

		static void DrawDebugSphere(BasePlayer player, Vector3 position, float radius = 0.5f, float duration = 1f)
		{
			player.SendConsoleCommand("ddraw.sphere", duration, Color.green, position, radius);
		}

		string GenerateId()
		{
			byte[] bytes = Guid.NewGuid().ToByteArray();
			int number = Math.Abs(BitConverter.ToInt32(bytes, 0));
			return number.ToString();
		}

		string Lang(string key, BasePlayer player = null)
		{
			return lang.GetMessage(key, this, player?.UserIDString);
		}

		bool IsDigitsOnly(string str)
		{
			foreach (char c in str)
				if (!char.IsDigit(c))
					return false;
			return true;
		}

		bool PlayerHasPermission(BasePlayer player, string permissionName)
		{
			return player.IsAdmin || permission.UserHasPermission(player.UserIDString, permissionName);
		}

		#endregion Utils

		#region Helpers

		/// <summary>
		/// Helper class for chat and console commands
		/// </summary>
		class Commander
		{
			#region Definitions

			public delegate bool PermissionCheck(BasePlayer player, string permission);

			/// <summary>Type of parameter for auto convertion</summary>
			public enum ParamType
			{
				/// <summary>Use this if you want a raw string</summary>
				String,
				Int, Float, Bool,
				/// <summary>Returns a BasePlayer object</summary>
				Player
			}

			public struct Param
			{
				public string Name { get; set; }
				public ParamType Type { get; set; }
				public bool Greedy { get; set; }
			}

			public class ParamValue
			{
				/// <summary>Raw value</summary>
				public object Value { get; set; }
				/// <summary>If argument wasn't parse properly</summary>
				public bool IsInvalid { get; set; }

				public string String => Get<string>();
				public int Integer => Get<int>();
				public float Single => Get<float>();
				public BasePlayer Player => Get<BasePlayer>();

				/// <exception cref="InvalidCastException"></exception>
				public T Get<T>()
				{
					return (T)Value;
				}
			}

			public class ValueCollection : Dictionary<string, ParamValue>
			{
				public new ParamValue this[string key]
				{
					get
					{
						ParamValue value;
						this.TryGetValue(key, out value);
						return value;
					}
				}
			}

			public class BaseCommand
			{
				public string Name { get; set; }
				public string Permission { get; set; }

				public virtual void Run(BasePlayer player, string[] args, PermissionCheck check) { }
			}

			public class Command : BaseCommand
			{
				public List<Param> Params => new List<Param>();
				public Action<BasePlayer, ValueCollection> Callback { get; set; }

				public Command AddParam(string name, ParamType type = ParamType.String, bool greedy = false)
				{
					if (name == null)
						throw new NullReferenceException("Name of the parameter can't be null");
					if (greedy && type != ParamType.String)
						throw new InvalidOperationException("Only string-type parameters can be greedy");

					Params.Add(new Param
					{
						Name = name,
						Type = type,
						Greedy = greedy
					});

					return this;
				}

				public override void Run(BasePlayer player, string[] args, PermissionCheck check)
				{
					if (check != null && !check(player, Permission))
						return;

					var collection = new ValueCollection();

					if (Params.Count > 0)
						CheckParams(args, ref collection);

					Callback?.Invoke(player, collection);
				}

				private void CheckParams(string[] args, ref ValueCollection collection)
				{
					for (int i = 0; i < args.Length; i++)
					{
						if (i >= Params.Count)
							break;

						var arg = args[i];
						var param = Params[i];

						if (param.Greedy)
						{
							collection.Add(param.Name, new ParamValue { Value = string.Join(" ", args, i, args.Length - i) });
							break;
						}

						object value;
						bool result = CheckAndConvert(arg, param.Type, out value);
						collection.Add(param.Name, new ParamValue { Value = value, IsInvalid = !result });
					}
				}

				private bool CheckAndConvert(string arg, ParamType type, out object result)
				{
					switch (type)
					{
						case ParamType.String:
							result = arg;
							return true;
						case ParamType.Int:
							{
								int ret;
								if (int.TryParse(arg, out ret))
								{
									result = ret;
									return true;
								}
								result = ret;
								return false;
							}
						case ParamType.Float:
							{
								float ret;
								if (float.TryParse(arg, out ret))
								{
									result = ret;
									return true;
								}
								result = ret;
								return false;
							}
						case ParamType.Bool:
							{
								bool ret;
								if (ParseBool(arg, out ret))
								{
									result = ret;
									return true;
								}
								result = ret;
								return false;
							}
						case ParamType.Player:
							result = BasePlayer.Find(arg);
							return true;
						default:
							result = null;
							return false;
					}
				}
			}

			public class CommandGroup : BaseCommand
			{
				private List<BaseCommand> _children = new List<BaseCommand>();
				private Command _empty;

				public Command Add(string name, string permission, Action<BasePlayer, ValueCollection> callback)
				{
					var cmd = new Command
					{
						Name = name,
						Permission = permission,
						Callback = callback
					};

					if (name == null)
						return _empty = cmd;

					_children.Add(cmd);
					return cmd;
				}

				public CommandGroup AddGroup(string name, string permission = null)
				{
					var group = new CommandGroup
					{
						Name = name,
						Permission = permission
					};

					_children.Add(group);
					return group;
				}

				public override void Run(BasePlayer player, string[] args, PermissionCheck check)
				{
					if (check != null && !check(player, Permission))
						return;

					Commander.Run(_children, _empty, player, args);
				}
			}

			#endregion Definitions

			private List<BaseCommand> _commands = new List<BaseCommand>();
			private Command _empty;
			private PermissionCheck _permCheck;

			public Commander(PermissionCheck permissionCheck = null)
			{
				_permCheck = permissionCheck;
			}

			public Command Add(string name, string permission, Action<BasePlayer, ValueCollection> callback)
			{
				var cmd = new Command
				{
					Name = name,
					Permission = permission,
					Callback = callback
				};

				if (name == null || name.Length == 0)
					return _empty = cmd;

				_commands.Add(cmd);
				return cmd;
			}

			public CommandGroup AddGroup(string name, string permission = null)
			{
				var group = new CommandGroup
				{
					Name = name,
					Permission = permission
				};

				_commands.Add(group);
				return group;
			}

			static protected void Run(List<BaseCommand> cmds, BaseCommand empty, BasePlayer player, string[] args, PermissionCheck check = null)
			{
				if (args == null || args.Length == 0)
				{
					empty?.Run(player, args, check);
					return;
				}

				cmds.Find((cmd) => cmd.Name.Equals(args[0], StringComparison.CurrentCultureIgnoreCase))
				   ?.Run(player, args.Skip(1).ToArray(), check);
			}

			public void Run(BasePlayer player, string[] args)
			{
				Run(_commands, _empty, player, args, _permCheck);
			}

			#region Custom Boolean Parser

			private static string[] _trueBoolValues = { "true", "yes", "on", "enable", "1" };
			private static string[] _falseBoolValues = { "false", "no", "off", "disable", "0" };

			protected static bool ParseBool(string input, out bool result)
			{
				for (int i = 0; i < _trueBoolValues.Length; i++)
				{
					if (input.Equals(_trueBoolValues[i], StringComparison.CurrentCultureIgnoreCase))
					{
						return result = true;
					}
					else if (input.Equals(_falseBoolValues[i], StringComparison.CurrentCultureIgnoreCase))
					{
						result = false;
						return true;
					}
				}

				return result = false;
			}

			#endregion Custom Boolean Parser
		}

		class JVector3
		{
			public float x;
			public float y;
			public float z;

			public JVector3(float x, float y, float z)
			{
				this.x = x;
				this.y = y;
				this.z = z;
			}

			public JVector3(Vector3 vector)
			{
				x = vector.x;
				y = vector.y;
				z = vector.z;
			}

			public Vector3 ToUnity()
			{
				return new Vector3(x, y, z);
			}
		}

		#endregion Helpers

		class RectZone : MonoBehaviour
		{
			public ZoneDefinition Definition { get; private set; }
			public HashSet<BasePlayer> Players { get; private set; } = new HashSet<BasePlayer>();

			private MeshCollider collider;

			void Awake()
			{
				gameObject.layer = (int)Rust.Layer.Reserved1;

				Rigidbody rigidbody = gameObject.AddComponent<Rigidbody>();
				rigidbody.isKinematic = true;
				rigidbody.useGravity = false;
				rigidbody.detectCollisions = true;

				collider = gameObject.AddComponent<MeshCollider>();
				collider.convex = true;
				collider.isTrigger = true;
			}

			public void SetZone(ZoneDefinition definition)
			{
				Definition = definition;
				MakeMesh(definition.Vertices);
			}

			public void ShowZone(BasePlayer player, float duration)
			{
				Vector3? prevVertex = null;

				foreach (Vector3 vertex in collider.sharedMesh.vertices)
				{
					if (prevVertex == null)
					{
						prevVertex = vertex;
						continue;
					}

					ShowPoint(player, prevVertex.Value, vertex, duration);

					prevVertex = null;
				}
			}

			void MakeMesh(List<JVector3> vertices)
			{
				Mesh mesh = new Mesh();

				List<Vector3> tempVertices = new List<Vector3>();
				List<int> tempIndices = new List<int>();

				foreach(JVector3 vertex in vertices)
					tempVertices.Add(vertex.ToUnity());

				// Side
				tempIndices.Add(0);
				tempIndices.Add(1);

				for (int i = 2; i < tempVertices.Count; i++)
				{
					tempIndices.Add(i);

					if (tempIndices.Count % 3 == 0)
					{
						tempIndices.Add(i - 1);
						tempIndices.Add(i + 1);
						tempIndices.Add(i);
						tempIndices.Add(i);
					}
				}

				tempIndices.Add(0);
				tempIndices.Add(tempVertices.Count - 1);
				tempIndices.Add(1);
				tempIndices.Add(0);

				mesh.SetVertices(tempVertices);
				mesh.SetIndices(tempIndices.ToArray(), MeshTopology.Triangles, 0);

				mesh.RecalculateBounds();
				mesh.RecalculateNormals();

				collider.sharedMesh = mesh;
			}
			
			void OnTriggerEnter(Collider collider)
			{
				BasePlayer player = collider.GetComponentInParent<BasePlayer>();

				if (player != null)
				{
					Players.Add(player);

					if (Definition.Options.ContainsKey("entermsg") && Definition.Options["entermsg"] != null)
						player.ChatMessage(Definition.Options["entermsg"]);

					Interface.Oxide.CallHook("OnEnterZone", Definition.Id, player);

					if(Definition.Options.Count != 0)
						Interface.Oxide.CallHook("OnEnterZoneWithOptions", Definition.Id, player, Definition.Options);
				}
				else
				{
					/*if (Definition.Options.ContainsKey("nobuildex"))
					{
						MeshColliderBatch batch = collider.GetComponent<MeshColliderBatch>();

						if(batch != null)
						{
							FieldInfo info = batch.GetType().GetField("instances", BindingFlags.NonPublic | BindingFlags.Instance);
							var batchColliders = (ListDictionary<Component, ColliderCombineInstance>)info.GetValue(batch);

							List<ColliderCombineInstance> batchCollidersList = batchColliders.Values;

							for(int i = 0; i < batchCollidersList.Count; i++)
							{
								ColliderCombineInstance instance = batchCollidersList[i];

								if(this.collider.bounds.Intersects(instance.bounds.ToBounds()))
								{
									instance.collider.GetComponentInParent<BaseCombatEntity>()?.Kill(BaseNetworkable.DestroyMode.Gib);
								}
							}
						}
					}*/
				}
			}

			void OnTriggerExit(Collider collider)
			{
				BasePlayer player = collider.GetComponentInParent<BasePlayer>();

				if (player != null)
				{
					Players.Remove(player);

					if (Definition.Options.ContainsKey("exitmsg") && Definition.Options["exitmsg"] != null)
						player.ChatMessage(Definition.Options["exitmsg"]);

					Interface.Oxide.CallHook("OnExitZone", Definition.Id, player);

					if(Definition.Options.Count != 0)
						Interface.Oxide.CallHook("OnExitZoneWithOptions", Definition.Id, player, Definition.Options);
				}
			}
		}
	}
}

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