#if UNITY_EDITOR using UnityEditor; using UnityEngine; using System.Collections.Generic; public class ManualTerrainRegionCopier : EditorWindow { private Terrain sourceTerrain; private Terrain targetTerrain; private int gridX = 0, gridZ = 0; private int splitCount = 4; private bool copyHeights = true; private bool copyDetails = true; private bool copyTrees = true; private bool copyLayers = true; [MenuItem("Tools/Terrain Region Copier")] public static void ShowWindow() { GetWindow("Copy Terrain Region"); } void OnGUI() { GUILayout.Label("Копіювати сектор з Map.asset", EditorStyles.boldLabel); sourceTerrain = (Terrain)EditorGUILayout.ObjectField("Звідки (Map)", sourceTerrain, typeof(Terrain), true); targetTerrain = (Terrain)EditorGUILayout.ObjectField("Куди (частина)", targetTerrain, typeof(Terrain), true); gridX = EditorGUILayout.IntSlider("Grid X (0-3)", gridX, 0, splitCount - 1); gridZ = EditorGUILayout.IntSlider("Grid Z (0-3)", gridZ, 0, splitCount - 1); splitCount = EditorGUILayout.IntField("Розмір сітки", splitCount); GUILayout.Space(10); GUILayout.Label("Що копіювати:"); copyHeights = EditorGUILayout.Toggle("Висоти", copyHeights); copyDetails = EditorGUILayout.Toggle("Трава / деталі", copyDetails); copyTrees = EditorGUILayout.Toggle("Дерева", copyTrees); copyLayers = EditorGUILayout.Toggle("Текстури / шари", copyLayers); if (GUILayout.Button("🔁 Копіювати")) { if (sourceTerrain == null || targetTerrain == null) { Debug.LogError("❌ Обери обидва Terrain'и."); return; } CopyRegion(sourceTerrain, targetTerrain, gridX, gridZ, splitCount); } } void CopyRegion(Terrain source, Terrain target, int gx, int gz, int grid) { TerrainData src = source.terrainData; TerrainData dst = target.terrainData; // --- HEIGHTS --- if (copyHeights) { int heightRes = src.heightmapResolution - 1; int chunkSize = heightRes / grid; float[,] heights = src.GetHeights(gx * chunkSize, gz * chunkSize, dst.heightmapResolution, dst.heightmapResolution); dst.SetHeights(0, 0, heights); } // --- DETAILS --- if (copyDetails) { dst.detailPrototypes = src.detailPrototypes; int detailRes = src.detailResolution; int detailChunk = detailRes / grid; dst.SetDetailResolution(detailChunk, src.detailResolutionPerPatch); for (int i = 0; i < src.detailPrototypes.Length; i++) { int[,] layer = src.GetDetailLayer(gx * detailChunk, gz * detailChunk, detailChunk, detailChunk, i); dst.SetDetailLayer(0, 0, i, layer); } } // --- TREES --- if (copyTrees) { dst.treePrototypes = src.treePrototypes; List trees = new List(); Vector2 min = new Vector2(gx / (float)grid, gz / (float)grid); Vector2 max = min + new Vector2(1f / grid, 1f / grid); foreach (TreeInstance tree in src.treeInstances) { if (tree.position.x >= min.x && tree.position.x < max.x && tree.position.z >= min.y && tree.position.z < max.y) { TreeInstance t = tree; t.position.x = (t.position.x - min.x) * grid; t.position.z = (t.position.z - min.y) * grid; trees.Add(t); } } dst.treeInstances = trees.ToArray(); } // --- TEXTURES (Layers + Alphamaps) --- if (copyLayers) { dst.terrainLayers = src.terrainLayers; dst.wavingGrassAmount = src.wavingGrassAmount; dst.wavingGrassSpeed = src.wavingGrassSpeed; dst.wavingGrassStrength = src.wavingGrassStrength; dst.wavingGrassTint = src.wavingGrassTint; int alphaRes = src.alphamapResolution; int alphaChunk = alphaRes / grid; dst.alphamapResolution = alphaChunk; float[,,] alphaMaps = src.GetAlphamaps(gx * alphaChunk, gz * alphaChunk, alphaChunk, alphaChunk); if (alphaMaps != null && alphaMaps.GetLength(2) == dst.terrainLayers.Length) { dst.SetAlphamaps(0, 0, alphaMaps); } else { Debug.LogWarning($"⚠️ Alphamap mismatch. Skipping for ({gx},{gz})"); } } EditorUtility.SetDirty(dst); AssetDatabase.SaveAssets(); Debug.Log($"✅ Скопійовано сектор ({gx}, {gz}) до → {target.name}"); } } #endif