diff --git a/Assets/Scripts/Task/ATaskTemplMan.cs b/Assets/Scripts/Task/ATaskTemplMan.cs index 95f2add267..c57b544d55 100644 --- a/Assets/Scripts/Task/ATaskTemplMan.cs +++ b/Assets/Scripts/Task/ATaskTemplMan.cs @@ -67,10 +67,10 @@ namespace PerfectWorld.Scripts.Task // fread(pOffs, sizeof(long), tph.item_count, fp); - pOffs = AAssit.ReadArrayFromBinary(fs, tph.item_count, ref readBytes); + pOffs = AAssit.ReadArrayFromBinary(fs, (int)tph.item_count, ref readBytes); - for (int i = 0; i < tph.item_count; i++) + for (int i = 0; i < 1; i++) //TODO: tph.item_count { fs.Seek(pOffs[i], SeekOrigin.Begin); diff --git a/Assets/Scripts/Task/TaskTempl.cs b/Assets/Scripts/Task/TaskTempl.cs index 8e43546304..687660c994 100644 --- a/Assets/Scripts/Task/TaskTempl.cs +++ b/Assets/Scripts/Task/TaskTempl.cs @@ -2,6 +2,8 @@ using UnityEngine; using System.IO; using System.Runtime.InteropServices; using System; +using BrewMonster; +using ModelRenderer.Scripts.Common; namespace PerfectWorld.Scripts.Task @@ -273,13 +275,15 @@ namespace PerfectWorld.Scripts.Task enumTAFEachYear // 每年 // Yearly } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct TASK_PACK_HEADER { public uint magic; public uint version; - public int item_count; + public uint item_count; } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct ZONE_VERT { public float x; @@ -670,6 +674,19 @@ namespace PerfectWorld.Scripts.Task else return false; } + + public static ushort uint_to_ushort(uint id) + { + return (ushort)(id & 0xFF); + } + + public static void convert_txt(ref ushort[] str, int len, ushort code) + { + for (int i = 0; i < len; i++) + { + str[i] ^= code; + } + } } @@ -940,6 +957,231 @@ namespace PerfectWorld.Scripts.Task } } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct AWARD_RATIO_SCALE + { + static uint g_ulNewCount; // Static counter for memory tracking + + // Default constructor not available in C# 9.0, fields are initialized directly + public uint m_ulScales; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_AWARD_SCALES)] + public float[] m_Ratios; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_AWARD_SCALES)] + public AWARD_DATA[] m_Awards; //[MAX_AWARD_SCALES]; + + // Initialize method instead of constructor + public void Initialize() + { + m_ulScales = 0; + m_Ratios = new float[TaskTemplConstants.MAX_AWARD_SCALES]; + m_Awards = null; + +#if TASK_TEMPL_EDITOR + m_Awards = new AWARD_DATA[TaskTemplConstants.MAX_AWARD_SCALES]; + g_ulNewCount++; +#endif + } + + public static bool operator == (AWARD_RATIO_SCALE a, AWARD_RATIO_SCALE b) + { + if (a.m_ulScales != b.m_ulScales) + { + return false; + } + + for (uint i = 0; i < a.m_ulScales; ++i) + { + // Add null check + if (a.m_Ratios[i] != b.m_Ratios[i] || + (a.m_Awards != null && b.m_Awards != null && i < a.m_Awards.Length && i < b.m_Awards.Length && + !(a.m_Awards[i] == b.m_Awards[i]))) + { + return false; + } + } + return true; + } + + public static bool operator != (AWARD_RATIO_SCALE a, AWARD_RATIO_SCALE b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + if (obj is AWARD_RATIO_SCALE) + return this == (AWARD_RATIO_SCALE)obj; + return false; + } + + public override int GetHashCode() + { + return m_ulScales.GetHashCode(); + } + + // Copy constructor equivalent method + public static AWARD_RATIO_SCALE CreateCopy(AWARD_RATIO_SCALE src) + { + AWARD_RATIO_SCALE result = new AWARD_RATIO_SCALE(); + result.m_ulScales = src.m_ulScales; + result.m_Ratios = new float[TaskTemplConstants.MAX_AWARD_SCALES]; + + // Copy the ratios array + for (int i = 0; i < src.m_Ratios.Length && i < TaskTemplConstants.MAX_AWARD_SCALES; i++) + { + result.m_Ratios[i] = src.m_Ratios[i]; + } + +#if !TASK_TEMPL_EDITOR + if (src.m_ulScales > 0) + { + result.m_Awards = new AWARD_DATA[src.m_ulScales]; + g_ulNewCount++; + } +#else + result.m_Awards = new AWARD_DATA[TaskTemplConstants.MAX_AWARD_SCALES]; + g_ulNewCount++; +#endif + + // Copy awards if available + if (src.m_Awards != null && result.m_Awards != null) + { + for (uint i = 0; i < src.m_ulScales && i < result.m_Awards.Length && i < src.m_Awards.Length; i++) + { + result.m_Awards[i] = src.m_Awards[i]; + } + } + + return result; + } + + public bool HasAward() + { + if (m_Awards == null) + return false; + + for (uint i = 0; i < m_ulScales && i < m_Awards.Length; i++) + if (m_Awards[i].HasAward()) + return true; + + return false; + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct AWARD_ITEMS_SCALE + { + static uint g_ulNewCount; // Static counter for memory tracking + + // Default constructor not available in C# 9.0, fields are initialized directly + public uint m_ulScales; + public uint m_ulItemId; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_AWARD_SCALES)] + public uint[] m_Counts; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_AWARD_SCALES)] + public AWARD_DATA[] m_Awards; //[MAX_AWARD_SCALES]; + + // Initialize method instead of constructor + public void Initialize() + { + m_ulScales = 0; + m_ulItemId = 0; + m_Counts = new uint[TaskTemplConstants.MAX_AWARD_SCALES]; + m_Awards = null; + +#if TASK_TEMPL_EDITOR + m_Awards = new AWARD_DATA[TaskTemplConstants.MAX_AWARD_SCALES]; + g_ulNewCount++; +#endif + } + + public static bool operator == (AWARD_ITEMS_SCALE a, AWARD_ITEMS_SCALE b) + { + if (a.m_ulScales != b.m_ulScales) + { + return false; + } + for (uint i = 0; i < a.m_ulScales; ++i) + { + // Add null check + if (a.m_Counts[i] != b.m_Counts[i] || + (a.m_Awards != null && b.m_Awards != null && i < a.m_Awards.Length && i < b.m_Awards.Length && + !(a.m_Awards[i] == b.m_Awards[i]))) + { + return false; + } + } + + return a.m_ulItemId == b.m_ulItemId; + } + + public static bool operator != (AWARD_ITEMS_SCALE a, AWARD_ITEMS_SCALE b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + if (obj is AWARD_ITEMS_SCALE) + return this == (AWARD_ITEMS_SCALE)obj; + return false; + } + + public override int GetHashCode() + { + return m_ulScales.GetHashCode() ^ m_ulItemId.GetHashCode(); + } + + // Copy constructor equivalent method + public static AWARD_ITEMS_SCALE CreateCopy(AWARD_ITEMS_SCALE src) + { + AWARD_ITEMS_SCALE result = new AWARD_ITEMS_SCALE(); + result.m_ulScales = src.m_ulScales; + result.m_ulItemId = src.m_ulItemId; + result.m_Counts = new uint[TaskTemplConstants.MAX_AWARD_SCALES]; + + // Copy the counts array + for (int i = 0; i < src.m_Counts.Length && i < TaskTemplConstants.MAX_AWARD_SCALES; i++) + { + result.m_Counts[i] = src.m_Counts[i]; + } + +#if !TASK_TEMPL_EDITOR + if (src.m_ulScales > 0) + { + result.m_Awards = new AWARD_DATA[src.m_ulScales]; + g_ulNewCount++; + } +#else + result.m_Awards = new AWARD_DATA[TaskTemplConstants.MAX_AWARD_SCALES]; + g_ulNewCount++; +#endif + + // Copy awards if available + if (src.m_Awards != null && result.m_Awards != null) + { + for (uint i = 0; i < src.m_ulScales && i < result.m_Awards.Length && i < src.m_Awards.Length; i++) + { + result.m_Awards[i] = src.m_Awards[i]; + } + } + + return result; + } + + public bool HasAward() + { + if (m_Awards == null) + return false; + + for (uint i = 0; i < m_ulScales && i < m_Awards.Length; i++) + if (m_Awards[i].HasAward()) + return true; + + return false; + } + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct AWARD_DATA { @@ -1053,6 +1295,7 @@ namespace PerfectWorld.Scripts.Task public bool m_bSendMsg; public int m_nMsgChannel; public uint m_ulCandItems; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_AWARD_CANDIDATES)] public AWARD_ITEMS_CAND[] m_CandItems; //[MAX_AWARD_CANDIDATES]; public uint m_ulSummonedMonsters; public AWARD_MONSTERS_SUMMONED m_SummonedMonsters; @@ -1114,9 +1357,9 @@ namespace PerfectWorld.Scripts.Task // 显示全局变量表达式 // Display global variable expressions public uint m_ulExpCnt; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT)] - public string[] m_pszExp; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT)] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT * TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_CHAR_LEN)] + public char[] m_pszExp; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT * TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_CHAR_LEN)] public TASK_EXPRESSION[] m_pExpArr; // 显示全局变量表达式提示字符串 // Display global variable expression prompt strings @@ -1132,6 +1375,7 @@ namespace PerfectWorld.Scripts.Task public int m_iTaskLimit; public uint m_ulTitleNum; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TITLE_NUM)] public TITLE_AWARD[] m_pTitleAward; public int m_iLeaderShip; @@ -1471,6 +1715,7 @@ namespace PerfectWorld.Scripts.Task } + public enum task_tm_type { @@ -1541,6 +1786,7 @@ namespace PerfectWorld.Scripts.Task } } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct Task_Region { public ZONE_VERT zvMin; @@ -1575,6 +1821,7 @@ namespace PerfectWorld.Scripts.Task } } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct ATaskTemplFixedData { // 任务id // Task ID @@ -1582,11 +1829,12 @@ namespace PerfectWorld.Scripts.Task // 任务名称 // Task name [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TASK_NAME_LEN)] - public char[] m_szName; + public ushort[] m_szName; // 任务署名 // Task signature public bool m_bHasSign; - public string m_pszSignature; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TASK_NAME_LEN)] + public ushort[] m_pszSignature; // 任务类型 // Task type public uint m_ulType; @@ -1615,9 +1863,11 @@ namespace PerfectWorld.Scripts.Task public char[] m_tmType; // 发放起始时间 // Distribution start time + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TIMETABLE_SIZE)] public task_tm[] m_tmStart; // 发放终止时间 // Distribution end time + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TIMETABLE_SIZE)] public task_tm[] m_tmEnd; // 发放频率 // Distribution frequency @@ -1664,18 +1914,21 @@ namespace PerfectWorld.Scripts.Task public bool m_bDelvInZone; public uint m_ulDelvWorld; public uint m_ulDelvRegionCnt; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TASKREGION)] public Task_Region[] m_pDelvRegion; // 进入区域任务失败 // Task fails when entering region public bool m_bEnterRegionFail; public uint m_ulEnterRegionWorld; public uint m_ulEnterRegionCnt; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TASKREGION)] public Task_Region[] m_pEnterRegion; // 离开区域任务失败 // Task fails when leaving region public bool m_bLeaveRegionFail; public uint m_ulLeaveRegionWorld; public uint m_ulLeaveRegionCnt; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TASKREGION)] public Task_Region[] m_pLeaveRegion; // 离开阵营失败 // Fails when leaving force @@ -1735,8 +1988,11 @@ namespace PerfectWorld.Scripts.Task // Change global key/value public uint m_ulChangeKeyCnt; - public long[] m_plChangeKey; // [TASK_AWARD_MAX_CHANGE_VALUE] - public long[] m_plChangeKeyValue; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_CHANGE_VALUE)] + public int[] m_plChangeKey; // [TASK_AWARD_MAX_CHANGE_VALUE] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_CHANGE_VALUE)] + public int[] m_plChangeKeyValue; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_CHANGE_VALUE)] public bool[] m_pbChangeType; // Fail on scene switch @@ -1764,7 +2020,7 @@ namespace PerfectWorld.Scripts.Task public bool m_bPQTask; // Whether it is a PQ task // 是否是PQ任务 public uint m_ulPQExpCnt; // PQ task global variable display // PQ任务全局变量显示 [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT)] - public string[] m_pszPQExp; // PQ expressions + public byte[] m_pszPQExp; // PQ expressions [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT)] public TASK_EXPRESSION[] m_pPQExpArr; // PQ expression arrays @@ -1939,6 +2195,7 @@ namespace PerfectWorld.Scripts.Task public bool m_bShowByNotInTeam; public uint m_iPremTitleNumTotal; public uint m_iPremTitleNumRequired; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TITLE_NUM)] public int[] m_PremTitles; public bool m_bShowByTitle; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] @@ -1982,6 +2239,7 @@ namespace PerfectWorld.Scripts.Task //public ZONE_VERT m_ReachSiteMin; //public ZONE_VERT m_ReachSiteMax; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TASKREGION)] public Task_Region[] m_pReachSite; public uint m_ulReachSiteCnt; public uint m_ulReachSiteId; @@ -2005,6 +2263,7 @@ namespace PerfectWorld.Scripts.Task //public ZONE_VERT m_LeaveSiteMin; //public ZONE_VERT m_LeaveSiteMax; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TASKREGION)] public Task_Region[] m_pLeaveSite; public uint m_ulLeaveSiteCnt; public uint m_ulLeaveSiteId; @@ -2043,11 +2302,29 @@ namespace PerfectWorld.Scripts.Task public uint m_ulAwardType_F; /* 普通和按每个方式 */ /* Normal and per-method rewards */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] - public AWARD_DATA[] m_Award_S; /* 成功 */ /* Success */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] - public AWARD_DATA[] m_Award_F; /* 失败 */ /* Failure */ + public AWARD_DATA m_Award_S; /* 成功 */ /* Success */ + public AWARD_DATA m_Award_F; /* 失败 */ /* Failure */ + + /* 时间比例方式 */ /* Time ratio method */ + public AWARD_RATIO_SCALE m_AwByRatio_S; + public AWARD_RATIO_SCALE m_AwByRatio_F; + + /* 按获得物比例方式 */ /* Item ratio method */ + public AWARD_ITEMS_SCALE m_AwByItems_S; + public AWARD_ITEMS_SCALE m_AwByItems_F; + + /* 层次结构 */ /* Hierarchy structure */ + public uint m_ulParent; + public uint m_ulPrevSibling; + public uint m_ulNextSibling; + public uint m_ulFirstChild; + + /* 库任务相关 */ /* Library task related */ + public bool m_bIsLibraryTask; + public float m_fLibraryTasksProbability; + public bool m_bIsUniqueStorageTask; + public int m_iWorldContribution; // 世界贡献度要求 // World contribution requirement } public class ATaskTempl { @@ -2114,7 +2391,21 @@ namespace PerfectWorld.Scripts.Task { long readBytes = 0; - ATaskTemplFixedData fixedData = AAssit.ReadFromBinaryOf(fp, ref readBytes); + BMLogger.Log($"LoadFixedDataFromBinFile: {fp.Length}"); + + ATaskTemplFixedData fixedData; + fixedData = AAssit.ReadFromBinaryOf(fp, ref readBytes); + + + // fixedData.m_ID = AAssit.ReadFromBinaryOf(fp, ref readBytes); + // fixedData.m_szName = AAssit.ReadArrayFromBinary(fp, TaskTemplConstants.MAX_TASK_NAME_LEN, ref readBytes); + // TaskTemplUtils.convert_txt(ref fixedData.m_szName, TaskTemplConstants.MAX_TASK_NAME_LEN, TaskTemplUtils.uint_to_ushort(fixedData.m_ID)); + // BMLogger.Log($"LoadFixedDataFromBinFile: ID {fixedData.m_ID} Name {ByteToStringUtils.UshortArrayToCP936String(fixedData.m_szName)}"); + // fixedData.m_bHasSign = AAssit.ReadFromBinaryOf(fp, ref readBytes); + + + + // ATaskTemplFixedData fixedData = AAssit.ReadFromBinaryOf(fp, ref readBytes); //convert_txt(m_szName, MAX_TASK_NAME_LEN, (namechar)m_ID);