using System; using PhxhSDK; using UnityEngine; using System.Linq; using LC.Newtonsoft.Json; using Framework.Constants; using Sirenix.OdinInspector; using Cysharp.Threading.Tasks; using System.Collections.Generic; using UnityEngine.AddressableAssets; namespace Framework.Manager { /// /// 解锁类型 /// public enum UnlockType { [LabelText("按挂点解锁")] ForGroup, [LabelText("按主题解锁")] ForThematic, } /// /// 解锁条件类型 /// public enum UnlockConditionType { [LabelText("关卡解锁")] Level, [LabelText("金币解锁")] Coin, } [Serializable] public class BuildData { [ReadOnly] public string buildID; [LabelText("挂点数量")] public int nodeCount; [LabelText("主题数量")] public int thematicCount; [LabelText("解锁类型")] [SerializeField] public UnlockType unlockType; [LabelText("解锁条件类型")] [SerializeField] public UnlockConditionType unlockConditionType; [LabelText("解锁条件")] public List unlockInfos; [LabelText("挂点数据")] public List NodeInfos; [Serializable] public class UnlockInfo { [LabelText("条件")] public int condition; //主题 or 挂点 [LabelText("对应组")] public int conditionGroup; [LabelText("前置组")] public int preGroup; } [Serializable] public class BuildNode { [LabelText("挂点名称")] [ReadOnly] public string Name; [HideInInspector] public List Options; [HideInInspector] public string IconPath; [JsonConstructor] public BuildNode(string name) { this.Name = name; this.Options = new List(); this.IconPath = string.Empty; } public BuildNode() { } } } /// /// 节点信息类 /// public class NodeInfo { public string Name; public Dictionary Options; //按挂点解锁条件 public int Condition; //前置解锁组 public string PreGroup; public string IconPath; public OptionInfo GetOptionInfo(string optionID = null) { if (optionID == null) optionID = "Option1"; return Options.GetValueOrDefault(optionID); } } /// /// 节点选项类 /// public class OptionInfo { public string Name; public string IconPath; //按主题解锁条件 public int Condition; //前置主题 public string PreThematic; } /// /// 玩家养成建造存盘数据 /// public class UserBuildInfo { public int GuideGroup; public string BuildData = NormalConstants.DefaultBuildID; public Dictionary ChooseNodeInfo; public UserBuildInfo() { ChooseNodeInfo = new Dictionary(); } public UserBuildInfo(string buildData) { DebugUtil.LogError("建造新的buildDAta :{0}", buildData); BuildData = buildData; ChooseNodeInfo = new Dictionary(); } } public class BuildManager { public const string UserBuildSaveKey = "UserBuildInfo"; public const string DefaultBuildID = "Build_1"; private const string NodeName = "Node{0}"; private const string OptionName = "Option{0}"; private static BuildManager _instance; public static BuildManager Instance { get { if (_instance == null) { _instance = new BuildManager(); } return _instance; } } public Dictionary NodeInfos; public NodeInfo CurIUnlockNodeInfo; public bool IsChanging = false; /// /// 更换场景 /// public bool ChangeBuildSceneID; //玩家存盘选择信息 private UserBuildInfo _userBuildInfo; public UserBuildInfo UserBuildInfo { get => _userBuildInfo; private set => _userBuildInfo = value; } //已达到的条件 public int ReachCondition { get => _reachCondition; private set => _reachCondition = value; } private int _reachCondition = -1; //动态加载的图标 private Dictionary _iconSprites; //当前场景蓝图 public Sprite CurBlueprint; //Build场景相机 public Camera CurBuildCamera; private BuildData _curBuildData; private bool _isInit; private bool _isInGame; public async UniTask Init(BuildData buildData, bool inGame = false, UserBuildInfo userBuildInfo = null) { if (_isInit && !ChangeBuildSceneID) return; _curBuildData = buildData; NodeInfos = new Dictionary(); _iconSprites = new Dictionary(); InitNodesInfo(); InitUserBuildInfo(userBuildInfo); InitCondition(); await InitIcon(); InitBlueprint(); _isInGame = inGame; if (inGame) CurBuildCamera = CameraManager.Instance.UICamera; _isInit = true; } /// /// 初始化该Build场景的节点信息 /// private void InitNodesInfo() { try { foreach (var node in _curBuildData.NodeInfos) { var nodeInfo = new NodeInfo { Name = node.Name, Options = new Dictionary(), IconPath = node.IconPath }; foreach (var option in node.Options) { var optionInfo = new OptionInfo() { Name = option }; nodeInfo.Options.Add(option, optionInfo); } NodeInfos.Add(nodeInfo.Name, nodeInfo); } } catch (Exception e) { DebugUtil.LogError("BuildManager.InitNodesInfo 初始化节点错误 :{0}", e); } } /// /// 初始化存盘信息 /// private void InitUserBuildInfo(UserBuildInfo userBuildInfo) { try { if(_isInit)return; //游戏中传入数据 if (userBuildInfo != null) { _userBuildInfo = userBuildInfo; } else { StorageManager.Instance.Init(); _userBuildInfo = StorageManager.Instance.GetStorage(UserBuildSaveKey); if (_userBuildInfo == null) { var buildId = _curBuildData.buildID; _userBuildInfo = new UserBuildInfo(buildId); } } foreach (var nodeInfo in NodeInfos) { if (_userBuildInfo.ChooseNodeInfo.TryGetValue(nodeInfo.Key, out var option)) { continue; } /*var optionInfo = nodeInfo.Value.GetOptionInfo(); if (optionInfo == null) return; _userBuildInfo.ChooseNodeInfo.TryAdd(nodeInfo.Key, optionInfo.Name);*/ _userBuildInfo.ChooseNodeInfo.TryAdd(nodeInfo.Key, ""); } //DebugUserChooseNode(); } catch (Exception e) { DebugUtil.LogError("BuildManager.InitUserBuildInfo 初始玩家信息错误 :{0}", e); } } /// /// 初始化条件 /// private void InitCondition() { try { switch (_curBuildData.unlockType) { case UnlockType.ForGroup: { foreach (var unlockInfo in _curBuildData.unlockInfos) { var nodeName = string.Format(NodeName, unlockInfo.conditionGroup); if (NodeInfos.TryGetValue(nodeName, out var nodeInfo)) { nodeInfo.Condition = unlockInfo.condition; var nextNode = string.Format(NodeName, unlockInfo.preGroup); nodeInfo.PreGroup = nextNode; //DebugUtil.LogError("挂点解锁:节点{0}的解锁条件是: {1}, 前置解锁组是: {2}", nodeInfo.Name, unlockInfo.condition, nextNode); } } break; } case UnlockType.ForThematic: { foreach (var unlockInfo in _curBuildData.unlockInfos) { var optionName = string.Format(OptionName, unlockInfo.conditionGroup); foreach (var nodeInfo in NodeInfos.Values) { if (nodeInfo.Options.TryGetValue(optionName, out var optionInfo)) { optionInfo.Condition = unlockInfo.condition; var nextOption = string.Format(OptionName, unlockInfo.preGroup); optionInfo.PreThematic = nextOption; DebugUtil.LogError("主题解锁:节点{0}的选项{1}的解锁条件是:{2}, 前置解锁主题是: {3}", nodeInfo.Name, optionInfo.Name, unlockInfo.condition, nextOption); } } } break; } } } catch (Exception e) { DebugUtil.LogError("BuildManager.InitCondition 初始化条件错误 :{0}", e); } } /// /// 异步加载该建造物品图标 /// private async UniTask InitIcon() { try { foreach (var nodeInfo in NodeInfos.Values) { foreach (var optionInfo in nodeInfo.Options.Values) { optionInfo.IconPath = await InitOptionIcon(nodeInfo.IconPath, optionInfo.Name); } } } catch (Exception e) { DebugUtil.LogError("BuildManager.InitIcon 初始化图标数据错误 :{0}", e); } } /// /// 初始化加载选项图标 /// private async UniTask InitOptionIcon(string iconsPath, string optionName) { try { var path = string.Format(iconsPath, optionName); var assetPath = path.Replace(Application.dataPath, "").Replace('\\', '/'); var sprite = await AssetManager.Instance.LoadAssetAsync(assetPath); if (_iconSprites.TryAdd(path, sprite)) return path; return null; } catch (Exception e) { DebugUtil.LogError("BuildManager.InitOptionIcon 加载选项图标错误, 路径: {0}, Error: {1}", iconsPath, e); return null; } } /// /// 加载当前场景蓝图 /// private async void InitBlueprint() { try { var path = string.Format(Constants.PathConstants.BuildBlueprint, _curBuildData.buildID); CurBlueprint = await AssetManager.Instance.LoadAssetAsync(path); } catch (Exception e) { DebugUtil.LogError("BuildManager.InitBlueprint 加载蓝图错误 :{0}", e); } } /// /// 更换建造场景 /// public async void ChangeBuildScene() { var buildId = _curBuildData.buildID.Equals(NormalConstants.DefaultBuildID) ? "Build_2" : "Build_1"; var buildPath = string.Format(Framework.Constants.PathConstants.SceneBuildPath, buildId); await Addressables.LoadSceneAsync(buildPath).ToUniTask(); } /// /// 获得选项Icon图标 /// public Sprite GetOptionIcon(string nodeName, string optionName) { if (NodeInfos.TryGetValue(nodeName, out var nodeInfo)) { if (nodeInfo.Options.TryGetValue(optionName, out var optionInfo)) { if (_iconSprites.TryGetValue(optionInfo.IconPath, out var sprite)) return sprite; } } return null; } /// /// 根据节点获得解锁条件 /// public int GetCondition(string nodeName) { var condition = 0; if (NodeInfos.TryGetValue(nodeName, out var nodeInfo)) { condition = nodeInfo.Condition; } return condition; } public void SaveNodeInfo(string node, string option) { if (_userBuildInfo.ChooseNodeInfo.TryGetValue(node, out var oldOption)) { _userBuildInfo.ChooseNodeInfo[node] = option; DebugUtil.LogY($"节点{node}保存了{option}选择"); } else { DebugUtil.LogWarning("玩家Build存档信息没有 {0} 节点信息,请检查初始化", node); _userBuildInfo.ChooseNodeInfo.Add(node, option); } StorageManager.Instance.SaveWithoutUpdate(); } /// /// 获取下一个解锁节点 /// public string GetNextLockNode() { string nodeName = null; switch (_curBuildData.unlockType) { case UnlockType.ForGroup: { foreach (var node in NodeInfos) { if (_userBuildInfo.ChooseNodeInfo.TryGetValue(node.Key, out var curNode) && _userBuildInfo.ChooseNodeInfo.TryGetValue(node.Value.PreGroup, out var preNode)) { //当前节点位选择且前置节点已选择 if (string.IsNullOrEmpty(curNode) && !string.IsNullOrEmpty(preNode)) { //DebugUtil.LogError("下一个节点是{0}", node.Key); return node.Key; } } } var firstNode = NodeInfos .OrderBy(kv => kv.Value.Condition) .FirstOrDefault(); return firstNode.Key; } //TODO 按主题解锁 default: break; } //DebugUtil.LogError("得到最小的节点是{0}", nodeName); return nodeName; } /// /// 更新已经达到的条件 /// public void UpdateReachCondition(int condition) { //TODO 分场景 、解锁类型、解锁条件 _reachCondition = condition; } /// /// 更新本地节点选择 /// public void SetBuildUserInfo(int guideGroupID) { _userBuildInfo.GuideGroup = guideGroupID; StorageManager.Instance.SyncForce = true; } /// /// 播放音效 /// public void PlaySound() { if (_isInGame) AudioManager.Instance.PlaySound(AudioType.SOUND, "S_Btn", new UnityAudio(false)); } /// /// Debug 清楚玩家所有选择 /// public void ClearOption() { foreach (var node in NodeInfos) { if (_userBuildInfo.ChooseNodeInfo.TryGetValue(node.Key, out var option)) _userBuildInfo.ChooseNodeInfo[node.Key] = ""; } DebugUserChooseNode(); StorageManager.Instance.SyncForce = true; } private void DebugUserChooseNode() { foreach (var infos in _userBuildInfo.ChooseNodeInfo) { DebugUtil.LogError("节点 {0} 选择的的是 {1}", infos.Key, infos.Value); } } public void Release() { } } }