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,120 @@
// Package fatigue owns daily fatigue-limit reconciliation rules shared by
// character selection and live account-entitlement activation.
package fatigue
const (
DefaultLimit int64 = 156
BlackDiamondLimit int64 = 188
FatigueBatteryStatKey = "fatigue_battery"
FatigueBatteryChargeStatKey = "fatigue_battery_charge"
FatigueBatteryChargeLimit int64 = 20000
FatigueBatteryActivation int64 = 156
FatigueBatteryPerBuff int64 = 5
FatigueBatteryDayCapacity1 int64 = 78
FatigueBatteryDayCapacity2 int64 = 117
FatigueBatteryDayCapacity3 int64 = 156
FatigueBatteryDayCapacity4 int64 = 234
)
// RemainingStat reads a character's remaining fatigue out of its stats map.
//
// Exported because more than one projection needs the same number the dungeon
// entry path consumes: the op7 mode-10 peer prompt renders 剩余疲劳值, and
// re-listing the keys at that call site is how the two would drift apart. See
// remainingStat for the legacy spellings it also accepts.
func RemainingStat(stats map[string]int64) (int64, bool) {
return remainingStat(stats)
}
// BatteryBuffCount is the native counter: the tooltip displays count - 1.
// sub_2691300 also disables the bonus at the current client's level cap.
func BatteryBuffCount(remaining int64, level int, roomActive bool) uint16 {
if level >= 90 {
return 0
}
remaining = min(max(remaining, 0), BatteryCapacity(level))
if remaining == 0 && !roomActive {
return 0
}
return uint16(remaining + 1)
}
// BatteryCapacity returns the PVF fatigue-battery display capacity for a
// character level. The level bands are the 99-entry serverparameter table:
// 1-19, 20-29, 30-39, and 40+.
func BatteryCapacity(level int) int64 {
switch {
case level >= 40:
return FatigueBatteryDayCapacity4
case level >= 30:
return FatigueBatteryDayCapacity3
case level >= 20:
return FatigueBatteryDayCapacity2
case level > 0:
return FatigueBatteryDayCapacity1
default:
// Legacy records without a level must not be truncated during migration.
return FatigueBatteryDayCapacity4
}
}
// Consume deducts up to amount from the persisted remaining fatigue without
// allowing a negative value. The consumed return value is the exact durable
// delta and is zero for exhausted characters or non-positive requests.
func Consume(remaining, amount int64) (next, consumed int64) {
if remaining < 0 {
remaining = 0
}
if amount <= 0 || remaining == 0 {
return remaining, 0
}
if amount > remaining {
amount = remaining
}
return remaining - amount, amount
}
// DesiredBlackDiamondLimit changes only the two known native membership
// limits. Custom/event limits are preserved instead of being overwritten.
func DesiredBlackDiamondLimit(current int64, active bool) int64 {
if current <= 0 {
current = DefaultLimit
}
if active && current == DefaultLimit {
return BlackDiamondLimit
}
if !active && current == BlackDiamondLimit {
return DefaultLimit
}
return current
}
// ReconcileLimit preserves consumed fatigue while switching the maximum.
// Example: 120/156 -> 152/188 -> 120/156.
func ReconcileLimit(remaining, currentLimit, desiredLimit int64) (int64, int64, bool) {
if desiredLimit <= 0 {
return remaining, currentLimit, false
}
originalRemaining, originalLimit := remaining, currentLimit
if currentLimit <= 0 {
currentLimit = DefaultLimit
}
if remaining < 0 {
remaining = 0
}
if remaining > currentLimit {
remaining = currentLimit
}
if currentLimit == desiredLimit {
return remaining, currentLimit, remaining != originalRemaining || currentLimit != originalLimit
}
used := currentLimit - remaining
if used < 0 {
used = 0
}
nextRemaining := desiredLimit - used
if nextRemaining < 0 {
nextRemaining = 0
}
return nextRemaining, desiredLimit, true
}