服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
60 lines
2.8 KiB
Go
60 lines
2.8 KiB
Go
package dnfbridge
|
||
|
||
// raidRewardJournalLimit 是 raidRewardCompleted / raidRewardPublished 两张表的
|
||
// 容量上限。
|
||
//
|
||
// 这两张表按 {RaidKey, Phase, Token} 记录每次结算的幂等凭据。Token 每次结算递增、
|
||
// RaidKey 由单调的 nextRaidSeq 生成且永不复用,所以**每次结算都是一个新键**:
|
||
// 没有上限就会随进程生命周期内已结算的攻坚次数一直涨(估算 4~24 MB/天)。
|
||
//
|
||
// 更麻烦的是它的读取方式:completedSingleRuntimeRaidForLeave(raid_online.go:1824)
|
||
// 与 completedTeamRuntimeRaidForLeave(raid_online.go:1866)为了按角色找到那场已结束
|
||
// 的攻坚,每次退攻坚请求都要**全表遍历**这张 map,代价 O(已完成攻坚数)。累积一万次
|
||
// 结算之后,每次退攻坚都要扫一万项并对命中项做 cloneRuntimeRaidState 深拷贝。
|
||
//
|
||
// 上限把「内存」和「退攻坚开销」一起封顶。语义上只丢弃很久以前就已结束、客户端
|
||
// 早已不可能再点「退出攻坚队」的历史记录;最近 1024 次结算的幂等凭据全部保留。
|
||
const raidRewardJournalLimit = 1024
|
||
|
||
// storeRaidRewardCompletionLocked 写入一条结算凭据,并在超出上限时淘汰最旧的一条。
|
||
// 调用方必须已持有 raidRewardCommitMu。
|
||
func (s *Service) storeRaidRewardCompletionLocked(
|
||
key runtimeRaidRewardCompletionKey,
|
||
completion runtimeRaidSettlementRewardCompletion,
|
||
) {
|
||
if s.raidRewardCompleted == nil {
|
||
s.raidRewardCompleted = make(map[runtimeRaidRewardCompletionKey]runtimeRaidSettlementRewardCompletion)
|
||
}
|
||
if _, exists := s.raidRewardCompleted[key]; !exists {
|
||
s.raidRewardCompletedOrder = append(s.raidRewardCompletedOrder, key)
|
||
}
|
||
s.raidRewardCompleted[key] = completion
|
||
for len(s.raidRewardCompleted) > raidRewardJournalLimit &&
|
||
len(s.raidRewardCompletedOrder) > 0 {
|
||
oldest := s.raidRewardCompletedOrder[0]
|
||
s.raidRewardCompletedOrder = s.raidRewardCompletedOrder[1:]
|
||
delete(s.raidRewardCompleted, oldest)
|
||
}
|
||
}
|
||
|
||
// storeRaidRewardPublicationLocked 同上,作用于 raidRewardPublished。
|
||
// 调用方必须已持有 raidRewardFlowMu。
|
||
func (s *Service) storeRaidRewardPublicationLocked(
|
||
key runtimeRaidRewardCompletionKey,
|
||
publication *runtimeRaidRewardPublication,
|
||
) {
|
||
if s.raidRewardPublished == nil {
|
||
s.raidRewardPublished = make(map[runtimeRaidRewardCompletionKey]*runtimeRaidRewardPublication)
|
||
}
|
||
if _, exists := s.raidRewardPublished[key]; !exists {
|
||
s.raidRewardPublishedOrder = append(s.raidRewardPublishedOrder, key)
|
||
}
|
||
s.raidRewardPublished[key] = publication
|
||
for len(s.raidRewardPublished) > raidRewardJournalLimit &&
|
||
len(s.raidRewardPublishedOrder) > 0 {
|
||
oldest := s.raidRewardPublishedOrder[0]
|
||
s.raidRewardPublishedOrder = s.raidRewardPublishedOrder[1:]
|
||
delete(s.raidRewardPublished, oldest)
|
||
}
|
||
}
|