DNF90 服务端与启动器完整源码(含 GM 工具功能增强)
服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
This commit is contained in:
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
|
||||
Reference in new issue
Block a user