136 lines
5.0 KiB
C#
136 lines
5.0 KiB
C#
|
|
#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<ManualTerrainRegionCopier>("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<TreeInstance> trees = new List<TreeInstance>();
|
||
|
|
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
|