Main/Assets/Editor/SplitTerrain/CollectThings.cs
2025-01-25 04:38:09 +08:00

355 lines
12 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Thousandto.Core.Asset;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Thousandto.Editor.Test
{
public enum CollectTypeDefine
{
SkyBox, //天空盒子
Grass, //草
Effect, //场景特效
Mass, //其他杂七杂八的物件
}
public struct Thing
{
public string Name { get; set; }
public CollectTypeDefine CType { get; set; }
public GameObject Go { get; set; }
//当前物件的边界信息
public Bounds Bounds { get; set; }
//网格中的索引
public int Index { get; set; }
};
/// <summary>
/// 收集场景中的物件以分块区域来划分生成新的prefab
/// </summary>
public class CollectThings
{
List<MyTerrainData> _allTerrainDatas = new List<MyTerrainData>();
List<Thing> _grassThings = new List<Thing>();
List<Thing> _skyBoxThings = new List<Thing>();
List<Thing> _effectThings = new List<Thing>();
//跨mesh的普通物件
List<Thing> _otherThings = new List<Thing>();
//一些没有跨mesh存在的物件则集中存放到一起保存成一个新的prefab
Dictionary<MyTerrainData, List<Thing>> _thingInOneTerrainDict = new Dictionary<MyTerrainData, List<Thing>>();
private string _curMapName = "";
//记录各个分块
Dictionary<int, Rect> _resolutionDict = new Dictionary<int, Rect>();
//<index, <thingType, thingList>>
Dictionary<int, Dictionary<int, List<Thing>>> _collectThingDict = new Dictionary<int, Dictionary<int, List<Thing>>>();
private int _mapSize = 0;
private int _blockSize = 0;
/// <summary>
/// 设置分辨率
/// </summary>
/// <param name="mapSize">地图大小</param>
/// <param name="blockSize">分块大小</param>
public void SetResolution(int mapSize, int blockSize)
{
_mapSize = mapSize;
_blockSize = blockSize;
float countf = mapSize / (float)blockSize;
int count = mapSize / blockSize;
if (countf - count > 0.1f)
count++;
_resolutionDict.Clear();
for (int i = 0; i < count; ++i)
{
for(int j = 0; j < count; ++j)
{
Rect rect = new Rect(i * blockSize, j * blockSize, blockSize, blockSize);
int key = TerrainConfigLoader.CalcIndex(i, j);
_resolutionDict.Add(key, rect);
}
}
}
public void Collect(string mapName = "")
{
if(string.IsNullOrEmpty(mapName))
{
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
if (File.Exists(path))
{
EditorSceneManager.OpenScene(path);
}
}
else
{
if(mapName != EditorSceneManager.GetActiveScene().name)
{
var path = ConfigDefine.GetSceneFile(mapName);
if (File.Exists(path))
EditorSceneManager.OpenScene(path);
}
}
//删除旧的thing prefab
DeleteOldThingPrefabs();
var scene = EditorSceneManager.GetActiveScene();
var name = scene.name;
_curMapName = name;
_allTerrainDatas = LoadAllSplitedTerrain(name);
if (!CollectThingsInRoot())
return;
AssetDatabase.StartAssetEditing();
var configList = SaveThings(_collectThingDict);
AssetDatabase.StopAssetEditing();
if(configList.Count > 0)
{
var savePath = ConfigDefine.GetConfigPath(TerrainConfigDefine.THING_CONFIG_FILENAME);
File.WriteAllLines(savePath, configList.ToArray());
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
public static List<MyTerrainData> LoadAllSplitedTerrain(string mapName)
{
List<MyTerrainData> list = new List<MyTerrainData>();
string storePath = ConfigDefine.GetSaveTerrainPath(mapName);
if (!Directory.Exists(storePath))
{
Utils.ShowErrorMsgBox("加载小块地图网格", "找不到存储路径:" + storePath);
return list;
}
var fileList = Directory.GetFiles(storePath, "*.obj");
for(int i = 0; i < fileList.Length; ++i)
{
list.Add(MyTerrainData.CreateTerrainDataFromFileName(fileList[i]));
}
return list;
}
public bool CollectThingsInRoot(string root = "SceneRoot")
{
var rootGo = GameObject.Find(root);
if(rootGo == null)
{
Utils.ShowErrorMsgBox("获取场景中所有GameObject", "没有找到跟节点SceneRoot");
return false;
}
List<GameObject> gos = new List<GameObject>();
FindGameObjects(rootGo, gos);
for(int i = 0; i < gos.Count; ++i)
{
string fullName = Utils.GetGameObjectHierarchyPath(gos[i]);
if (gos[i].transform.childCount > 0 && gos[i].transform.position == Vector3.zero && gos[i].transform.localScale == Vector3.one)
continue;
Thing thing = new Thing();
thing.CType = GetThingTypeFromName(fullName);
thing.Go = gos[i];
thing.Name = fullName;
thing.Bounds = GetThingBounds(gos[i]);
//thing.RelateToMeshs = CalcRelativeToTerrainMeshes(thing, _allTerrainDatas);
if (thing.Bounds.size == Vector3.zero)
thing.Index = Utils.CalcIndex(thing.Go.transform.position, _blockSize);
else
thing.Index = Utils.CalcIndex(Utils.GetGameObjectCenter(thing), _blockSize);
Dictionary<int, List<Thing>> typeToThing;
if(!_collectThingDict.TryGetValue(thing.Index, out typeToThing))
{
typeToThing = new Dictionary<int, List<Thing>>();
_collectThingDict.Add(thing.Index, typeToThing);
}
if(thing.CType != CollectTypeDefine.SkyBox)
{
Utils.AddToDict(typeToThing, (int)thing.CType, thing);
}
else
{
_skyBoxThings.Add(thing);
}
}
return true;
}
private List<string> SaveThings(Dictionary<int, Dictionary<int, List<Thing>>> dataDict)
{
CreateNewPrefab("skybox", _skyBoxThings);
List<string> configList = new List<string>();
var itorRoot = dataDict.GetEnumerator();
while(itorRoot.MoveNext())
{
var rootGo = new GameObject("Thing_" + itorRoot.Current.Key);
var itor = itorRoot.Current.Value.GetEnumerator();
while(itor.MoveNext())
{
var rootName = GetRootName(itor.Current.Key);
var thingList = itor.Current.Value;
if(thingList != null)
{
var go = CopyToGameObject(rootName, thingList);
go.transform.parent = rootGo.transform;
}
}
string savePath = ConfigDefine.GetSavePrefabPath(rootGo.name + ".prefab");
configList.Add(string.Format("{0}", itorRoot.Current.Key));
PrefabUtility.CreatePrefab(savePath, rootGo);
AssetDatabase.ImportAsset(savePath);
GameObject.DestroyImmediate(rootGo);
}
EditorUtility.ClearProgressBar();
return configList;
}
private string GetRootName(int thingType)
{
CollectTypeDefine cType = (CollectTypeDefine)thingType;
switch(cType)
{
case CollectTypeDefine.Effect:
return "scene_effect";
case CollectTypeDefine.Grass:
return "grass";
case CollectTypeDefine.SkyBox:
return "skybox";
}
return "default";
}
private GameObject CopyToGameObject(string rootName, List<Thing> things)
{
GameObject go = new GameObject(rootName);
for (int i = 0; i < things.Count; ++i)
{
var inst = GameObject.Instantiate(things[i].Go);
inst.name = things[i].Go.name;
inst.transform.parent = go.transform;
Utils.CopyTransProperty(inst.transform, things[i].Go.transform);
Utils.CopyMesh(inst.transform, things[i].Go.transform);
}
return go;
}
private string CreateNewPrefab(string rootName, List<Thing> things)
{
GameObject go = new GameObject(rootName);
for(int i = 0; i < things.Count; ++i)
{
var inst = GameObject.Instantiate(things[i].Go);
inst.name = things[i].Go.name;
inst.transform.parent = go.transform;
Utils.CopyTransProperty(inst.transform, things[i].Go.transform);
Utils.CopyMesh(inst.transform, things[i].Go.transform);
}
string savePath = ConfigDefine.GetSavePrefabPath(rootName + ".prefab");
PrefabUtility.CreatePrefab(savePath, go);
AssetDatabase.ImportAsset(savePath);
GameObject.DestroyImmediate(go);
return savePath;
}
private void FindGameObjects(GameObject root, List<GameObject> refList)
{
List<GameObject> retList = refList;
Transform rootTran = root.transform;
if (rootTran.childCount == 0)
{
retList.Add(rootTran.gameObject);
return;
}
for (int i = 0; i < rootTran.childCount; ++i)
{
var temp = rootTran.GetChild(i);
{
FindGameObjects(temp.gameObject, refList);
}
}
}
private static CollectTypeDefine GetThingTypeFromName(string name)
{
if (name.IndexOf("sky", System.StringComparison.CurrentCultureIgnoreCase) >= 0)
return CollectTypeDefine.SkyBox;
if (name.IndexOf("grass", System.StringComparison.CurrentCultureIgnoreCase) >= 0)
return CollectTypeDefine.Grass;
if (name.IndexOf("effect", System.StringComparison.CurrentCultureIgnoreCase) >= 0)
return CollectTypeDefine.Effect;
return CollectTypeDefine.Mass;
}
private static bool IsBoxcollider(GameObject go)
{
return go.GetComponentInChildren<BoxCollider>() != null;
}
private static Bounds GetThingBounds(GameObject go)
{
var mf = go.GetComponentInChildren<MeshFilter>();
if (mf == null || mf.sharedMesh == null)
{
var boxcollider = go.GetComponentInChildren<BoxCollider>();
if (boxcollider == null)
{
Transform trans = go.transform;
Bounds bounds = new Bounds(trans.position, Vector3.zero);
return bounds;
}
//boxcollider.bounds是世界坐标这里需要相对坐标
return new Bounds(boxcollider.center, boxcollider.size);
}
return mf.sharedMesh.bounds;
}
private static void DeleteOldThingPrefabs()
{
var path = ConfigDefine.GetSavePrefabPath();
var fileList = Directory.GetFiles(path, "*.prefab");
for(int i = 0; i < fileList.Length; ++i)
{
if (fileList[i].StartsWith("Thing_"))
File.Delete(fileList[i]);
}
}
}
}