fix convert task data

This commit is contained in:
NguyenVanDat
2025-10-10 16:04:14 +07:00
parent 2883bef8fd
commit 2ecdf4d0db
3 changed files with 142 additions and 66 deletions
+29 -4
View File
@@ -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<uint>(fp, ref readBytes);
fixedData.m_bHasSign = AAssit.ReadFromBinaryOf<bool>(fp, ref readBytes);
// Special case for bool: read as byte and compare with > 0
fixedData.m_bHasSign = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0;
fixedData.m_bChooseOne = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0;
// Other primitive types
fixedData.m_lAvailFrequency = AAssit.ReadFromBinaryOf<int>(fp, ref readBytes);
fixedData.m_fLibraryTasksProbability = AAssit.ReadFromBinaryOf<float>(fp, ref readBytes);
```
**Rule**: Use `AAssit.ReadFromBinaryOf<T>(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<byte>(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<bool>(fp, ref readBytes);
// First read the flag/count (read bool as byte and convert with > 0)
fixedData.m_bHasSign = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0;
// Skip the pointer (Case 3)
fp.Seek(4, SeekOrigin.Current);
@@ -250,6 +261,20 @@ public static T[] ReadArrayFromBinary<T>(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<bool>(fp, ref readBytes); // Wrong!
```
✅ **Correct**:
```csharp
// Read as byte and compare with > 0
fixedData.m_bHasSign = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0; // Correct!
```
---
❌ **Wrong**: Skipping pointer size instead of basic type size for Case 5
```csharp
// C++: ushort* m_pszSignature
+1 -1
View File
@@ -70,7 +70,7 @@ namespace PerfectWorld.Scripts.Task
pOffs = AAssit.ReadArrayFromBinary<uint>(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);
+112 -61
View File
@@ -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<uint>(fp, ref readBytes); // unsigned long m_ID;
BMLogger.Log($"LoadFixedDataFromBinFile: {fixedData.m_ID}");
var originalPos = fp.Position;
// Task ID
fixedData.m_ID = AAssit.ReadFromBinaryOf<uint>(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<ushort>(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<ushort>(fp, TaskTemplConstants.MAX_TASK_NAME_LEN, ref readBytes); //64
// Has Signature (bool m_bHasSign;)
fixedData.m_bHasSign = AAssit.ReadFromBinaryOf<bool>(fp, ref readBytes);
Debug.LogError($"m_bHasSign: {fixedData.m_bHasSign}");
// Has Signature (bool m_bHasSign;)
fixedData.m_bHasSign = AAssit.ReadFromBinaryOf<byte>(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<uint>(fp, ref readBytes);
// Debug.LogError($"Type: {fixedData.m_ulType}");
// Task Type (unsigned long m_ulType;)
fixedData.m_ulType = AAssit.ReadFromBinaryOf<uint>(fp, ref readBytes);//value 103
BMLogger.LogError($"Type: {fixedData.m_ulType}");
// Time Limit (unsigned long m_ulTimeLimit;)
fixedData.m_ulTimeLimit = AAssit.ReadFromBinaryOf<uint>(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<byte>(fp, ref readBytes) > 0;
// Time Limit (unsigned long m_ulTimeLimit;)
fixedData.m_ulTimeLimit = AAssit.ReadFromBinaryOf<uint>(fp, ref readBytes);
// Absolute Fail (bool m_bAbsFail;)
fixedData.m_bAbsFail = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0;
// Offline Fail (bool m_bOfflineFail;)
fixedData.m_bOfflineFail = AAssit.ReadFromBinaryOf<bool>(fp, ref readBytes);
// Absolute Fail Time (task_tm m_tmAbsFailTime;)
fixedData.m_tmAbsFailTime = AAssit.ReadFromBinaryOf<task_tm>(fp, ref readBytes);
// Absolute Fail (bool m_bAbsFail;)
fixedData.m_bAbsFail = AAssit.ReadFromBinaryOf<bool>(fp, ref readBytes);
// (unsigned long m_ulAbsFailTime;) // commented out in C++ source
// Absolute Fail Time (task_tm m_tmAbsFailTime;)
fixedData.m_tmAbsFailTime = AAssit.ReadFromBinaryOf<task_tm>(fp, ref readBytes);
// Item Not Take Off (bool m_bItemNotTakeOff;)
fixedData.m_bItemNotTakeOff = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0;
// (unsigned long m_ulAbsFailTime;) // commented out in C++ source
// Absolute Time (bool m_bAbsTime;)
fixedData.m_bAbsTime = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0;
// Item Not Take Off (bool m_bItemNotTakeOff;)
fixedData.m_bItemNotTakeOff = AAssit.ReadFromBinaryOf<bool>(fp, ref readBytes);
// Timetable count (unsigned long m_ulTimetable;)
fixedData.m_ulTimetable = AAssit.ReadFromBinaryOf<uint>(fp, ref readBytes);
// Absolute Time (bool m_bAbsTime;)
fixedData.m_bAbsTime = AAssit.ReadFromBinaryOf<bool>(fp, ref readBytes);
// Timetable type (char m_tmType[MAX_TIMETABLE_SIZE];)
fixedData.m_tmType = AAssit.ReadArrayFromBinary<byte>(fp, TaskTemplConstants.MAX_TIMETABLE_SIZE, ref readBytes);
// Timetable count (unsigned long m_ulTimetable;)
fixedData.m_ulTimetable = AAssit.ReadFromBinaryOf<uint>(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<byte>(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<int>(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<int>(fp, ref readBytes);
// Available frequency (long m_lAvailFrequency;)
fixedData.m_lAvailFrequency = AAssit.ReadFromBinaryOf<int>(fp, ref readBytes);
// Choose one subtask (bool m_bChooseOne;)
fixedData.m_bChooseOne = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0;
// Period limit (long m_lPeriodLimit;)
fixedData.m_lPeriodLimit = AAssit.ReadFromBinaryOf<int>(fp, ref readBytes);
// Random one subtask (bool m_bRandOne;)
fixedData.m_bRandOne = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0;
// bool m_bExeChildInOrder;
// Whether subtasks are executed in order
fixedData.m_bExeChildInOrder = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0; // 是否子任务有顺序 // Whether subtasks are executed in order
// Choose one subtask (bool m_bChooseOne;)
fixedData.m_bChooseOne = AAssit.ReadFromBinaryOf<bool>(fp, ref readBytes);
// bool m_bParentAlsoFail;
// Whether the parent task fails if this one does
fixedData.m_bParentAlsoFail = AAssit.ReadFromBinaryOf<byte>(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<byte>(fp, ref readBytes) > 0; // 子任务成功后父任务成功 // Whether parent task succeeds after subtask succeeds
// Random one subtask (bool m_bRandOne;)
fixedData.m_bRandOne = AAssit.ReadFromBinaryOf<bool>(fp, ref readBytes);
// Whether this task can be abandoned
// bool m_bCanGiveUp;
fixedData.m_bCanGiveUp = AAssit.ReadFromBinaryOf<byte>(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<byte>(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<byte>(fp, ref readBytes) > 0; // 失败后是否可重新完成 // Whether task can be repeated after failure
// Give up clears the task
// bool m_bClearAsGiveUp;
fixedData.m_bClearAsGiveUp = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0; // 放弃清空任务 // Give up clears the task
// Whether recording is needed
// bool m_bNeedRecord;
fixedData.m_bNeedRecord = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0; // 是否需要记录 // Whether recording is needed
// Player's death causes failure
// bool m_bFailAsPlayerDie;
fixedData.m_bFailAsPlayerDie = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0; // 玩家被击杀是否认为失败 // Player's death causes failure
// Maximum number of receivers
// unsigned long m_ulMaxReceiver;
fixedData.m_ulMaxReceiver = AAssit.ReadFromBinaryOf<uint>(fp, ref readBytes); // 接受者上限 // Maximum number of receivers
// Is in delivery zone
// bool m_bDelvInZone;
fixedData.m_bDelvInZone = AAssit.ReadFromBinaryOf<byte>(fp, ref readBytes) > 0; // 发放区域 // Is in delivery zone
// Delivery world id
// unsigned long m_ulDelvWorld;
fixedData.m_ulDelvWorld = AAssit.ReadFromBinaryOf<uint>(fp, ref readBytes); // 发放世界 // Delivery world id
// Number of delivery regions
// unsigned long m_ulDelvRegionCnt;
fixedData.m_ulDelvRegionCnt = AAssit.ReadFromBinaryOf<uint>(fp, ref readBytes); // 发放区域计数 // Number of delivery regions
fp.Seek(originalPos, SeekOrigin.Begin);
return;
}