Files
2026-03-12 13:50:41 +07:00

289 lines
12 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 v8current
// 用户布局版本 7bChecked1[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;
}
}
}