355 lines
12 KiB
C#
355 lines
12 KiB
C#
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]);
|
||
}
|
||
}
|
||
}
|
||
}
|