NLDClient-yudde/ProjectNLD/Assets/Editor/LevelEditor/LevelEditorWindow.cs

442 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using cfg.LevelCfg;
using Framework;
using Gameplay;
using Gameplay.Level;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities;
using Sirenix.Utilities.Editor;
using System;
using System.Collections.Generic;
using System.Linq;
using TGS;
using UnityEditor;
using UnityEngine;
using UnityEngine.Serialization;
using Constants = Framework.Constants;
using ObjectFieldAlignment = Sirenix.OdinInspector.ObjectFieldAlignment;
//todo 序列化bug
public class LevelEditorWindow : OdinEditorWindow
{
private static readonly Color regionColor = MapUtils.GetRGBAColor("FF960072");
[Serializable]
public class RegionData
{
[LabelText("出战区")]
[OnValueChanged("OnRegionChanged")]
public int preparingRegionId;
[LabelText("出战区朝向")]
public LevelData.CharacterToward preparingRegionToward;
[LabelText("撤退区")]
public int fallbackRegionId;
[LabelText("敌方撤退区")]
public int enemyFallbackRegionId;
[LabelText("PVP防守区")]
public int pvpDefendRegionId;
[LabelText("PVP防守方朝向")]
public LevelData.CharacterToward pvpDefendToward;
private void OnRegionChanged()
{
var regionslist = currWindow._curMap.MapData.regions;
for (int i = 0; i < regionslist.Count; i++)
{
currWindow._curMap.SetRegionColor(i, false, regionColor);
}
currWindow._curMap.SetRegionColor(preparingRegionId, true, regionColor);
}
}
[Serializable]
public class NPCEditorInfo
{
[HideLabel]
public LevelData.NPCInfo npcInfo;
private bool _isEditing;
public NPCEditorInfo(LevelData.NPCInfo npcInfo)
{
this.npcInfo = npcInfo;
}
[Button("开始编辑巡逻信息")]
[HideIf("_isEditing")]
private void StartEditNPC()
{
LevelEditorWindow.currWindow.StartEditPatrolInfo(npcInfo);
_isEditing = true;
}
[Button("完成编辑巡逻信息")]
[ShowIf("_isEditing")]
private void FinishEditNPC()
{
LevelEditorWindow.currWindow.FinishEditPatrolInfo();
_isEditing = false;
}
}
// private static LevelPresentation currentLevelPresentation;
private MapManager _mapManager;
private Dictionary<Vector2Int, GameObject> _npcDic;
private Map _curMap;
public static LevelEditorWindow currWindow;
private LevelEditor _levelEditor;
private LevelData.NPCInfo _currEditingNPCInfo;
public bool IsEditingPatrolInfo => _currEditingNPCInfo != null;
private bool ResponseClickOnCell => isEditingNPC || IsEditingPatrolInfo;
// [LabelText("关卡名称"), Indent]
// public string levelName;
[LabelText("当前关卡数据"), Indent]
[OnValueChanged("OnCurrentLevelDataChanged")]
public LevelData currentLevelData = null;
[LabelText("当前地区数据"), Indent]
[OnValueChanged("OnCurrentLevelDataChanged")]
public RegionData curRegionData = null;
[LabelText("添加NPC")]
[LabelWidth(100)]
[SerializeField]
public bool isEditingNPC;
[PreviewField(150, ObjectFieldAlignment.Center)]
[AssetList(Path = (Constants.LEVEL_NPC_PATH_WITHOUT_ASSET), CustomFilterMethod = "IsNPCPrefabValid")]
[ShowIf("isEditingNPC")]
[LabelText("选择NPC")]
public GameObject npcObject;
private bool IsNPCPrefabValid(GameObject prefab)
{
var monsterClasses = EditorTableManager.instance.tables.MonsterClass;
var prefabPath = AssetDatabase.GetAssetPath(prefab);
foreach (var monsterClassCfg in monsterClasses.DataList)
{
if (monsterClassCfg.PrefabPath == prefabPath)
return true;
}
return false;
}
public List<NPCEditorInfo> CurrentNpcInfo = null;
[Indent]
[Button("保存当前关卡")]
private void SaveCurrentLevel()
{
CheckCorrectLevel();
//var configFilePath = string.Format(Constants.LEVEL_CONFIG_FORMAT_PATH, currentLevelData.id);
currentLevelData.preparingRegionId = curRegionData.preparingRegionId;
currentLevelData.fallbackRegionId = curRegionData.fallbackRegionId;
currentLevelData.enemyFallbackRegionId = curRegionData.enemyFallbackRegionId;
currentLevelData.preparingRegionToward = curRegionData.preparingRegionToward;
currentLevelData.pvpDefendRegionId = curRegionData.pvpDefendRegionId;
currentLevelData.pvpDefendToward = curRegionData.pvpDefendToward;
//NPC列表
currentLevelData.npcInfos = CurrentNpcInfo.Select(editorNPCInfo => editorNPCInfo.npcInfo).ToList();
_levelEditor.SaveLevelData();
}
public static void OpenWindow(LevelEditor levelEditor)
{
MapEditorSettings.Init();
currWindow = GetWindow<LevelEditorWindow>();
currWindow.position = GUIHelper.GetEditorWindowRect().AlignCenter(800, 600);
currWindow.currentLevelData = null;
currWindow._levelEditor = levelEditor;
currWindow.LoadLevel(levelEditor.LevelData);
}
public const string preparingRegionErrorMessage = "关卡出战区设置错误,<{0}>地图没有:<{1}>号地区。\n";
public const string fallbackRegionErrorMessage = "关卡撤退区设置错误,<{0}>地图没有:<{1}>号地区。\n";
public const string enemyFallbackRegionErrorMessage = "关卡敌方撤退区设置错误,<{0}>地图没有:<{1}>号地区。\n";
public const string fixedMessage = "已将错误区域设置为<0>号地区。";
private void CheckCorrectLevel()
{
if (_curMap == null)
{
return;
}
var regionList = _curMap.MapData.regions;
var errorMessage = string.Empty;
if (!_curMap.MapData.IsRegionExist(currentLevelData.preparingRegionId))
{
errorMessage += string.Format(preparingRegionErrorMessage, null,
currentLevelData.preparingRegionId);
currentLevelData.preparingRegionId = 0;
}
if (!_curMap.MapData.IsRegionExist(currentLevelData.fallbackRegionId))
{
errorMessage += string.Format(fallbackRegionErrorMessage, null,
currentLevelData.fallbackRegionId);
currentLevelData.fallbackRegionId = 0;
}
if (!_curMap.MapData.IsRegionExist(currentLevelData.enemyFallbackRegionId))
{
errorMessage += string.Format(enemyFallbackRegionErrorMessage, null,
currentLevelData.enemyFallbackRegionId);
currentLevelData.enemyFallbackRegionId = 0;
}
if (!string.IsNullOrEmpty(errorMessage))
{
CustomPopUpWindow.PopUp(errorMessage + fixedMessage);
}
}
private void Awake()
{
SceneView.duringSceneGui += OnSceneGUI;
}
protected override void OnEnable()
{
TerrainTypeConfig.Load();
_npcDic = new Dictionary<Vector2Int, GameObject>();
base.OnEnable();
}
protected override void OnDisable()
{
currWindow = null;
//MapEditorUtils.UnLoadMap(EditorMap.Instance);
//DestroyImmediate(GameObject.Find("Main Camera"));
DestroyNpcPrefab();
_npcDic = null;
base.OnDisable();
}
protected override void OnDestroy()
{
base.OnDestroy();
if (_curMap != null)
_curMap.TerrainGridSystem.OnMouseClickOnGrid -= OnCellClick;
SaveCurrentLevel();
SceneView.duringSceneGui -= OnSceneGUI;
}
private bool banSaveLevelList = false;
private void OnCurrentLevelDataChanged()
{
Debug.Log($"{GetType()}.OnCurrentLevelDataChanged");
}
private const string descKey = "LevelDesc";
private const string nameKey = "LevelName";
private void LoadLevel(LevelData levelData)
{
DestroyNpcPrefab();
_npcDic.Clear();
currentLevelData = levelData;
//加载地区信息
curRegionData = new RegionData();
curRegionData.preparingRegionId = currentLevelData.preparingRegionId;
curRegionData.fallbackRegionId = currentLevelData.fallbackRegionId;
curRegionData.enemyFallbackRegionId = currentLevelData.enemyFallbackRegionId;
curRegionData.preparingRegionToward = currentLevelData.preparingRegionToward;
curRegionData.pvpDefendRegionId = currentLevelData.pvpDefendRegionId;
curRegionData.pvpDefendToward = currentLevelData.pvpDefendToward;
_mapManager = FindObjectOfType<MapManager>();
_curMap = _mapManager.Map;
_curMap.TerrainGridSystem.OnMouseClickOnGrid += OnCellClick;
//加载NPC到场景中
CurrentNpcInfo = new();
foreach (var npcInfo in currentLevelData.npcInfos)
{
CurrentNpcInfo.Add(new(npcInfo));
string npcId = string.Format("P_E{0}", npcInfo.id.ToString().Substring(1));
var npc = AssetDatabase.LoadAssetAtPath<GameObject>(string.Format(Constants.LEVEL_NPC_PATH, npcId));
var position = _curMap.BlockPosition2WorldPosition(npcInfo.position);
_npcDic.Add(npcInfo.position, Instantiate(npc, position, npc.transform.rotation));
}
}
private void OnCellClick(TerrainGridSystem tgs, int cellindex, int buttonindex)
{
if (!ResponseClickOnCell) return;
var clickPosition = _curMap.TGSCellIndex2BlockPosition(cellindex);
int leftButton = 0;
int rightButton = 1;
if (buttonindex != leftButton && buttonindex != rightButton)
return;
bool opTrue = buttonindex == leftButton;
if (IsEditingPatrolInfo)
{
if (opTrue)
AddPatrolInfo(clickPosition);
else
RemovePatrolInfo(clickPosition);
}
else if (isEditingNPC)
{
if (opTrue)
{
AddNPC(clickPosition);
}
else
{
RemoveNPC(clickPosition);
}
}
}
private void AddNPC(Vector2Int clickPosition)
{
if (npcObject == null)
{
DebugUtil.LogError("请选择正确的NPC");
return;
}
if (_npcDic.ContainsKey(clickPosition))
{
DebugUtil.LogError("该位置已有NPC存在请重新选");
return;
}
LevelData.NPCInfo npcInfo = new LevelData.NPCInfo();
string npcId = npcObject.name.Replace("P_E", "1");
npcInfo.id = int.Parse(npcId);
npcInfo.position = clickPosition;
//默认等级为1
npcInfo.level = 1;
CurrentNpcInfo.Add(new(npcInfo));
var position = _curMap.BlockPosition2WorldPosition(npcInfo.position);
_npcDic.Add(npcInfo.position, Instantiate(npcObject, position, npcObject.transform.rotation));
DebugUtil.Log("添加了[{0}]NPC到[ {1} ]位置上", npcObject.name, npcInfo.position);
}
private void RemoveNPC(Vector2Int clickPosition)
{
if (_npcDic.TryGetValue(clickPosition, out var npcObj))
{
var npc = CurrentNpcInfo.FirstOrDefault(npc => npc.npcInfo.position == clickPosition);
if (npc != null)
{
CurrentNpcInfo.Remove(npc);
DebugUtil.Log("从[ {0} ]位置上移除了[{1}]NPC", clickPosition, npcObj.name);
DestroyImmediate(npcObj);
_npcDic.Remove(clickPosition);
}
}
}
private void AddPatrolInfo(Vector2Int clickPosition)
{
_currEditingNPCInfo.patrolInfos.Add(new LevelData.PatrolInfo()
{
patrolPoint = clickPosition,
});
}
private void RemovePatrolInfo(Vector2Int clickPosition)
{
var index = _currEditingNPCInfo.patrolInfos.FindLastIndex(pInfo => pInfo.patrolPoint == clickPosition);
if (index >= 0)
_currEditingNPCInfo.patrolInfos.RemoveAt(index);
}
public void StartEditPatrolInfo(LevelData.NPCInfo npcInfo)
{
_currEditingNPCInfo = npcInfo;
}
public void FinishEditPatrolInfo()
{
_currEditingNPCInfo = null;
}
private void DestroyNpcPrefab()
{
foreach (var npc in _npcDic)
{
DestroyImmediate(npc.Value);
}
}
protected override void OnGUI()
{
base.OnGUI();
if (_levelEditor == null || _mapManager == null || _mapManager.Map != _curMap ||
_levelEditor.LevelData != currentLevelData)
{
Debug.LogError("数据已变更,请重新打开关卡编辑器");
Close();
}
}
private void OnSceneGUI(SceneView sceneView)
{
DrawPatrolPath();
}
private void DrawPatrolPath()
{
if (!IsEditingPatrolInfo)
{
return;
}
Vector3 lastWorldPos = Vector3.zero;
for (int i = 0; i < _currEditingNPCInfo.patrolInfos.Count; i++)
{
var gridPos = _currEditingNPCInfo.patrolInfos[i].patrolPoint;
var worldPos = _curMap.BlockPosition2WorldPosition(gridPos);
Handles.color = Color.blue;
Handles.DrawSolidDisc(worldPos, Vector3.up, 0.4f);
if (i > 0)
{
Handles.color = Color.yellow;
EditorUtil.DrawArrowInScene(lastWorldPos, worldPos, 0.5f);
}
//Handles.color = Color.black;
Handles.Label(worldPos, i.ToString());
lastWorldPos = worldPos;
}
}
}