diff --git a/.cursor/rules/convert-data-rule.mdc b/.cursor/rules/convert-data-rule.mdc index 03924c974c..4954635dec 100644 --- a/.cursor/rules/convert-data-rule.mdc +++ b/.cursor/rules/convert-data-rule.mdc @@ -9,7 +9,7 @@ When reading binary data from C++ files using `FileStream`, follow these convers ## Important Type Mappings - `unsigned long` in C++ → `uint` in C# -- `bool` in C++ → 1 byte (same as C# in struct layout) +- `bool` in C++ → 1 byte (read as `byte` in C#, then convert with `> 0`) - `wchar_t` on Windows → 2 bytes - `task_char` → `ushort` - Pointer size in C++ binary → typically 4 bytes (32-bit) @@ -32,13 +32,24 @@ float m_fLibraryTasksProbability; ```csharp // Read value and assign to the field fixedData.m_ID = AAssit.ReadFromBinaryOf(fp, ref readBytes); -fixedData.m_bHasSign = AAssit.ReadFromBinaryOf(fp, ref readBytes); + +// Special case for bool: read as byte and compare with > 0 +fixedData.m_bHasSign = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; +fixedData.m_bChooseOne = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; + +// Other primitive types fixedData.m_lAvailFrequency = AAssit.ReadFromBinaryOf(fp, ref readBytes); fixedData.m_fLibraryTasksProbability = AAssit.ReadFromBinaryOf(fp, ref readBytes); ``` **Rule**: Use `AAssit.ReadFromBinaryOf(fp, ref readBytes)` where T is the C# equivalent type. +**Important for bool**: C++ bool is stored as 1 byte in binary files. Always read as `byte` and convert to C# bool using `> 0`: +```csharp +// Correct pattern for bool +fixedData.m_boolField = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; +``` + --- ## Case 2: Fixed-Size Arrays (Inline Memory) @@ -195,8 +206,8 @@ task_tm* m_tmStart; // Only has data if m_ulTimetable > 0 **C# Conversion**: ```csharp -// First read the flag/count -fixedData.m_bHasSign = AAssit.ReadFromBinaryOf(fp, ref readBytes); +// First read the flag/count (read bool as byte and convert with > 0) +fixedData.m_bHasSign = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; // Skip the pointer (Case 3) fp.Seek(4, SeekOrigin.Current); @@ -250,6 +261,20 @@ public static T[] ReadArrayFromBinary(FileStream fp, int count, ref long read ## Common Mistakes to Avoid +❌ **Wrong**: Reading bool directly as bool type +```csharp +// C++: bool m_bHasSign +fixedData.m_bHasSign = AAssit.ReadFromBinaryOf(fp, ref readBytes); // Wrong! +``` + +✅ **Correct**: +```csharp +// Read as byte and compare with > 0 +fixedData.m_bHasSign = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; // Correct! +``` + +--- + ❌ **Wrong**: Skipping pointer size instead of basic type size for Case 5 ```csharp // C++: ushort* m_pszSignature diff --git a/Assets/Scripts/Task/ATaskTemplMan.cs b/Assets/Scripts/Task/ATaskTemplMan.cs index c57b544d55..c7093ad170 100644 --- a/Assets/Scripts/Task/ATaskTemplMan.cs +++ b/Assets/Scripts/Task/ATaskTemplMan.cs @@ -70,7 +70,7 @@ namespace PerfectWorld.Scripts.Task pOffs = AAssit.ReadArrayFromBinary(fs, (int)tph.item_count, ref readBytes); - for (int i = 0; i < 1; i++) //TODO: tph.item_count + for (int i = 0; i < 3; 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 c2548f99fb..0d4892125f 100644 --- a/Assets/Scripts/Task/TaskTempl.cs +++ b/Assets/Scripts/Task/TaskTempl.cs @@ -2457,95 +2457,146 @@ namespace PerfectWorld.Scripts.Task } private bool LoadFixedDataFromBinFile(FileStream fp) { - for (int i = 1; i <= 8; i++) - { - for (int j = 1; j <= 8; j++) - { - Debug.LogError($"==== {i},{j} ==="); - ConvertFixedData(fp, i, j); - Debug.LogError($"=========="); - } - } + // for (int j = 1; j <= 20; j++) + // { + // Debug.LogError($"==== {j} ==="); + // ConvertFixedData(fp, j); + // Debug.LogError($"=========="); + // } + ConvertFixedData(fp, 1); return true; } - private void ConvertFixedData(FileStream fp, int x1, int x2) + private void ConvertFixedData(FileStream fp, int x2) { long readBytes = 0; BMLogger.Log($"LoadFixedDataFromBinFile: {fp.Length}"); ATaskTemplFixedData fixedData; - // Task ID - fixedData.m_ID = AAssit.ReadFromBinaryOf(fp, ref readBytes); // unsigned long m_ID; - BMLogger.Log($"LoadFixedDataFromBinFile: {fixedData.m_ID}"); + var originalPos = fp.Position; + // Task ID + fixedData.m_ID = AAssit.ReadFromBinaryOf(fp, ref readBytes); // unsigned long m_ID; + BMLogger.LogError($"m_ID: {fixedData.m_ID}"); - // Task Name (task_char m_szName[MAX_TASK_NAME_LEN];) - fixedData.m_szName = AAssit.ReadArrayFromBinary(fp, x1*TaskTemplConstants.MAX_TASK_NAME_LEN, ref readBytes); - // Debug.LogError($"m_szName: {fixedData.m_szName}"); + // Task Name (task_char m_szName[MAX_TASK_NAME_LEN];) + fixedData.m_szName = AAssit.ReadArrayFromBinary(fp, TaskTemplConstants.MAX_TASK_NAME_LEN, ref readBytes); //64 - // Has Signature (bool m_bHasSign;) - fixedData.m_bHasSign = AAssit.ReadFromBinaryOf(fp, ref readBytes); - Debug.LogError($"m_bHasSign: {fixedData.m_bHasSign}"); + // Has Signature (bool m_bHasSign;) + fixedData.m_bHasSign = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; + BMLogger.LogError($"m_bHasSign: {fixedData.m_bHasSign}"); //68 - // Signature pointer (task_char* m_pszSignature;) - // Only the pointer address is stored in the binary (skip 4 bytes) - fp.Seek(x2, SeekOrigin.Current); + // Signature pointer (task_char* m_pszSignature;) + // Only the pointer address is stored in the binary (skip 4 bytes) + fp.Seek(4, SeekOrigin.Current); - // Task Type (unsigned long m_ulType;) - fixedData.m_ulType = AAssit.ReadFromBinaryOf(fp, ref readBytes); - // Debug.LogError($"Type: {fixedData.m_ulType}"); + // Task Type (unsigned long m_ulType;) + fixedData.m_ulType = AAssit.ReadFromBinaryOf(fp, ref readBytes);//value 103 + BMLogger.LogError($"Type: {fixedData.m_ulType}"); + + // Time Limit (unsigned long m_ulTimeLimit;) + fixedData.m_ulTimeLimit = AAssit.ReadFromBinaryOf(fp, ref readBytes); - if (fixedData.m_ulType == 103) - { - //fixedData.m_bHasSign ==0 && - Debug.LogError("Catch it!"); - } + // Offline Fail (bool m_bOfflineFail;) + fixedData.m_bOfflineFail = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; - // Time Limit (unsigned long m_ulTimeLimit;) - fixedData.m_ulTimeLimit = AAssit.ReadFromBinaryOf(fp, ref readBytes); + // Absolute Fail (bool m_bAbsFail;) + fixedData.m_bAbsFail = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; - // Offline Fail (bool m_bOfflineFail;) - fixedData.m_bOfflineFail = AAssit.ReadFromBinaryOf(fp, ref readBytes); + // Absolute Fail Time (task_tm m_tmAbsFailTime;) + fixedData.m_tmAbsFailTime = AAssit.ReadFromBinaryOf(fp, ref readBytes); + + - // Absolute Fail (bool m_bAbsFail;) - fixedData.m_bAbsFail = AAssit.ReadFromBinaryOf(fp, ref readBytes); + // (unsigned long m_ulAbsFailTime;) // commented out in C++ source - // Absolute Fail Time (task_tm m_tmAbsFailTime;) - fixedData.m_tmAbsFailTime = AAssit.ReadFromBinaryOf(fp, ref readBytes); + // Item Not Take Off (bool m_bItemNotTakeOff;) + fixedData.m_bItemNotTakeOff = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; - // (unsigned long m_ulAbsFailTime;) // commented out in C++ source + // Absolute Time (bool m_bAbsTime;) + fixedData.m_bAbsTime = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; + + - // Item Not Take Off (bool m_bItemNotTakeOff;) - fixedData.m_bItemNotTakeOff = AAssit.ReadFromBinaryOf(fp, ref readBytes); + // Timetable count (unsigned long m_ulTimetable;) + fixedData.m_ulTimetable = AAssit.ReadFromBinaryOf(fp, ref readBytes); - // Absolute Time (bool m_bAbsTime;) - fixedData.m_bAbsTime = AAssit.ReadFromBinaryOf(fp, ref readBytes); + // Timetable type (char m_tmType[MAX_TIMETABLE_SIZE];) + fixedData.m_tmType = AAssit.ReadArrayFromBinary(fp, TaskTemplConstants.MAX_TIMETABLE_SIZE, ref readBytes); - // Timetable count (unsigned long m_ulTimetable;) - fixedData.m_ulTimetable = AAssit.ReadFromBinaryOf(fp, ref readBytes); + // Start time pointer (task_tm* m_tmStart; [MAX_TIMETABLE_SIZE]) + // Only the pointer address is stored in the binary (skip 4 bytes) + fp.Seek(4, SeekOrigin.Current); - // Timetable type (char m_tmType[MAX_TIMETABLE_SIZE];) - fixedData.m_tmType = AAssit.ReadArrayFromBinary(fp, TaskTemplConstants.MAX_TIMETABLE_SIZE, ref readBytes); + // End time pointer (task_tm* m_tmEnd; [MAX_TIMETABLE_SIZE]) + // Only the pointer address is stored in the binary (skip 4 bytes) + fp.Seek(4, SeekOrigin.Current); - // Start time pointer (task_tm* m_tmStart; [MAX_TIMETABLE_SIZE]) - // Only the pointer address is stored in the binary (skip 4 bytes) - fp.Seek(4, SeekOrigin.Current); + // Available frequency (long m_lAvailFrequency;) + fixedData.m_lAvailFrequency = AAssit.ReadFromBinaryOf(fp, ref readBytes); - // End time pointer (task_tm* m_tmEnd; [MAX_TIMETABLE_SIZE]) - // Only the pointer address is stored in the binary (skip 4 bytes) - fp.Seek(4, SeekOrigin.Current); + // Period limit (long m_lPeriodLimit;) + fixedData.m_lPeriodLimit = AAssit.ReadFromBinaryOf(fp, ref readBytes); - // Available frequency (long m_lAvailFrequency;) - fixedData.m_lAvailFrequency = AAssit.ReadFromBinaryOf(fp, ref readBytes); + // Choose one subtask (bool m_bChooseOne;) + fixedData.m_bChooseOne = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; - // Period limit (long m_lPeriodLimit;) - fixedData.m_lPeriodLimit = AAssit.ReadFromBinaryOf(fp, ref readBytes); + // Random one subtask (bool m_bRandOne;) + fixedData.m_bRandOne = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; + + // bool m_bExeChildInOrder; + // Whether subtasks are executed in order + fixedData.m_bExeChildInOrder = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; // 是否子任务有顺序 // Whether subtasks are executed in order - // Choose one subtask (bool m_bChooseOne;) - fixedData.m_bChooseOne = AAssit.ReadFromBinaryOf(fp, ref readBytes); + // bool m_bParentAlsoFail; + // Whether the parent task fails if this one does + fixedData.m_bParentAlsoFail = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; // 失败后是否认为父任务也失败 // Whether the parent task fails if this one does + + // Whether parent task succeeds after subtask succeeds + // bool m_bParentAlsoSucc; + fixedData.m_bParentAlsoSucc = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; // 子任务成功后父任务成功 // Whether parent task succeeds after subtask succeeds - // Random one subtask (bool m_bRandOne;) - fixedData.m_bRandOne = AAssit.ReadFromBinaryOf(fp, ref readBytes); + // Whether this task can be abandoned + // bool m_bCanGiveUp; + fixedData.m_bCanGiveUp = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; // 能否放弃此任务 // Whether this task can be abandoned + + // Whether the task can be repeated/completed again + // bool m_bCanRedo; + fixedData.m_bCanRedo = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; // 是否可重复完成 // Whether the task can be repeated/completed again + + // Whether task can be repeated after failure + // bool m_bCanRedoAfterFailure; + fixedData.m_bCanRedoAfterFailure = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; // 失败后是否可重新完成 // Whether task can be repeated after failure + + // Give up clears the task + // bool m_bClearAsGiveUp; + fixedData.m_bClearAsGiveUp = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; // 放弃清空任务 // Give up clears the task + + // Whether recording is needed + // bool m_bNeedRecord; + fixedData.m_bNeedRecord = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; // 是否需要记录 // Whether recording is needed + + // Player's death causes failure + // bool m_bFailAsPlayerDie; + fixedData.m_bFailAsPlayerDie = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; // 玩家被击杀是否认为失败 // Player's death causes failure + + // Maximum number of receivers + // unsigned long m_ulMaxReceiver; + fixedData.m_ulMaxReceiver = AAssit.ReadFromBinaryOf(fp, ref readBytes); // 接受者上限 // Maximum number of receivers + + // Is in delivery zone + // bool m_bDelvInZone; + fixedData.m_bDelvInZone = AAssit.ReadFromBinaryOf(fp, ref readBytes) > 0; // 发放区域 // Is in delivery zone + + // Delivery world id + // unsigned long m_ulDelvWorld; + fixedData.m_ulDelvWorld = AAssit.ReadFromBinaryOf(fp, ref readBytes); // 发放世界 // Delivery world id + + // Number of delivery regions + // unsigned long m_ulDelvRegionCnt; + fixedData.m_ulDelvRegionCnt = AAssit.ReadFromBinaryOf(fp, ref readBytes); // 发放区域计数 // Number of delivery regions + + fp.Seek(originalPos, SeekOrigin.Begin); + return; }