Files
hanfuit 645b64fe21 DNF90 服务端与启动器完整源码(含 GM 工具功能增强)
服务端(Go):
- GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面
- GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新
- 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新)
- 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍
- 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0)
- 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算

启动器(Python/JS):
- 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭
- GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐)
- 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
2026-11-04 14:31:55 +08:00

307 lines
13 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.
#pragma once
#include <windows.h>
// Starts the one-time current-EXE cipher proxy after 86JP.dll is loaded by
// the normal ijl15 plugin chain.
void Start90CNPatch();
// Returns true when the loaded executable is the separately supported
// 2026-10 new client. That executable has a different native layout and
// must enter the narrow channel bootstrap worker instead of the production
// hook set built for the current NoPack client.
bool IsNewClientCompatibilityMode();
// Starts the new-client channel selector/connector worker. It waits for the
// native directory object, selects the configured local channel, and invokes
// the client's own endpoint handler; it does not synthesize packets.
void StartNewClientChannelCompatibility();
// 接口名称:Queue90CNClientNotice
// 中文说明:把一条 UTF-16 游戏提示复制到 90CN 主线程队列,并唤醒游戏窗口线程。
// 参数:text 为不包含内嵌 NUL 的文本;length 为字符数,不包含结尾 NUL,最大 511。
// 返回值:TRUE 表示已经安全入队;FALSE 表示接口未就绪、参数无效或队列已满。
// 线程约束:调用者不会直接执行游戏 UI;实际提示只在 DNF 主窗口线程中显示。
EXTERN_C BOOL WINAPI Queue90CNClientNotice(
const wchar_t* text, unsigned int length);
// 客户端事件类型:只表示已经由当前 EXE 的窗口或场景切换边界可靠确认的状态。
enum DNF90ClientEventType : unsigned int
{
DNF90_CLIENT_EVENT_UI_READY = 1,
DNF90_CLIENT_EVENT_UI_CLOSED = 2,
DNF90_CLIENT_EVENT_ENTER_TOWN = 3,
// 事件名称:enter_dungeon
// 中文说明:当前 EXE 完成副本信息、首张地图和当前角色激活后产生一次。
DNF90_CLIENT_EVENT_ENTER_DUNGEON = 4,
// 事件名称:dungeon_room_changed
// 中文说明:副本活动态接受一个与上次不同的完整 op29 房间后产生一次。
DNF90_CLIENT_EVENT_DUNGEON_ROOM_CHANGED = 5,
// 事件名称:leave_dungeon
// 中文说明:副本活动态接受最终回城 op24 时,在 enter_town 前产生一次。
DNF90_CLIENT_EVENT_LEAVE_DUNGEON = 6,
};
// 上下文标志名称:DNF90ClientEventContextFlag
// 中文说明:说明追加字段中哪些值已经由当前 EXE 的完整 typed 包可靠确认。
enum DNF90ClientEventContextFlag : unsigned int
{
DNF90_CLIENT_EVENT_CONTEXT_DUNGEON_VALID = 1u << 0,
DNF90_CLIENT_EVENT_CONTEXT_ROOM_VALID = 1u << 1,
DNF90_CLIENT_EVENT_CONTEXT_PREVIOUS_ROOM_VALID = 1u << 2,
DNF90_CLIENT_EVENT_CONTEXT_BOSS_ROOM = 1u << 3,
};
// 兼容常量名称:DNF90_CLIENT_EVENT_V1_SIZE
// 中文说明:旧版事件只有前五个字段;新旧 DLL 通过该固定前缀双向兼容。
constexpr unsigned int DNF90_CLIENT_EVENT_V1_SIZE =
5u * sizeof(unsigned int);
// 结构名称:DNF90ClientEvent
// 中文说明:90CN.dll 复制到固定容量队列中的客户端生命周期事件。
// 字段:size 为结构大小;type 为 DNF90ClientEventType;sequence 为进程内递增编号;
// processID 为客户端进程;uiThreadID 为确认该事件的 DNF UI 线程;
// contextFlags 决定后续副本字段是否有效;previousRoom* 只用于换房事件。
struct DNF90ClientEvent
{
unsigned int size;
unsigned int type;
unsigned int sequence;
unsigned int processID;
unsigned int uiThreadID;
unsigned int contextFlags;
unsigned int dungeonID;
unsigned int roomX;
unsigned int roomY;
unsigned int roomLayerFlag;
unsigned int mapID;
unsigned int previousRoomX;
unsigned int previousRoomY;
unsigned int previousRoomLayerFlag;
unsigned int previousMapID;
};
static_assert(sizeof(DNF90ClientEvent) == 60,
"DNF90ClientEvent append-only ABI size changed unexpectedly");
// 接口名称:Dequeue90CNClientEvent
// 中文说明:从 90CN.dll 的固定容量队列中取出一条客户端生命周期事件。
// 参数:output 指向调用者提供的可写结构;outputSize 至少为 DNF90_CLIENT_EVENT_V1_SIZE。
// 旧调用者只取得 20 字节稳定前缀;当前调用者取得完整追加字段。
// 返回值:TRUE 表示取出一条完整事件;FALSE 表示参数无效或当前队列为空。
// 线程约束:本接口只复制事件数据,不调用 Lua,也不执行游戏 UI。
EXTERN_C BOOL WINAPI Dequeue90CNClientEvent(
DNF90ClientEvent* output, unsigned int outputSize);
// 有效标志名称:DNF90CharacterStatSnapshotFlag
// 中文说明:标记角色属性快照中已经由当前 EXE 的完整 class0/op2 包可靠取得的数据。
enum DNF90CharacterStatSnapshotFlag : unsigned int
{
DNF90_CHARACTER_STATS_BASE_VALID = 1u << 0,
DNF90_CHARACTER_STATS_SPEED_VALID = 1u << 1,
};
// 结构名称:DNF90CharacterStatSnapshot
// 中文说明:从当前 EXE 已成功处理的 92 字节角色状态块中复制出的只读快照。
// 字段:generation 每次收到有效 mode1/mode3 状态块时递增;四维已经还原为游戏数值,
// 不再保留线上协议使用的十倍缩放;速度字段保持当前协议中的原始整数单位。
struct DNF90CharacterStatSnapshot
{
unsigned int size;
unsigned int generation;
unsigned int validFlags;
unsigned int hpMax;
unsigned int mpMax;
int strength;
int vitality;
int intelligence;
int spirit;
unsigned int moveSpeed;
unsigned int attackSpeed;
unsigned int castSpeed;
};
static_assert(sizeof(DNF90CharacterStatSnapshot) == 48,
"DNF90CharacterStatSnapshot append-only ABI size changed unexpectedly");
// 接口名称:Query90CNCharacterStatSnapshot
// 中文说明:读取最近一次可靠角色属性快照,供独立 Lua DLL 计算战斗力。
// 参数:output 指向调用者提供的可写结构;outputSize 必须能容纳当前完整结构。
// 返回值:TRUE 表示已复制有效快照;FALSE 表示尚未收到角色数据或参数无效。
// 线程约束:只在 SRW 锁内复制普通数据,不读取游戏对象,也不执行游戏 UI。
EXTERN_C BOOL WINAPI Query90CNCharacterStatSnapshot(
DNF90CharacterStatSnapshot* output, unsigned int outputSize);
// 装备快照常量名称:DNF90_EQUIPMENT_SNAPSHOT_MAX_ITEMS
// 中文说明:当前 EXE 的穿戴对象位图覆盖槽位 0~32;快照按已出现对象保存,
// 因而最多需要 33 条,不会读取或虚构这个范围以外的槽位。
enum : unsigned int
{
DNF90_EQUIPMENT_SNAPSHOT_MAX_ITEMS = 33,
};
// 有效标志名称:DNF90EquipmentSnapshotFlag
// 中文说明:标记装备快照已经由当前 EXE 完整接受的 class0/op2 mode1/mode3
// 穿戴对象创建列表可靠取得。
enum DNF90EquipmentSnapshotFlag : unsigned int
{
DNF90_EQUIPMENT_SNAPSHOT_ROWS_VALID = 1u << 0,
};
// 结构名称:DNF90EquippedItemSnapshot
// 中文说明:一件已穿戴对象的只读线协议摘要。
// 字段:actorSlot 是当前 EXE 的运行时穿戴槽;upgradeLevel 来自 extData 低五位;
// amplifyType 与 amplifyValue 来自同一条已验证 0x77 状态投影。
// 边界:itemID/qualitySeed 只作为身份与换装变化证据;PVF 词条由服务端权威投影提供,
// Lua 不凭线协议 ID 猜稀有度或词条。
struct DNF90EquippedItemSnapshot
{
unsigned int itemID;
unsigned int qualitySeed;
unsigned short durability;
unsigned short amplifyValue;
unsigned char actorSlot;
unsigned char upgradeLevel;
unsigned char amplifyType;
unsigned char reserved;
};
static_assert(sizeof(DNF90EquippedItemSnapshot) == 16,
"DNF90EquippedItemSnapshot append-only ABI size changed unexpectedly");
// 结构名称:DNF90EquipmentSnapshot
// 中文说明:最近一次本地角色完整穿戴对象创建列表的固定容量只读副本。
// 字段:generation 每次接受完整列表时递增;sourceStatGeneration 对应同包属性版本;
// itemCount 仅说明 items 前多少条有效,允许为零以表示确实没有穿戴对象。
struct DNF90EquipmentSnapshot
{
unsigned int size;
unsigned int generation;
unsigned int sourceStatGeneration;
unsigned int validFlags;
unsigned int itemCount;
DNF90EquippedItemSnapshot items[DNF90_EQUIPMENT_SNAPSHOT_MAX_ITEMS];
};
static_assert(sizeof(DNF90EquipmentSnapshot) == 548,
"DNF90EquipmentSnapshot append-only ABI size changed unexpectedly");
// 接口名称:Query90CNEquipmentSnapshot
// 中文说明:读取最近一次可靠装备快照,供独立 Lua DLL 计算装备加成。
// 参数:output 指向调用者提供的可写结构;outputSize 必须能容纳当前完整结构。
// 返回值:TRUE 表示已复制有效快照;FALSE 表示尚未收到完整列表或参数无效。
// 线程约束:只在 SRW 锁内复制普通数据,不读取游戏对象,也不执行游戏 UI。
EXTERN_C BOOL WINAPI Query90CNEquipmentSnapshot(
DNF90EquipmentSnapshot* output, unsigned int outputSize);
// 有效标志名称:DNF90DamageAffixSnapshotFlag
// 中文说明:标记伤害词条快照已由服务端按当前 Script.pvf 与完整穿戴位图计算完成。
enum DNF90DamageAffixSnapshotFlag : unsigned int
{
DNF90_DAMAGE_AFFIX_SNAPSHOT_VALUES_VALID = 1u << 0,
DNF90_DAMAGE_AFFIX_SNAPSHOT_IDENTITY_VALID = 1u << 1,
DNF90_DAMAGE_AFFIX_SNAPSHOT_THREE_ATTACKS_VALID = 1u << 2,
DNF90_DAMAGE_AFFIX_SNAPSHOT_EQUIPMENT_SCORE_VALID = 1u << 3,
};
// 结构名称:DNF90DamageAffixSnapshot
// 中文说明:服务端从当前 Script.pvf 汇总的穿戴词条只读快照;所有百分比以 0.1% 为单位。
// 字段说明:whiteDamageTenths=白字(附加伤害),yellowDamageTenths=黄字(对敌人伤害增加),
// criticalDamageTenths=爆伤(暴击伤害);黄追和爆追始终单独保存,不能冒充前三项;
// allAttackTenths=所有攻击力/最终伤害,只并入三攻加成;
// pvfEquipmentScore=服务端按 PVF 等级、品级和稀有度计算的装备基础分。
struct DNF90DamageAffixSnapshot
{
unsigned int size;
unsigned int generation;
unsigned int validFlags;
unsigned int version;
unsigned int whiteDamageTenths;
unsigned int yellowDamageTenths;
unsigned int criticalDamageTenths;
unsigned int yellowAdditionalTenths;
unsigned int criticalAdditionalTenths;
unsigned int allAttackTenths;
unsigned int equippedItemCount;
unsigned int activeSetCount;
unsigned int job;
unsigned int growType;
unsigned int level;
unsigned int physicalAttack;
unsigned int magicalAttack;
unsigned int independentAttack;
char professionUtf8[32];
unsigned int pvfEquipmentScore;
};
static_assert(sizeof(DNF90DamageAffixSnapshot) == 108,
"DNF90DamageAffixSnapshot append-only ABI size changed unexpectedly");
// 接口名称:Query90CNDamageAffixSnapshot
// 中文说明:读取服务端按 PVF 汇总的完整穿戴词条,供独立 Lua DLL 计算并显示战斗力。
// 参数:output 为调用方可写结构;outputSize 必须容纳完整结构。
// 返回值:TRUE 表示已有有效快照;FALSE 表示尚未收到投影或参数无效。
EXTERN_C BOOL WINAPI Query90CNDamageAffixSnapshot(
DNF90DamageAffixSnapshot* output, unsigned int outputSize);
// 有效标志名称:DNF90CombatPanelStateFlag
// 中文说明:说明 Lua 提交的战斗力面板中哪些分项已经有真实数据来源。
enum DNF90CombatPanelStateFlag : unsigned int
{
DNF90_COMBAT_PANEL_ENABLED = 1u << 0,
DNF90_COMBAT_PANEL_BASE_SCORE_VALID = 1u << 1,
DNF90_COMBAT_PANEL_EQUIPMENT_SCORE_VALID = 1u << 2,
DNF90_COMBAT_PANEL_DAMAGE_AFFIXES_VALID = 1u << 3,
DNF90_COMBAT_PANEL_IDENTITY_VALID = 1u << 4,
DNF90_COMBAT_PANEL_THREE_ATTACKS_VALID = 1u << 5,
};
// 结构名称:DNF90CombatPanelState
// 中文说明:Lua 完成公式计算后交给主 DLL 绘制的纯数据状态。
// 字段:sourceGeneration 对应属性快照版本;formulaVersion 用于区分将来的公式升级;
// equipmentScore 只有在对应有效标志存在时才允许显示为数值。
struct DNF90CombatPanelState
{
unsigned int size;
unsigned int revision;
unsigned int sourceGeneration;
unsigned int validFlags;
unsigned int formulaVersion;
unsigned int totalScore;
unsigned int baseAttributeScore;
unsigned int equipmentScore;
unsigned int hpMax;
unsigned int mpMax;
int strength;
int vitality;
int intelligence;
int spirit;
unsigned int affixGeneration;
unsigned int whiteDamageTenths;
unsigned int yellowDamageTenths;
unsigned int criticalDamageTenths;
unsigned int yellowAdditionalTenths;
unsigned int criticalAdditionalTenths;
unsigned int allAttackTenths;
unsigned int equippedItemCount;
unsigned int activeSetCount;
unsigned int job;
unsigned int growType;
unsigned int level;
unsigned int physicalAttack;
unsigned int magicalAttack;
unsigned int independentAttack;
char professionUtf8[32];
};
static_assert(sizeof(DNF90CombatPanelState) == 148,
"DNF90CombatPanelState append-only ABI size changed unexpectedly");
// 接口名称:Update90CNCombatPanel
// 中文说明:复制 Lua 已计算好的面板状态,并唤醒 DNF UI 线程刷新侧栏。
// 参数:state 指向只读状态;stateSize 必须等于当前完整结构大小。
// 返回值:TRUE 表示已安全接收;FALSE 表示接口未就绪、参数无效或数值越界。
// 线程约束:调用者不直接绘制;所有窗口显示、隐藏和重绘均在 DNF UI 线程执行。
EXTERN_C BOOL WINAPI Update90CNCombatPanel(
const DNF90CombatPanelState* state, unsigned int stateSize);