using Unity.Netcode; using UnityEditor; using UnityEngine; using UnityEngine.AI; using Northbound; namespace Northbound.Editor { public class TemplateCreator { private const string TEMPLATE_BASE_PATH = "Assets/Data/Templates"; [MenuItem("Tools/Data/Create Monster Template")] public static void CreateMonsterTemplate() { CreateTemplate("Monster", SetupMonsterComponents); } [MenuItem("Tools/Data/Create Tower Template")] public static void CreateTowerTemplate() { CreateTemplate("Tower", SetupTowerComponents); } [MenuItem("Tools/Data/Create Player Template")] public static void CreatePlayerTemplate() { CreateTemplate("Player", SetupPlayerComponents); } private static void CreateTemplate(string typeName, System.Action setupComponents) { if (!AssetDatabase.IsValidFolder(TEMPLATE_BASE_PATH)) { System.IO.Directory.CreateDirectory(Application.dataPath + "/Data/Templates"); AssetDatabase.Refresh(); } string templateName = $"{typeName}Template"; string templatePath = $"{TEMPLATE_BASE_PATH}/{templateName}.prefab"; GameObject templateGO = new GameObject(templateName); setupComponents(templateGO); PrefabUtility.SaveAsPrefabAsset(templateGO, templatePath); GameObject.DestroyImmediate(templateGO); Debug.Log($"[TemplateCreator] Created template: {templatePath}"); AssetDatabase.Refresh(); Selection.activeObject = AssetDatabase.LoadAssetAtPath(templatePath); } private static void SetupMonsterComponents(GameObject go) { Transform t = go.transform; t.localPosition = Vector3.zero; t.localRotation = Quaternion.identity; t.localScale = Vector3.one; if (go.GetComponent() == null) { CapsuleCollider collider = go.AddComponent(); collider.isTrigger = false; collider.radius = 0.5f; collider.height = 2f; collider.direction = 1; collider.center = Vector3.zero; } if (go.GetComponent() == null) { Animator animator = go.AddComponent(); animator.runtimeAnimatorController = null; animator.avatar = null; animator.applyRootMotion = false; animator.updateMode = AnimatorUpdateMode.Normal; animator.cullingMode = AnimatorCullingMode.CullUpdateTransforms; } if (go.GetComponent() == null) go.AddComponent(); if (go.GetComponent() == null) go.AddComponent(); if (go.GetComponent() == null) go.AddComponent(); if (go.GetComponent() == null) { NavMeshAgent agent = go.AddComponent(); agent.speed = 2.6f; agent.angularSpeed = 120f; agent.acceleration = 8f; agent.stoppingDistance = 0f; agent.autoBraking = true; agent.radius = 0.5f; agent.height = 2f; } if (go.GetComponent() == null) { EnemyAIController ai = go.AddComponent(); ai.aiType = TeamType.Monster; ai.detectionRange = 6f; ai.detectionAngle = 360f; ai.maxChaseDistance = 30f; ai.attackRange = 1f; ai.attackInterval = 1.2f; ai.attackDamage = 3; ai.moveSpeed = 2.6f; ai.chaseSpeedMultiplier = 1.2f; } MeshFilter meshFilter = go.GetComponent(); if (meshFilter == null) meshFilter = go.AddComponent(); MeshRenderer meshRenderer = go.GetComponent(); if (meshRenderer == null) meshRenderer = go.AddComponent(); int monsterLayer = LayerMask.NameToLayer("Monster"); if (monsterLayer >= 0) { go.layer = monsterLayer; } else { go.layer = 0; } NetworkObject netObj = go.GetComponent(); if (netObj != null) { netObj.SynchronizeTransform = true; netObj.SpawnWithObservers = true; netObj.AlwaysReplicateAsRoot = false; } EnemyUnit enemyUnit = go.GetComponent(); if (enemyUnit != null) { enemyUnit.enemyTeam = TeamType.Monster; } } private static void SetupTowerComponents(GameObject go) { Transform t = go.transform; t.localPosition = Vector3.zero; t.localRotation = Quaternion.identity; t.localScale = Vector3.one; if (go.GetComponent() == null) go.AddComponent(); if (go.GetComponent() == null) go.AddComponent(); if (go.GetComponent() == null) go.AddComponent(); if (go.GetComponent() == null) { BoxCollider collider = go.AddComponent(); collider.size = new Vector3(1f, 2f, 1f); collider.center = new Vector3(0f, 1f, 0f); } if (go.GetComponent() == null) { NavMeshObstacle obstacle = go.AddComponent(); obstacle.shape = NavMeshObstacleShape.Box; obstacle.size = new Vector3(1f, 1f, 1f); obstacle.center = new Vector3(0f, 0.5f, 0f); } int defaultLayer = LayerMask.NameToLayer("Default"); if (defaultLayer >= 0) { go.layer = defaultLayer; } else { go.layer = 0; } } private static void SetupPlayerComponents(GameObject go) { if (go.GetComponent() == null) go.AddComponent(); int playerLayer = LayerMask.NameToLayer("Player"); if (playerLayer >= 0) { go.layer = playerLayer; } else { go.layer = 0; } } } }