Files
hanfuit 645b64fe21 DNF90 服务端与启动器完整源码(含 GM 工具功能增强)
服务端(Go):
- GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面
- GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新
- 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新)
- 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍
- 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0)
- 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算

启动器(Python/JS):
- 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭
- GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐)
- 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
2026-11-04 14:31:55 +08:00

102 lines
4.4 KiB
Go

package statbuff
import (
"testing"
"time"
dnfrepo "longheng.io/server/internal/modules/dnf/repository"
)
func TestActivateEpicDropRateStoresWindowAndExpires(t *testing.T) {
now := time.Date(2026, time.October, 3, 18, 0, 0, 0, time.UTC)
character := dnfrepo.CharacterRecord{CharacterID: "11", Stats: map[string]int64{}}
effect, err := ActivateEpicDropRate(&character, 490002458, 1136, 200, 10*time.Minute, now)
if err != nil {
t.Fatal(err)
}
if effect.MultiplierPercent != 200 || effect.ItemID != 490002458 ||
!effect.ExpireAt.Equal(now.Add(10*time.Minute)) {
t.Fatalf("effect=%+v", effect)
}
if character.Stats[EpicDropRatePercentStatKey] != 200 ||
character.Stats[EpicDropRateItemStatKey] != 490002458 {
t.Fatalf("stats=%v", character.Stats)
}
active, ok := ActiveEpicDropRate(character, now.Add(9*time.Minute))
if !ok || active.MultiplierPercent != 200 || active.ItemID != 490002458 {
t.Fatalf("within window active=%t effect=%+v", ok, active)
}
// 边界:正好到期不算有效("持续10分钟"),过期更不算。
if _, ok := ActiveEpicDropRate(character, now.Add(10*time.Minute)); ok {
t.Fatalf("exactly-expired window must not be active")
}
if _, ok := ActiveEpicDropRate(character, now.Add(11*time.Minute)); ok {
t.Fatalf("expired window must not be active")
}
}
func TestActiveEpicDropRateFailsClosedOnMissingOrBrokenState(t *testing.T) {
now := time.Date(2026, time.October, 3, 18, 0, 0, 0, time.UTC)
cases := map[string]dnfrepo.CharacterRecord{
"nil stats": {CharacterID: "11"},
"no percent": {CharacterID: "11", Stats: map[string]int64{EpicDropRateExpireStatKey: now.Add(time.Hour).Unix()}},
"no expire": {CharacterID: "11", Stats: map[string]int64{EpicDropRatePercentStatKey: 200}},
"zero percent": {CharacterID: "11", Stats: map[string]int64{EpicDropRatePercentStatKey: 0, EpicDropRateExpireStatKey: now.Add(time.Hour).Unix()}},
"negative percent": {CharacterID: "11", Stats: map[string]int64{EpicDropRatePercentStatKey: -200, EpicDropRateExpireStatKey: now.Add(time.Hour).Unix()}},
"negative expire": {CharacterID: "11", Stats: map[string]int64{EpicDropRatePercentStatKey: 200, EpicDropRateExpireStatKey: -5}},
"zero expire": {CharacterID: "11", Stats: map[string]int64{EpicDropRatePercentStatKey: 200, EpicDropRateExpireStatKey: 0}},
}
for name, character := range cases {
if _, ok := ActiveEpicDropRate(character, now); ok {
t.Fatalf("%s: must not be active", name)
}
}
}
// TestActivateEpicDropRateOverwritesInsteadOfStacking 锁住"不与其他史诗Buff药剂叠加":
// 第二次施加是**覆盖**,绝不会把倍率乘起来。
func TestActivateEpicDropRateOverwritesInsteadOfStacking(t *testing.T) {
now := time.Date(2026, time.October, 3, 18, 0, 0, 0, time.UTC)
character := dnfrepo.CharacterRecord{CharacterID: "11", Stats: map[string]int64{}}
if _, err := ActivateEpicDropRate(&character, 490002458, 1136, 200, 10*time.Minute, now); err != nil {
t.Fatal(err)
}
later := now.Add(5 * time.Minute)
effect, err := ActivateEpicDropRate(&character, 490006963, 1136, 200, 10*time.Minute, later)
if err != nil {
t.Fatal(err)
}
if effect.MultiplierPercent != 200 {
t.Fatalf("percent=%d, 叠加会得到 400", effect.MultiplierPercent)
}
active, ok := ActiveEpicDropRate(character, later.Add(time.Minute))
if !ok || active.MultiplierPercent != 200 || active.ItemID != 490006963 {
t.Fatalf("active=%t effect=%+v", ok, active)
}
if !active.ExpireAt.Equal(later.Add(10 * time.Minute)) {
t.Fatalf("expire=%s, 覆盖时窗口要按最后一次使用重新计时", active.ExpireAt)
}
}
func TestActivateEpicDropRateRejectsInvalidInput(t *testing.T) {
now := time.Date(2026, time.October, 3, 18, 0, 0, 0, time.UTC)
character := dnfrepo.CharacterRecord{CharacterID: "11"}
for _, tc := range []struct {
name string
target *dnfrepo.CharacterRecord
itemID int64
percent int64
duration time.Duration
}{
{name: "nil character", target: nil, itemID: 1, percent: 200, duration: time.Minute},
{name: "zero item", target: &character, itemID: 0, percent: 200, duration: time.Minute},
{name: "zero percent", target: &character, itemID: 1, percent: 0, duration: time.Minute},
{name: "zero duration", target: &character, itemID: 1, percent: 200},
} {
if _, err := ActivateEpicDropRate(tc.target, tc.itemID, 0, tc.percent, tc.duration, now); err == nil {
t.Fatalf("%s: expected rejection", tc.name)
}
}
}