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

FREE NavMeshPainter : 1.0 1.0

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
// Reference: RustLib
using Oxide.Core;
using RustLib.AI;
using RustLib.Extensions;
using RustLib.Misc;
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using GameLib.Threading;
using System.Diagnostics;
using System.IO;

namespace Oxide.Plugins
{
	[Info("NavMeshPainter", "Sulley", 1.0)]
	[Description("NavMeshPainter")]
	public class NavMeshPainter : RustPlugin
	{
		// TerrainMeta.HeightMap.GetHeight(Vector3);
		// TerrainMeta.Path.Monuments
		// https://i.gyazo.com/95ff6801b669aa226cab346fbe7dce7b.png

		private ThreadPool thread_pool = new ThreadPool();

		void OnTick()
		{
			thread_pool.ProcessCallbacks((object obj) => { Puts(obj.ToString()); });

			lock (debug_info)
				while (debug_info.Count > 0)
					Puts($"{debug_info.Dequeue()}");
		}

		void Unload() => thread_pool.Shutdown();

		private const int exponent = -1;
		private Dictionary<ulong, NavData> builders = new Dictionary<ulong, NavData>();
		private Dictionary<ulong, Mode> modes = new Dictionary<ulong, Mode>();
		private Dictionary<ulong, bool> is_on_ground = new Dictionary<ulong, bool>();
		private Queue<object> debug_info = new Queue<object>();

		[ConsoleCommand("nv_clear")]
		void ccmdClear(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			ulong steamid = args.Player().userID;
			builders[steamid] = new NavData(exponent);
		}

		private void DrawLine(BasePlayer player, float time, Vector3 first, Vector3 second)
		{
			player.SendConsoleCommand("ddraw.line", time, Color.blue, first, second);
		}

		[ConsoleCommand("nv_showpoint")]
		void ccmdShowPoint(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			BasePlayer player = args.Player();

			NavData builder = GetNavData(player);

			int point_id = Convert.ToInt32(args.Args[0]);

			Vector3 point = builder.GetPoint(point_id);

			Utilities.DrawAABB(player, point, new Vector3(1.0f, 1.0f, 1.0f), Color.black, 5.0f);
			Utilities.DrawText(player, point + new Vector3(0, 3, 0), point_id.ToString());
		}

		[ConsoleCommand("nv_testpath")]
		void ccmdTestPath(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			BasePlayer player = args.Player();

			NavData builder = GetNavData(player);

			int origin_id = Convert.ToInt32(args.Args[0]);
			int destination_id = Convert.ToInt32(args.Args[1]);

			List<Edge> edges = builder.GetPath(origin_id, destination_id, PathfindingOptions.Default());

			List<Vector3> points = new List<Vector3>();

			foreach (Edge edge in edges)
			{
				Vector3 point = builder.GetPoint(edge.j);
				points.Add(point);
			}

			foreach (Vector3 point in points)
				Utilities.DrawAABB(player, point, new Vector3(0.5f, 0.5f, 0.5f), Color.black, 5.0f);
		}

		[ConsoleCommand("nv_tws")]
		void ccmdTestWalkStraight(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			BasePlayer player = args.Player();

			NavData nav = GetNavData(player);

			int origin_id = Convert.ToInt32(args.Args[0]);
			int destination_id = Convert.ToInt32(args.Args[1]);

			Stopwatch sw = new Stopwatch();
			sw.Start();

			bool can_walk_straight = nav.CanWalkStraight(origin_id, destination_id, 1.0f, PathfindingOptions.Default(), (object s) => { });

			sw.Stop();
			player.ChatMessage($"can walk straight test: {can_walk_straight} in {sw.ElapsedMilliseconds} ms, {sw.ElapsedTicks} ticks TPM ({TimeSpan.TicksPerMillisecond})");
		}

		[ConsoleCommand("nv_tsp")]
		void ccmdTestSmoothPath(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			BasePlayer player = args.Player();

			NavData nav = GetNavData(player);

			int origin_id = Convert.ToInt32(args.Args[0]);
			int destination_id = Convert.ToInt32(args.Args[1]);
			int max_points = Convert.ToInt32(args.Args[2]);

			Stopwatch sw = new Stopwatch();
			sw.Start();

			List<Vector3> points = nav.GetSmoothedPath(origin_id, destination_id, 0.1f, PathfindingOptions.Default());

			sw.Stop();

			player.ChatMessage($"GetSmoothedPath test count({points.Count}) {sw.ElapsedMilliseconds} ms, {sw.ElapsedTicks} ticks");

			player.SendConsoleCommand($"echo {origin_id}, {destination_id}, {points.Count}");

			foreach (Vector3 point in points)
			{
				Utilities.DrawAABB(player, point, new Vector3(0.5f, 0.5f, 0.5f), Color.black, 5.0f);
			}

			for (int i = 0; i < points.Count - 1; i++)
			{
				Vector3 origin = points[i];
				Vector3 destination = points[i + 1];

				DrawLine(player, 5.0f, origin, destination);
			}
		}

		[ConsoleCommand("nv_save")]
		void ccmdSave(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			BasePlayer player = args.Player();

			NavData nav = GetNavData(player);

			string filename = args.Args[0];

			player.ChatMessage($"saving to: {filename}");

			Action job = () => { nav.Save(filename); };

			Action callback = () => { player.ChatMessage($"saved: {filename}"); };

			thread_pool.EnqueueJob(job, callback);
		}

		[ConsoleCommand("nv_load")]
		void ccmdLoad(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			BasePlayer player = args.Player();
			string filename = args.Args[0];

			player.ChatMessage($"loading nav file: {filename}");

			NavData nav = null;

			Action job = () => { nav = NavData.Load(filename); };
			Action callback = () =>
			{
				player.ChatMessage($"loaded nav file: {filename}");
				builders[player.userID] = nav;
			};

			thread_pool.EnqueueJob(job, callback);
		}

		[ConsoleCommand("nv_prune")]
		void ccmdPrune(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			BasePlayer player = args.Player();

			int prune_from = Convert.ToInt32(args.Args[0]);

			NavData current = GetNavData(player);

			NavData pruned = null;

			Action job = () =>
			{
				pruned = current.Prune(prune_from, (obj) =>
					{
					 lock (debug_info)
						 debug_info.Enqueue(obj);
				 });
			};

			Action callback = () =>
			{
				builders[player.userID] = pruned;
			};

			thread_pool.EnqueueJob(job, callback);
		}

		[ConsoleCommand("nv_showall")]
		void ccmdShowAll(ConsoleSystem.Arg args)
		{
			float max_draw_distance = 10.0f;

			BasePlayer player = args.Player();
			if (!player.IsAdmin)
				return;

			ulong steamid = args.Player().userID;

			NavData builder = GetNavData(args.Player());

			float time = 2.0f;

			if (modes.ContainsKey(player.userID) && modes[player.userID] == Mode.Scalpel)
				max_draw_distance = 5.0f;

			builder.DebugDrawInfo((Vector3 from, Vector3 to, int i_from, int i_to) =>
			{
				float distance = Vector3.Distance(from, player.transform.position);

				bool args_not_null = (args.Args != null);
				bool should_ignore_distance = (args_not_null && (args.Args.Contains("inf") || args.Args.Contains("infinite")));
				bool is_close_enough = (distance < max_draw_distance);

				if (!is_close_enough && !should_ignore_distance)
					return;

				DrawLine(player, time, from, to);

				if (args.Args != null && args.Args.Contains("text"))
				{
					Utilities.DrawText(player, from, $"{i_from}", time);
					Utilities.DrawText(player, to, $"{i_to}", time);
				}
			});
		}

		NavData GetNavData(BasePlayer player)
		{
			if (!builders.ContainsKey(player.userID))
				builders[player.userID] = new NavData(exponent);

			return builders[player.userID];
		}

		// want to make sure we were on ground last tick as well as this tick or points
		// will appear above where they are supposed to when players land
		bool IsOnGround(BasePlayer player)
		{
			if (!is_on_ground.ContainsKey(player.userID))
				is_on_ground[player.userID] = false;

			bool ret = (player.IsOnGround() && is_on_ground[player.userID]);
			is_on_ground[player.userID] = player.IsOnGround();

			return ret;
		}

		void PaintCircle(BasePlayer player, float radius, float density, Action<Vector3> output)
		{
			int multiple = (int)(radius / density);
			float distance = multiple * density;

			Vector3 center = player.transform.position;

			center.y += 1.0f;

			float x_min = center.x - distance;
			float z_min = center.z - distance;
			float x_max = center.x + distance;
			float z_max = center.z + distance;

			x_min = x_min.NearestMultipleOfNthPowerOf2(exponent);
			z_min = z_min.NearestMultipleOfNthPowerOf2(exponent);

			for (float x = x_min; x <= x_max; x += density)
			{
				for (float z = z_min; z <= z_max; z += density)
				{
					Vector3 current = new Vector3(x, center.y, z);
					distance = Vector3.Distance(current, player.transform.position);

					if (distance < radius)
					{
						//int layer_mask = 2162688;
						//int layer_mask = 1218652417;
						int layer_mask = 7;
						// 1218652417
						RaycastHit hit;
						Vector3 direction = (current - center).normalized;
						Vector3 origin = player.transform.position + new Vector3(0.0f, 1.5f, 0.0f);
						Physics.Raycast(origin, direction, out hit);
						float cast_distance = Vector3.Distance(hit.point, center);

						if (cast_distance > distance + 1.0f)
						{
							Physics.Raycast(current, Vector3.down, out hit, layer_mask);

							// for some reason unknown to me, unity's raycast often returns points which
							// are not *precisely* along the input ray, so we'll toss out the x and z but keep the y
							Vector3 output_point = new Vector3(x, hit.point.y, z);
							output(output_point);
						}
					}
				}
			}
		}

		private float radius = 3.75f;

		[ConsoleCommand("nv_eraseid")]
		void ccmdEraseID(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			BasePlayer player = args.Player();

			NavData builder = GetNavData(player);

			int point_id = Convert.ToInt32(args.Args[0]);

			player.ChatMessage($"Erasing: {point_id}");

			builder.Erase(point_id);
		}

		private enum Mode
		{
			None,
			Paint,
			Scalpel,
			ShowRaycast
		}

		[ConsoleCommand("nv_setmode")]
		void ccmdSetMode(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			BasePlayer player = args.Player();

			string input = args.Args[0];

			Mode new_mode = (Mode)Enum.Parse(typeof(Mode), input);

			modes[player.userID] = new_mode;

			player.SendDebugMessage($"Mode set to {new_mode}");
		}

		[ConsoleCommand("nv_setradius")]
		void ccmdSetRadius(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			BasePlayer player = args.Player();

			radius = Single.Parse(args.Args[0]);

			player.ChatMessage($"new radius: {radius}");
		}

		void OnPlayerTick(BasePlayer player)
		{
			if (!modes.ContainsKey(player.userID))
				return;

			Mode mode = modes[player.userID];

			if (mode == Mode.None)
				return;

			bool is_on_ground = IsOnGround(player);

			NavData builder = GetNavData(player);

			if (mode == Mode.Paint && is_on_ground)
			{
				PaintCircle(player, radius, builder.Density(), (Vector3 output) =>
				{
					Action<Vector3, Vector3, bool> visual_debug = (Vector3 from, Vector3 to, bool is_already_linked) =>
						 {
							  //DrawAABB(player, from + new Vector3(0, 1, 0), new Vector3(0.1f, 0.1f, 0.1f), Color.black, 0.1f);
							  //DrawLine(player, 0.1f, from, to);
						  };

					builder.AddWalkPoint(output, visual_debug);
				});
			}

			if (mode == Mode.ShowRaycast)
			{
				RaycastHit hit = GetForwardRaycastHit(player);
				Utilities.DrawAABB(player, hit.point, new Vector3(0.1f, 0.1f, 0.1f), Color.black, 0.1f);
			}

			if (mode == Mode.Scalpel)
			{
				RaycastHit hit = GetForwardRaycastHit(player);
				Vector3 hashed = hit.point;
				hashed.x = hashed.x.NearestMultipleOfNthPowerOf2(exponent);
				hashed.z = hashed.z.NearestMultipleOfNthPowerOf2(exponent);
				Utilities.DrawAABB(player, hashed, new Vector3(0.1f, 0.1f, 0.1f), Color.black, 0.1f);
			}
		}

		[ConsoleCommand("nv_erase")]
		void ccmdErase(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			BasePlayer player = args.Player();

			RaycastHit hit = GetForwardRaycastHit(player);
			Vector3 hashed = hit.point;
			hashed.x = hashed.x.NearestMultipleOfNthPowerOf2(exponent);
			hashed.z = hashed.z.NearestMultipleOfNthPowerOf2(exponent);

			player.ChatMessage($"Erasing: {hashed}");

			NavData data = GetNavData(player);

			float max_erase_height_difference = 1.0f;

			data.Erase(hashed, max_erase_height_difference);
		}

		[ConsoleCommand("nv_addpoint")]
		void ccmdAddPoint(ConsoleSystem.Arg args)
		{
			if (!args.Player().IsAdmin)
				return;

			BasePlayer player = args.Player();

			RaycastHit hit = GetForwardRaycastHit(player);
			Vector3 hashed = hit.point;
			hashed.x = hashed.x.NearestMultipleOfNthPowerOf2(exponent);
			hashed.z = hashed.z.NearestMultipleOfNthPowerOf2(exponent);

			player.ChatMessage($"Adding: {hashed}");

			NavData data = GetNavData(player);

			Action<Vector3, Vector3, bool> visual_debug = (Vector3 from, Vector3 to, bool is_already_linked) =>
			{
				Color draw_color = Color.blue;

				if (is_already_linked)
					draw_color = Color.white;

				player.SendConsoleCommand("ddraw.line", 3.0f, Color.blue, from, to);
			};

			data.AddWalkPoint(hashed, visual_debug);
		}

		RaycastHit GetForwardRaycastHit(BasePlayer player, int layer_mask = 7)
		{
			RaycastHit hit;
			Vector3 start = player.eyes.position;
			Vector3 direction = player.eyes.HeadForward();
			Physics.Raycast(start, direction, out hit, layer_mask);
			return hit;
		}
	}
}

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