DNF90 服务端与启动器完整源码(含 GM 工具功能增强)

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

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

No files matched your search

+306
View File
@@ -0,0 +1,306 @@
#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);