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

@@ -0,0 +1,122 @@
#pragma once
namespace dnf90_first_login_recovery {
constexpr long kMaxFirstLoginRecoveryAttempts = 2;
inline bool IsFirstLoginServerProgressMessage(int messageType) {
return messageType == 1; // ENUM_CMDPACKET_LOGIN
}
inline bool IsFirstLoginClientProgressMessage(int messageType) {
switch (messageType) {
case 171: // ENUM_CMDPACKET_CLIENT_SPEC_STATISTIC
case 476: // ENUM_CMDPACKET_COMPATIBILITY_INDEX
case 1320: // ENUM_CMDPACKET_LOG_DOMAIN_CONNECT
case 1262: // ENUM_CMDPACKET_LOG_CONNECT_PROCESS
case 593: // ENUM_CMDPACKET_SECURITY_STATUS
case 8: // ENUM_CMDPACKET_GET_USERINFO
return true;
default:
return false;
}
}
// The auto-connect timer can run inside the native startup message pump.
// Opening a socket while the packet processor is uninitialized loses LOGIN:
// native 02261E30 returns 80000001, but 03456304 still consumes the packet.
constexpr unsigned int kPacketProcessorPollMs = 50;
constexpr unsigned long long kPacketProcessorWaitLimitMs = 30000;
enum class PacketProcessorReadiness { NotReady, Ready, ReadFailed };
enum class AutoConnectAction { Ignore, Wait, Connect, TimedOut, ReadFailed };
struct AutoConnectReadiness {
long generation = 0;
unsigned long long startedAt = 0;
bool pending = false;
bool waited = false;
void Begin(long newGeneration, unsigned long long now) {
generation = newGeneration;
startedAt = now;
pending = true;
waited = false;
}
void Cancel() { pending = false; }
AutoConnectAction Poll(long currentGeneration, unsigned long long now,
PacketProcessorReadiness readiness) {
if (!pending || generation != currentGeneration) {
return AutoConnectAction::Ignore;
}
if (readiness == PacketProcessorReadiness::ReadFailed) {
pending = false;
return AutoConnectAction::ReadFailed;
}
if (readiness == PacketProcessorReadiness::Ready) {
pending = false; // Claim exactly one connect for this directory.
return AutoConnectAction::Connect;
}
waited = true;
if (now - startedAt >= kPacketProcessorWaitLimitMs) {
pending = false;
return AutoConnectAction::TimedOut;
}
return AutoConnectAction::Wait;
}
};
struct WatchdogState {
long watchdogGeneration;
long currentGeneration;
bool active;
bool serverDataSeen;
bool clientDataSeen;
long recoveryCount;
};
inline bool ShouldRecover(const WatchdogState& state) {
// Native ChannelConnect success is only a transport candidate. The first
// login is healthy once the client emits any proved post-login progress.
// serverDataSeen is diagnostic only: a stale native socket can prevent the
// receive hook from observing LOGIN even when the server already sent it.
return state.active &&
state.recoveryCount < kMaxFirstLoginRecoveryAttempts &&
state.watchdogGeneration > 0 &&
state.currentGeneration == state.watchdogGeneration &&
!state.clientDataSeen;
}
inline bool ShouldRecoverAfterRejectedRetry(
long initialSuccessGeneration,
long retryGeneration,
bool clientDataSeen,
long recoveryCount,
bool retryConnected) {
return initialSuccessGeneration > 0 &&
retryGeneration > initialSuccessGeneration &&
!clientDataSeen &&
recoveryCount < kMaxFirstLoginRecoveryAttempts &&
!retryConnected;
}
inline bool ShouldForceReleaseStaleSocket(
bool residentResetSucceeded,
bool socketPresent) {
return residentResetSucceeded && socketPresent;
}
// A proved login must not permanently disable recovery after disconnect.
// Only a rejected later directory connect with no live transport may reset;
// a successful connect or a still-owned socket always remains native-owned.
inline bool ShouldRecoverDisconnectedRetry(long initialGeneration,
long retryGeneration, bool clientProgress, bool connected,
bool transportReadable, bool socketAbsent, long attempts) {
return initialGeneration > 0 && retryGeneration > initialGeneration &&
clientProgress && !connected && transportReadable && socketAbsent &&
attempts < kMaxFirstLoginRecoveryAttempts;
}
} // namespace dnf90_first_login_recovery