Files
Cielonos/Assets/Scripts/MainGame/GameRun/Map/Zone/ZoneData.cs
SoulliesOfficial 47125f95f4 地图初步
2026-04-30 07:06:38 -04:00

384 lines
13 KiB
C#
Raw 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 System;
using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using Sirenix.Utilities;
using SLSUtilities.General;
using UnityEngine;
using UnityEngine.Serialization;
#if UNITY_EDITOR
using UnityEditor;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities.Editor;
#endif
namespace Cielonos.MainGame.Map
{
[CreateAssetMenu(fileName = "ZoneData", menuName = "Cielonos/MainGame/Map/ZoneData", order = 1)]
public partial class ZoneData : SerializedScriptableObject
{
[InlineProperty]
public struct SpawnPointKey : System.IEquatable<SpawnPointKey>
{
[HorizontalGroup("Row")] [LabelText("Spawn Point")] [LabelWidth(90)]
public string group;
[HorizontalGroup("Row", Width = 50, MarginLeft = 10)] [HideLabel]
public int index;
public SpawnPointKey(string group, int index)
{
this.group = group;
this.index = index;
}
public bool Equals(SpawnPointKey other)
{
return group == other.group && index == other.index;
}
public override bool Equals(object obj)
{
return obj is SpawnPointKey other && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
return ((group != null ? group.GetHashCode() : 0) * 397) ^ index;
}
}
public static bool operator ==(SpawnPointKey left, SpawnPointKey right)
{
return left.Equals(right);
}
public static bool operator !=(SpawnPointKey left, SpawnPointKey right)
{
return !left.Equals(right);
}
public override string ToString() => $"{group}_{index}";
}
[System.Serializable]
[InlineProperty]
[HideReferenceObjectPicker]
public class EnemySpawnMapping
{
[HideInInspector] [System.NonSerialized]
public ZoneData parent;
[FormerlySerializedAs("Group")] [HorizontalGroup("SpawnInfo", 0.25f), HideLabel] [ReadOnly]
public string group;
[FormerlySerializedAs("Index")] [HorizontalGroup("SpawnInfo", 0.15f), HideLabel] [ReadOnly]
public int index;
[FormerlySerializedAs("EnemyID")]
[HorizontalGroup("SpawnInfo", 0.5f), HideLabel]
[ValueDropdown("GetEnemyKeys")]
[OnValueChanged("OnEnemyIDChanged")]
public string enemyID;
public EnemySpawnMapping()
{
}
public EnemySpawnMapping(SpawnPointKey key, string val, ZoneData parent)
{
group = key.group;
index = key.index;
enemyID = val;
this.parent = parent;
}
#if UNITY_EDITOR
private void OnEnemyIDChanged()
{
if (parent != null)
{
parent.UpdateDictionaryEntry(group, index, enemyID);
}
}
#endif
private IEnumerable<string> GetEnemyKeys()
{
return MainGameBaseCollection.Instance.enemiesCollection.Keys;
}
}
}
public partial class ZoneData
{
#if UNITY_EDITOR
private static void AddButtonOnTitleBarGUI(Action buttonAction, EditorIcon icon = null)
{
icon ??= EditorIcons.MagnifyingGlass;
if (SirenixEditorGUI.ToolbarButton(icon))
{
buttonAction?.Invoke();
}
}
#endif
}
public partial class ZoneData
{
[Title("Scene Info")]
[ValueDropdown("GetAllSceneNames"), PropertyOrder(-1)]
[InfoBox("当前场景和ZoneData的关联场景不匹配", InfoMessageType.Error, VisibleIf = "@!IsCurrentSceneMatch")]
public string sceneName;
public bool IsCurrentSceneMatch => UnityEngine.SceneManagement.SceneManager.GetActiveScene().name == sceneName;
#if UNITY_EDITOR
private List<string> GetAllSceneNames()
{
List<string> sceneNames = new List<string>();
foreach (var scene in EditorBuildSettings.scenes)
{
if (scene.enabled)
{
string name = System.IO.Path.GetFileNameWithoutExtension(scene.path);
sceneNames.Add(name);
}
}
return sceneNames;
}
#endif
}
public partial class ZoneData
{
private void CollectSpawnPoints(List<SpawnPointKey> list, string groupName)
{
ZoneManager zoneManager = ZoneManager.Instance;
zoneManager.RebuildMapData();
list.Clear();
if (zoneManager.spawnPoints.TryGetValue(groupName, out List<SpawnPoint> points))
{
for (int i = 0; i < points.Count; i++)
{
list.Add(new SpawnPointKey(groupName, i));
}
}
}
}
public partial class ZoneData
{
[Title("Spawn Settings")]
[Title("Player", HorizontalLine = false, Bold = false)]
[ListDrawerSettings(ShowIndexLabels = false, AddCopiesLastElement = true), PropertyOrder(10), LabelText("Player Spawns")]
public List<SpawnPointKey> playerSpawns = new List<SpawnPointKey>() { new SpawnPointKey("Player", 0) };
}
public partial class ZoneData
{
[SerializeField, HideInInspector] public Dictionary<SpawnPointKey, string> enemySpawns = new Dictionary<SpawnPointKey, string>();
#if UNITY_EDITOR
[HideInInspector] private List<string> selectedGroupsToSync = new List<string>();
[Title("Enemy", HorizontalLine = false)]
[ShowInInspector]
[ListDrawerSettings(
OnTitleBarGUI = "DrawEnemySpawnTitleBarGUI",
ShowFoldout = true,
CustomRemoveIndexFunction = "RemoveEnemySpawnsIndex",
CustomRemoveElementFunction = "RemoveEnemySpawnsElement")]
[LabelText("Enemy Spawns"), PropertyOrder(12)]
private List<EnemySpawnMapping> EnemySpawnsInEditor
{
get => GetSortedMappings();
set
{
enemySpawns = new Dictionary<SpawnPointKey, string>();
foreach (EnemySpawnMapping item in value)
{
enemySpawns[new SpawnPointKey(item.group, item.index)] = item.enemyID;
}
EditorUtility.SetDirty(this);
}
}
private void OnEnemySyncSettingsChanged()
{
ZoneManager zoneManager = ZoneManager.Instance;
zoneManager.RebuildMapData();
Dictionary<SpawnPointKey, string> newDict = new Dictionary<SpawnPointKey, string>();
foreach (string group in selectedGroupsToSync)
{
if (zoneManager.spawnPoints.TryGetValue(group, out List<SpawnPoint> points))
{
for (int i = 0; i < points.Count; i++)
{
SpawnPointKey key = new SpawnPointKey(group, i);
newDict[key] = enemySpawns != null ? enemySpawns.GetValueOrDefault(key, "") : "";
}
}
}
enemySpawns = newDict;
EditorUtility.SetDirty(this);
}
private List<EnemySpawnMapping> GetSortedMappings()
{
List<EnemySpawnMapping> list = new List<EnemySpawnMapping>();
if (enemySpawns == null) return list;
list.AddRange(enemySpawns.Select(kvp => new EnemySpawnMapping(kvp.Key, kvp.Value, this)));
list.Sort((a, b) =>
{
int comp = string.Compare(a.group, b.group, System.StringComparison.Ordinal);
if (comp != 0) return comp;
return a.index.CompareTo(b.index);
});
return list;
}
private void RemoveEnemySpawnsElement(EnemySpawnMapping element)
{
SpawnPointKey key = new SpawnPointKey(element.group, element.index);
if (enemySpawns.Remove(key))
{
EditorUtility.SetDirty(this);
}
}
private void RemoveEnemySpawnsIndex(int index)
{
var list = GetSortedMappings();
if (index >= 0 && index < list.Count)
{
EnemySpawnMapping item = list[index];
SpawnPointKey key = new SpawnPointKey(item.group, item.index);
if (enemySpawns.Remove(key))
{
EditorUtility.SetDirty(this);
}
}
}
public void UpdateDictionaryEntry(string group, int index, string newEnemyID)
{
SpawnPointKey key = new SpawnPointKey(group, index);
if (enemySpawns.ContainsKey(key))
{
enemySpawns[key] = newEnemyID;
EditorUtility.SetDirty(this);
}
}
private void DrawEnemySpawnTitleBarGUI() => AddButtonOnTitleBarGUI(OpenEnemySyncSelector);
private void OpenEnemySyncSelector()
{
ZoneManager zoneManager = ZoneManager.Instance;
zoneManager.RebuildMapData();
GroupSyncPopup popup = new GroupSyncPopup(zoneManager.spawnPoints.Keys, selectedGroupsToSync, (result) =>
{
selectedGroupsToSync = result;
OnEnemySyncSettingsChanged();
});
OdinEditorWindow window = OdinEditorWindow.InspectObject(popup);
float width = 400;
float height = 200;
var centerRect = GUIHelper.GetEditorWindowRect().AlignCenter(width, height);
window.position = centerRect;
window.ShowPopup();
}
private class GroupSyncPopup
{
[LabelText("Available Groups")]
[ListDrawerSettings(IsReadOnly = true, ShowIndexLabels = false, HideAddButton = true, HideRemoveButton = true)]
[TableList(AlwaysExpanded = true, HideToolbar = true)]
[ShowInInspector, PropertyOrder(1)]
public List<GroupItem> toggles = new List<GroupItem>();
private readonly System.Action<List<string>> onConfirm;
public GroupSyncPopup(IEnumerable<string> available, List<string> current, System.Action<List<string>> onConfirm)
{
this.onConfirm = onConfirm;
foreach (string name in available)
{
toggles.Add(new GroupItem(name, current.Contains(name)));
}
}
[Button, PropertyOrder(2)]
public void Confirm()
{
List<string> result = toggles.Where(t => t.sync).Select(t => t.name).ToList();
this.onConfirm?.Invoke(result);
GUIHelper.CurrentWindow?.Close();
}
public class GroupItem
{
[HideLabel, TableColumnWidth(30, Resizable = false)]
public bool sync;
[HideLabel, ReadOnly] public string name;
public GroupItem(string name, bool sync)
{
this.name = name;
this.sync = sync;
}
}
}
#endif
}
public partial class ZoneData
{
[Title("Specified Locations", HorizontalLine = false)]
[PropertyOrder(20)]
[LabelText("Exit Spawns")]
[ListDrawerSettings(ShowIndexLabels = false, OnTitleBarGUI = "DrawExitSpawnsTitleBarGUI")]
public List<SpawnPointKey> exitSpawns = new List<SpawnPointKey>() { new SpawnPointKey("Exit", 0) };
#if UNITY_EDITOR
private void DrawExitSpawnsTitleBarGUI() =>
AddButtonOnTitleBarGUI(() => CollectSpawnPoints(exitSpawns, "Exit"), EditorIcons.Refresh);
#endif
[PropertySpace]
[PropertyOrder(21)]
[LabelText("Tech Center Spawns")]
[ListDrawerSettings(ShowIndexLabels = false, OnTitleBarGUI = "DrawTechCenterSpawnsTitleBarGUI")]
public List<SpawnPointKey> techCenterSpawns = new List<SpawnPointKey>();
#if UNITY_EDITOR
private void DrawTechCenterSpawnsTitleBarGUI() =>
AddButtonOnTitleBarGUI(() => CollectSpawnPoints(techCenterSpawns, "TechCenter"), EditorIcons.Refresh);
#endif
}
public partial class ZoneData
{
[Title("Random Locations", HorizontalLine = false)]
[ListDrawerSettings(ShowIndexLabels = false, AddCopiesLastElement = true), PropertyOrder(50), LabelText("Random Location Spawns")]
public List<SpawnPointKey> randomLocationSpawns = new List<SpawnPointKey>();
[ValueDropdown("GetLocationIDs"), PropertyOrder(51), LabelText("Available Random Locations")]
public List<string> availableRandomLocations = new List<string>();
public List<string> GetLocationIDs()
{
return new List<string>() { "Factory", "Warehouse", "Office", "Laboratory", "Hangar", "Storage" }
.Exclude(availableRandomLocations).ToList();
}
}
}