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;
///
/// C++ sizeof(USER_LAYOUT) with default packing (MSVC pack 8).
/// 与 C++ sizeof(USER_LAYOUT) 一致(MSVC 默认 pack 8)。
///
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
///
/// Serializes this USER_LAYOUT to a byte array (344 bytes to match C++ sizeof(USER_LAYOUT)).
/// 序列化为字节数组(344 字节,与 C++ sizeof(USER_LAYOUT) 一致)。
///
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);
}
}
/// Converts this USER_LAYOUT to USER_LAYOUT_Flat for binary serialization.
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;
}
}
}