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,76 @@
package dnfbridge
import "longheng.io/server/internal/modules/dnf/raid"
func (s *Service) runtimeRaidFiendWarConfig() (*raid.FiendWarConfig, error) {
s.raidFiendWarMu.Lock()
defer s.raidFiendWarMu.Unlock()
if s.raidFiendWar != nil || s.raidFiendWarErr != nil {
return s.raidFiendWar, s.raidFiendWarErr
}
s.initialEquipmentMu.Lock()
archive, err := s.initialEquipmentArchiveLocked()
s.initialEquipmentMu.Unlock()
if err != nil {
s.raidFiendWarErr = err
return nil, err
}
s.raidFiendWar, s.raidFiendWarErr = raid.LoadFiendWarConfig(archive)
return s.raidFiendWar, s.raidFiendWarErr
}
func runtimeRaidMemberLimit(state runtimeRaidState) int {
if state.RaidMode == runtimeRaidOwnerFiendWar {
if state.FiendWarConfig == nil {
return 0
}
return state.FiendWarConfig.MemberMax
}
return raid.MaxAttackPartyMembers
}
// currentFiendWarSquadCount 是超时空的小队编制数。
//
// 操作员 2026-10-02 的定案:
//
// 「超时空总共有8个编制 跟其他攻坚战不一样的是 每个小队编制仅可放1人
// 最有力的证明是 小队编制界面 每个小队后面三格都是锁住的」
//
// 副本侧也对得上:罗什那两张地图的 `[player number]` 是 `2 8`(最少 2 人、最多 8 人)。
const currentFiendWarSquadCount = 8
// runtimeRaidGroupMaxFor 返回"这个团有几个小队编制"(客户端小队编制界面画几行)。
//
// 超时空是 **8**;安东/卢克沿用既有的 runtimeRaidMaxGroups(10,40 人格子)。
func runtimeRaidGroupMaxFor(state runtimeRaidState) byte {
if state.RaidMode == runtimeRaidOwnerFiendWar {
return currentFiendWarSquadCount
}
return runtimeRaidMaxGroups
}
// runtimeRaidGroupSizeFor 返回"一个小队编制能站几个人"。
//
// 超时空是 **1** —— 客户端的小队编制界面每队后面三格是锁住的,团长把 B 拖进
// 已经有 A 的队时,**A 被挤成单人(未编队)、B 占这个位置**,而不是整脚拒绝;
// 见 moveRuntimeRaidMember 里那条挤人分支。其余团仍然是 4 人一队。
//
// 这条尺子同时管着"普通队伍 → 小队编号"的自动同步
// (runtimeRaidSquadForOrdinaryPartyLedBy):超时空里两个人在镇上组了队,
// 他们会被分到**两个不同的编制**,而不是挤进同一队。
func runtimeRaidGroupSizeFor(state runtimeRaidState) int {
if state.RaidMode == runtimeRaidOwnerFiendWar {
return 1
}
return runtimeRaidGroupSize
}
// runtimeRaidGroupLimit 是这个团的小队编制数上限(按人数上限除以每队容量算)。
// 超时空每队 1 人 ⇒ 就是 8。
func runtimeRaidGroupLimit(state runtimeRaidState) byte {
size := runtimeRaidGroupSizeFor(state)
if size <= 0 {
return 0
}
return byte((runtimeRaidMemberLimit(state) + size - 1) / size)
}