convert continue :)))

This commit is contained in:
PCBrew
2025-11-03 17:34:39 +07:00
parent 2dc4c9ae1c
commit 10c7ba598b
9 changed files with 428 additions and 11 deletions
@@ -0,0 +1,123 @@
using Unity.VisualScripting;
using UnityEngine;
namespace BrewMonster
{
public class CECTaoistRank
{
private int m_id; // ID
private string m_name; // ID
private CECTaoistRank m_next;
static bool initComplete = false;
public static CECTaoistRank[] s_allTaoistRanks = new CECTaoistRank[(int)ToaistRank.TotalRankCount];
public static readonly int[] TaoistRankIDs = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 20, 21, 22, 30, 31, 32 };
public bool IsGodRank()
{
CECTaoistRank GodRank;
for (GodRank = GetGodRankBegin(); GodRank != GetGodRankEnd();
GodRank = GodRank.GetNext())
{
if (this == GodRank)
{
return true;
}
}
return false;
}
public CECTaoistRank GetGodRankBegin()
{
init();
return s_allTaoistRanks[(int)ToaistRank.BaseRankCount];
}
public CECTaoistRank GetGodRankEnd()
{
init();
return GetLastGodRank().m_next;
}
public CECTaoistRank GetLastGodRank()
{
init();
return s_allTaoistRanks[(int)ToaistRank.BaseRankCount + (int)ToaistRank.GodRankCount - 1];
}
public bool IsEvilRank()
{
CECTaoistRank EvilRank;
for (EvilRank = GetEvilRankBegin(); EvilRank != GetEvilRankEnd();
EvilRank = EvilRank.GetNext())
{
if (this == EvilRank)
{
return true;
}
}
return false;
}
public CECTaoistRank GetNext()
{
return m_next;
}
public static CECTaoistRank GetEvilRankBegin()
{
init();
return s_allTaoistRanks[(int)ToaistRank.BaseRankCount + (int)ToaistRank.GodRankCount];
}
public static CECTaoistRank GetEvilRankEnd()
{
init();
return GetLastEvilRank().m_next;
}
public static CECTaoistRank GetLastEvilRank()
{
init();
return s_allTaoistRanks[(int)ToaistRank.TotalRankCount - 1];
}
public static CECTaoistRank GetTaoistRank(int id)
{
init();
for (int i = 0; i < (int)ToaistRank.TotalRankCount; i++)
{
if (TaoistRankIDs[i] == id)
{
return s_allTaoistRanks[i];
}
}
return null;
}
public static void init()
{
if (initComplete)
{
return;
}
for (int i = 0; i < (int)ToaistRank.TotalRankCount; i++)
{
s_allTaoistRanks[i].m_id = TaoistRankIDs[i];
/* s_allTaoistRanks[i].m_name =
g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan()->GetStringFromTable(1001 + s_allTaoistRanks[i].m_id);*/
if (i != (int)ToaistRank.BaseRankCount - 1 &&
i != (int)ToaistRank.BaseRankCount + (int)ToaistRank.GodRankCount - 1 &&
i != (int)ToaistRank.TotalRankCount - 1)
{
s_allTaoistRanks[i].m_next = s_allTaoistRanks[i + 1];
}
else
{
s_allTaoistRanks[i].m_next = null;
}
}
initComplete = true;
}
}
public enum ToaistRank
{
TotalRankCount = 15,
BaseRankCount = 9,
GodRankCount = 3,
EvilRankCount = 3,
};
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0af7ab2d9c8f26f409468880e8e6e951
@@ -1109,7 +1109,19 @@ namespace CSNetwork.GPDataType
public const float MIN_MOVELEN_ON_GROUND = 0.5f;
public const float MIN_MOVELEN_FOR_DETECT_VIBRATION = 0.05f;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct cmd_scene_service_npc_list
{
public uint count;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct NpcEntry
{
public int tid; // npc template id
public int nid; // npc id
}
public NpcEntry[] list;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct cmd_npc_info_list
{
@@ -17,7 +17,10 @@ namespace CSNetwork
_buffer = new byte[capacity];
_size = 0;
}
public void Clear()
{
_size = 0; // reset logical length
}
public Octets(byte[] data)
{
if (data == null)
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4d8aa48b7719fb24ea83a779c1bf10eb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,18 @@
using System;
using UnityEngine;
namespace BrewMonster
{
public class CECObservableChange : IDisposable
{
public virtual void Dispose()
{
// Cleanup logic here
}
};
public class CECObserver
{
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 85f9d76b7820b1445aefd08f3f700001
@@ -1,12 +1,17 @@
using System.Collections.Generic;
using CSNetwork;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.GameData;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace BrewMonster.Scripts.Skills
{
class CECHostSkillModel
{
public static CECHostSkillModel instance;
public static CECHostSkillModel Instance {
public static CECHostSkillModel Instance
{
get
{
if (instance == null)
@@ -20,23 +25,243 @@ namespace BrewMonster.Scripts.Skills
}
Dictionary<int, ElementSkill> m_allProfSkills = new Dictionary<int, ElementSkill>();
Dictionary<int, List<int>> m_allRankProfSkills = new Dictionary<int, List<int>>();
private HashSet<int> m_allProfNPCs = new HashSet<int>();
private Dictionary<int, int> m_treeHeightMap = new Dictionary<int, int>();
private Dictionary<int, int> m_evilRootMap = new Dictionary<int, int>();
private Dictionary<int, int> m_godRootMap = new Dictionary<int, int>();
private Dictionary<int, int> m_baseRootMap = new Dictionary<int, int>();
private int m_skillLearnNPCNID;
private bool m_bInitialized;
private Octets m_npcListData;
public void Initialize()
{
// Çå¿ÕËùÓм¼ÄÜ£¬·ÀÖ¹ÒòΪ¶à¸ö½ÇÉ«µÇ¼µ¼ÖÂÖØ¸´¼ÓÔØ¼¼ÄÜ
Release();
InitAllSkillsOfCurProf();
/*FindAllNPCsOfCurProf();
std::set<int> rootSkills = GetRootSkillSet();
FindAllNPCsOfCurProf();
HashSet<int> rootSkills = GetRootSkillSet();
InitSkillTreeHeightMap(rootSkills);
InitSkillTreeRootMap(rootSkills);
m_bInitialized = true;
// ÖØÐ´¦ÀíNPCLIST
ProcessServiceList();*/
ProcessServiceList();
}
public void ProcessServiceList()
{
if (m_npcListData.Size > 0)
{
byte[] data = m_npcListData.RawBuffer;
int headerSize = Marshal.SizeOf(typeof(cmd_header));
int offset = headerSize;
int bodySize = m_npcListData.Size - offset;
byte[] bodyBytes = new byte[bodySize];
Buffer.BlockCopy(data, offset, bodyBytes, 0, bodySize);
cmd_scene_service_npc_list npcList = GPDataTypeHelper.FromBytes<cmd_scene_service_npc_list>(bodyBytes);
int i;
for (i = 0; i < npcList.count; i++)
{
int tid = npcList.list[i].tid;
if (m_allProfNPCs.Contains(tid))
{
if (m_skillLearnNPCNID != npcList.list[i].nid)
{
m_skillLearnNPCNID = npcList.list[i].nid;
SetCurServiceSkills(tid);
var change = new CECSkillPanelChange(CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_NPC, 0, 0);
//NotifyObservers(change);
break;
}
}
}
if (i == npcList.count && m_skillLearnNPCNID != 0)
{
m_skillLearnNPCNID = 0;
SetCurServiceSkills(0);
var change = new CECSkillPanelChange(CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_NPC, 0, 0);
//NotifyObservers(change);
}
m_npcListData.Clear();
}
}
private readonly HashSet<int> m_curServiceSkills = new HashSet<int>();
public void SetCurServiceSkills(int tid)
{
m_curServiceSkills.Clear();
if (tid == 0)
return;
var pDB = ElementDataManProvider.GetElementDataMan();
// Read NPC_ESSENCE from element data
DATA_TYPE dt = default;
var dataprt = pDB.get_data_ptr((uint)tid, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
if (dataprt == null)
return;
var npcEssence = (NPC_ESSENCE)dataprt;
// Get skill service block from id_skill_service
var dataprt2 = pDB.get_data_ptr((uint)tid, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
if (dataprt2 == null)
return;
var skillService = (NPC_SKILL_SERVICE)dataprt2;
// Copy all non-zero skill ids into m_curServiceSkills
foreach (int skillId in skillService.id_skills)
{
if (skillId != 0)
m_curServiceSkills.Add(skillId);
}
}
private void InitSkillTreeRootMap(IEnumerable<int> rootSkills)
{
foreach (int rootSkillID in rootSkills)
{
InitializeRootOfSkillTree(rootSkillID);
}
}
private void InitializeRootOfSkillTree(int rootSkillID)
{
var skillRootMap = GetSkillRootMap(rootSkillID);
var toTravelSkills = new Queue<int>();
toTravelSkills.Enqueue(rootSkillID);
while (toTravelSkills.Count > 0)
{
int skillID = toTravelSkills.Dequeue();
var juniors = GetJunior(skillID);
foreach (var (id, level) in juniors)
{
int juniorSkillID = (int)id;
skillRootMap[juniorSkillID] = rootSkillID;
toTravelSkills.Enqueue(juniorSkillID);
}
}
}
private Dictionary<int, int> GetSkillRootMap(int rootSkillID)
{
var skill = m_allProfSkills[rootSkillID];
var taoistRank = CECTaoistRank.GetTaoistRank(skill.GetRank());
if (taoistRank.IsEvilRank())
return m_evilRootMap;
else if (taoistRank.IsGodRank())
return m_godRootMap;
else
return m_baseRootMap;
}
private void InitSkillTreeHeightMap(IEnumerable<int> rootSkills)
{
foreach (var rootSkillID in rootSkills)
{
m_treeHeightMap[rootSkillID] = GetSkillTreeHeight(rootSkillID);
}
}
private int GetSkillTreeHeight(int rootSkillID)
{
var juniors = GetJunior(rootSkillID);
int maxHeight = 0;
for (int i = 0; i < juniors.Count; i++)
{
int subHeight = GetSkillTreeHeight((int)juniors[i].id);
if (subHeight > maxHeight)
{
maxHeight = subHeight;
}
}
return 1 + maxHeight;
}
private List<(uint id, int level)> GetJunior(int skillID)
{
if (!m_allProfSkills.TryGetValue(skillID, out var skill))
{
throw new Exception($"Skill {skillID} not found in m_allProfSkills");
}
var juniors = skill.GetJunior();
var ret = new List<(uint id, int level)>();
foreach (var (id, level) in juniors)
{
if (id != 0)
ret.Add((id, level));
}
return ret;
}
private HashSet<int> GetRootSkillSet()
{
var rootSkills = new HashSet<int>();
foreach (var kvp in m_allProfSkills)
if (kvp.Value.GetJunior().Count != 0)
rootSkills.Add(kvp.Key);
foreach (var kvp in m_allProfSkills)
foreach (var (id, level) in kvp.Value.GetJunior())
rootSkills.Remove((int)id);
return rootSkills;
}
private void FindAllNPCsOfCurProf()
{
DATA_TYPE dt = DATA_TYPE.DT_NPC_ESSENCE;
elementdataman pDB = ElementDataManProvider.GetElementDataMan();
var map = pDB.GetMap<Dictionary<uint, DATA_TYPE>>(ID_SPACE.ID_SPACE_ESSENCE);
uint id;
foreach (var item in map)
{
if (item.Value == dt)
{
id = item.Key;
}
else
{
continue;
}
NPC_ESSENCE npcEssence = (NPC_ESSENCE)pDB.get_data_ptr(id, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
if (npcEssence.id_skill_service != 0 &&
(npcEssence.combined_switch & (uint)NPC_COMBINED_SWITCH.NCS_IGNORE_DISTANCE_CHECK) != 0)
{
NPC_SKILL_SERVICE skillService = (NPC_SKILL_SERVICE)pDB.get_data_ptr(npcEssence.id_skill_service, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
bool profCorrect = false;
for (int i = 0; i < skillService.id_skills.Length; i++)
{
if (skillService.id_skills[i] != 0)
{
ElementSkill pSkill = ElementSkill.Create(skillService.id_skills[i], 1);
if (pSkill.GetCls() == GameController.Instance.GetHostPlayer().GetProfession())
{
// NPCǰְҵܣҪ¼NPCID
profCorrect = true;
break;
}
}
}
if (profCorrect)
{
m_allProfNPCs.Add((int)npcEssence.id);
}
}
}
}
public void InitAllSkillsOfCurProf()
{
// --- B1: Thu thập toàn bộ skill từ các NPC có cung cấp dịch vụ học skill ---
@@ -57,13 +282,13 @@ namespace BrewMonster.Scripts.Skills
{
continue;
}
NPC_ESSENCE npcEssence = (NPC_ESSENCE)pDB.get_data_ptr(id, ID_SPACE.ID_SPACE_ESSENCE,ref dt);
NPC_ESSENCE npcEssence = (NPC_ESSENCE)pDB.get_data_ptr(id, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
if (npcEssence.id_skill_service != 0 &&
(npcEssence.combined_switch & (uint)NPC_COMBINED_SWITCH.NCS_IGNORE_DISTANCE_CHECK) != 0)
{
NPC_SKILL_SERVICE skillService = (NPC_SKILL_SERVICE)pDB.get_data_ptr(
npcEssence.id_skill_service, ID_SPACE. ID_SPACE_ESSENCE, ref dt
npcEssence.id_skill_service, ID_SPACE.ID_SPACE_ESSENCE, ref dt
);
for (int i = 0; i < skillService.id_skills.Length; i++)
@@ -85,7 +310,7 @@ namespace BrewMonster.Scripts.Skills
{
ElementSkill pSkill = ElementSkill.Create(curID, 1);
int cls = pSkill.GetCls();
int playerCls = GameController.Instance.GetHostPlayer().GetProfession();
int playerCls = GameController.Instance.GetHostPlayer().GetProfession();
bool isSameClass = (cls == playerCls || cls == 255);
bool isProvidedByNPC = npcSkills.Contains(curID);
@@ -155,4 +380,25 @@ namespace BrewMonster.Scripts.Skills
SKILL_EVIL, // ɼ / Immortal skill
SKILL_GOD, // ħ / Demonic skill
}
public class CECSkillPanelChange : CECObservableChange
{
public enum enumChangeMask
{
CHANGE_SKILL_LEVEL_UP, // Skill level up
CHANGE_SKILL_OVERRIDDEN, // Skill overridden
CHANGE_SKILL_NPC // NPC providing skill changed
}
public enumChangeMask m_changeMask;
public int m_skillID;
public int m_skillLevel;
public CECSkillPanelChange(enumChangeMask mask, int id, int level)
{
m_changeMask = mask;
m_skillID = id;
m_skillLevel = level;
}
}
}
@@ -141,7 +141,10 @@ namespace BrewMonster.Scripts.Skills
{
return Skill.Create(id, n);
}
//
public virtual List<(uint id, int level)> GetJunior()
{
return new List<(uint, int)>();
}
public virtual ushort[] GetName() { return null;}
public virtual byte[] GetNativeName() { return null;}
// ?,skill_type