289 lines
12 KiB
C#
289 lines
12 KiB
C#
using System;
|
||
using System.Runtime.InteropServices;
|
||
using CSNetwork.GPDataType;
|
||
|
||
namespace BrewMonster.UI
|
||
{
|
||
// Define and Macro from EC_GameUIMan.h
|
||
// 定义与宏
|
||
public static class EC_GameUIMan_Constants
|
||
{
|
||
// public const int LAYOUTDATA_VERSION = 15;
|
||
// #define CECGAMEUIMAN_MAX_MSGS 200
|
||
// #define CECGAMEUIMAN_MAX_BROKEN 8
|
||
// #define CECGAMEUIMAN_MAX_TASKHINT 6
|
||
|
||
public const int CECGAMEUIMAN_MAX_MARKS = 5;
|
||
public const int CECGAMEUIMAN_MARK_NAME_LEN = 8;
|
||
public const int CECGAMEUIMAN_MAX_GROUPS = 10;
|
||
public const int CECGAMEUIMAN_MAX_CHATS = 10;
|
||
public const int CECGAMEUIMAN_MAX_QSHOPITEMS = 8;
|
||
public const int CECGAMEUIMAN_MAX_FASHIONSHOPITEMS = 6;
|
||
|
||
/// <summary>
|
||
/// C++ sizeof(USER_LAYOUT) with default packing (MSVC pack 8).
|
||
/// 与 C++ sizeof(USER_LAYOUT) 一致(MSVC 默认 pack 8)。
|
||
/// </summary>
|
||
public const int USER_LAYOUT_SIZE = 344;
|
||
}
|
||
|
||
// SAVE_MARK: saved mark (NPC, position, name)
|
||
// 保存的标记(NPC、位置、名称)
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public struct SAVE_MARK
|
||
{
|
||
public int nNPC;
|
||
public A3DVECTOR3 vecPos;
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_GameUIMan_Constants.CECGAMEUIMAN_MARK_NAME_LEN + 1)]
|
||
public ushort[] szName; // ACHAR in C++ (wchar_t) → ushort[]
|
||
}
|
||
|
||
// USER_LAYOUT_Flat: flat struct for binary serialization (total size 344 to match C++ sizeof).
|
||
// 扁平结构体,用于二进制序列化(总大小 344,与 C++ sizeof 一致)。
|
||
// Field order matches C++ EC_GameUIMan.h. Pack=1 + explicit padding for exact 344-byte output.
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public struct USER_LAYOUT_Flat
|
||
{
|
||
public sbyte nVersion;
|
||
public sbyte nMapMode;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bQuickbar1Mode;
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte[] bChecked1;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bQuickbar2Mode;
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] bChecked2;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bQuickbarPetMode;
|
||
public int nChatWinSize;
|
||
public int nCurChatColor;
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_MARKS)]
|
||
public SAVE_MARK[] a_Mark;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bOnlineNotify;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bAutoReply;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bSaveHistory;
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_GROUPS)]
|
||
public int[] idGroup;
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_GROUPS)]
|
||
public uint[] clrGroup;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bTraceAll;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bQuickbarShowAll1;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bQuickbarShowAll2;
|
||
public int nQuickbarCurPanel1, nQuickbarCurPanel2, nQuickbarDisplayPanels1, nQuickbarDisplayPanels2;
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_MARKS)]
|
||
public short[] a_MarkMapID;
|
||
public uint dwTraceMask;
|
||
public byte ucCurSystemModuleSC;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bSystemModuleQuickBarMini;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bMenuMode;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bShowCompareDesc;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bShowLowHP;
|
||
[MarshalAs(UnmanagedType.U1)] public bool bShowTargetOfTarget;
|
||
// Padding to reach C++ sizeof(USER_LAYOUT)=344 (C# Pack=1 yields 313, +31 padding)
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)]
|
||
public byte[] _padding;
|
||
}
|
||
|
||
// TASK_HINT: task hint data
|
||
// 任务提示数据
|
||
// TODO: ACString strHint is not inline in C++ (pointer); when reading from C++ binary skip ptr after dwTime and fill strHint separately.
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public struct TASK_HINT
|
||
{
|
||
public uint dwTime; // DWORD → uint
|
||
public string strHint;
|
||
}
|
||
|
||
// USER_LAYOUT_6: user layout version 6
|
||
// 用户布局版本 6
|
||
// Base for layout versions: common fields (v6 and v7 differ only by bChecked1 size).
|
||
// 布局版本基类:公共字段(v6 与 v7 仅 bChecked1 长度不同)
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public class USER_LAYOUT_Base
|
||
{
|
||
public sbyte nVersion; // __int8 → sbyte
|
||
public sbyte nMapMode;
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bQuickbar1Mode;
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bQuickbar2Mode;
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||
public byte[] bChecked2;
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bQuickbarPetMode;
|
||
public int nChatWinSize;
|
||
public int nCurChatColor;
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_MARKS)]
|
||
public SAVE_MARK[] a_Mark;
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bOnlineNotify;
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bAutoReply;
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bSaveHistory;
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_GROUPS)]
|
||
public int[] idGroup;
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_GROUPS)]
|
||
public uint[] clrGroup; // A3DCOLOR (DWORD) → uint
|
||
}
|
||
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public class USER_LAYOUT_6 : USER_LAYOUT_Base
|
||
{
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||
public byte[] bChecked1;
|
||
}
|
||
|
||
// USER_LAYOUT_7: user layout version 7 (bChecked1[5]); base for v8–current
|
||
// 用户布局版本 7(bChecked1[5]);v8 至当前版本的基类
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public class USER_LAYOUT_7 : USER_LAYOUT_Base
|
||
{
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
|
||
public byte[] bChecked1;
|
||
}
|
||
|
||
// USER_LAYOUT_8: extends USER_LAYOUT_7
|
||
// 用户布局版本 8
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public class USER_LAYOUT_8 : USER_LAYOUT_7
|
||
{
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bTraceAll;
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bQuickbarShowAll1;
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bQuickbarShowAll2;
|
||
public int nQuickbarCurPanel1;
|
||
public int nQuickbarCurPanel2;
|
||
public int nQuickbarDisplayPanels1;
|
||
public int nQuickbarDisplayPanels2;
|
||
}
|
||
|
||
// USER_LAYOUT_9: extends USER_LAYOUT_8
|
||
// 用户布局版本 9
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public class USER_LAYOUT_9 : USER_LAYOUT_8
|
||
{
|
||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_MARKS)]
|
||
public short[] a_MarkMapID; // init to 1 per element in C++; caller must init in C#
|
||
}
|
||
|
||
// USER_LAYOUT_10: extends USER_LAYOUT_9
|
||
// 用户布局版本 10
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public class USER_LAYOUT_10 : USER_LAYOUT_9
|
||
{
|
||
public uint dwTraceMask; // DWORD → uint; init 0
|
||
}
|
||
|
||
// USER_LAYOUT_11: extends USER_LAYOUT_10
|
||
// 用户布局版本 11
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public class USER_LAYOUT_11 : USER_LAYOUT_10
|
||
{
|
||
public byte ucCurSystemModuleSC; // unsigned char → byte; init 0
|
||
}
|
||
|
||
// USER_LAYOUT_12: extends USER_LAYOUT_11
|
||
// 用户布局版本 12
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public class USER_LAYOUT_12 : USER_LAYOUT_11
|
||
{
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bSystemModuleQuickBarMini; // init false
|
||
}
|
||
|
||
// USER_LAYOUT_13: extends USER_LAYOUT_12
|
||
// 用户布局版本 13
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public class USER_LAYOUT_13 : USER_LAYOUT_12
|
||
{
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bMenuMode; // init false
|
||
}
|
||
|
||
// USER_LAYOUT_14: extends USER_LAYOUT_13
|
||
// 用户布局版本 14
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public class USER_LAYOUT_14 : USER_LAYOUT_13
|
||
{
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bShowCompareDesc; // init true
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bShowLowHP; // init true
|
||
}
|
||
|
||
// USER_LAYOUT: current user layout (extends USER_LAYOUT_14)
|
||
// 当前用户布局
|
||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
public class USER_LAYOUT : USER_LAYOUT_14
|
||
{
|
||
[MarshalAs(UnmanagedType.U1)]
|
||
public bool bShowTargetOfTarget; // init true
|
||
|
||
/// <summary>
|
||
/// Serializes this USER_LAYOUT to a byte array (344 bytes to match C++ sizeof(USER_LAYOUT)).
|
||
/// 序列化为字节数组(344 字节,与 C++ sizeof(USER_LAYOUT) 一致)。
|
||
/// </summary>
|
||
public byte[] ToBytes()
|
||
{
|
||
USER_LAYOUT_Flat flat = ToFlat();
|
||
byte[] bytes = new byte[EC_GameUIMan_Constants.USER_LAYOUT_SIZE];
|
||
IntPtr ptr = Marshal.AllocHGlobal(EC_GameUIMan_Constants.USER_LAYOUT_SIZE);
|
||
try
|
||
{
|
||
Marshal.StructureToPtr(flat, ptr, false);
|
||
Marshal.Copy(ptr, bytes, 0, EC_GameUIMan_Constants.USER_LAYOUT_SIZE);
|
||
return bytes;
|
||
}
|
||
finally
|
||
{
|
||
Marshal.FreeHGlobal(ptr);
|
||
}
|
||
}
|
||
|
||
/// <summary>Converts this USER_LAYOUT to USER_LAYOUT_Flat for binary serialization.</summary>
|
||
public USER_LAYOUT_Flat ToFlat()
|
||
{
|
||
var flat = new USER_LAYOUT_Flat
|
||
{
|
||
nVersion = nVersion,
|
||
nMapMode = nMapMode,
|
||
bQuickbar1Mode = bQuickbar1Mode,
|
||
bChecked1 = bChecked1 ?? new byte[5],
|
||
bQuickbar2Mode = bQuickbar2Mode,
|
||
bChecked2 = bChecked2 ?? new byte[3],
|
||
bQuickbarPetMode = bQuickbarPetMode,
|
||
nChatWinSize = nChatWinSize,
|
||
nCurChatColor = nCurChatColor,
|
||
a_Mark = a_Mark ?? new SAVE_MARK[EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_MARKS],
|
||
bOnlineNotify = bOnlineNotify,
|
||
bAutoReply = bAutoReply,
|
||
bSaveHistory = bSaveHistory,
|
||
idGroup = idGroup ?? new int[EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_GROUPS],
|
||
clrGroup = clrGroup ?? new uint[EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_GROUPS],
|
||
bTraceAll = bTraceAll,
|
||
bQuickbarShowAll1 = bQuickbarShowAll1,
|
||
bQuickbarShowAll2 = bQuickbarShowAll2,
|
||
nQuickbarCurPanel1 = nQuickbarCurPanel1,
|
||
nQuickbarCurPanel2 = nQuickbarCurPanel2,
|
||
nQuickbarDisplayPanels1 = nQuickbarDisplayPanels1,
|
||
nQuickbarDisplayPanels2 = nQuickbarDisplayPanels2,
|
||
a_MarkMapID = a_MarkMapID ?? new short[EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_MARKS],
|
||
dwTraceMask = dwTraceMask,
|
||
ucCurSystemModuleSC = ucCurSystemModuleSC,
|
||
bSystemModuleQuickBarMini = bSystemModuleQuickBarMini,
|
||
bMenuMode = bMenuMode,
|
||
bShowCompareDesc = bShowCompareDesc,
|
||
bShowLowHP = bShowLowHP,
|
||
bShowTargetOfTarget = bShowTargetOfTarget,
|
||
_padding = new byte[31]
|
||
};
|
||
// Ensure a_Mark elements have szName initialized
|
||
for (int i = 0; i < flat.a_Mark.Length; i++)
|
||
{
|
||
if (flat.a_Mark[i].szName == null)
|
||
flat.a_Mark[i].szName = new ushort[EC_GameUIMan_Constants.CECGAMEUIMAN_MARK_NAME_LEN + 1];
|
||
}
|
||
return flat;
|
||
}
|
||
}
|
||
}
|