服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
114 lines
4.0 KiB
Go
114 lines
4.0 KiB
Go
package dnfbridge
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
dnfdungeonadmission "longheng.io/server/internal/modules/dnf/dungeonadmission"
|
|
)
|
|
|
|
// 验证周常五图的准入策略生成与开放日开关。
|
|
func TestAbisEntryPolicies(t *testing.T) {
|
|
for _, spec := range abisDungeonSpecs {
|
|
policies, err := abisEntryPolicies(spec, 0)
|
|
if err != nil {
|
|
t.Fatalf("dungeon %d: %v", spec.id, err)
|
|
}
|
|
if len(policies) != 2 {
|
|
t.Fatalf("dungeon %d: want 2 policies, got %d", spec.id, len(policies))
|
|
}
|
|
account, character := policies[0], policies[1]
|
|
if account.Scope == character.Scope {
|
|
t.Fatalf("dungeon %d: both policies share scope %d", spec.id, account.Scope)
|
|
}
|
|
t.Logf("dungeon %d %s: account key=%s limit=%d section=%q | character key=%s limit=%d section=%q",
|
|
spec.id, spec.name,
|
|
account.Key, account.Limit, account.SourceSection,
|
|
character.Key, character.Limit, character.SourceSection)
|
|
if account.Key != abisSharedAccountPolicyKey {
|
|
t.Fatalf("dungeon %d: account policy key=%q want=%q (must be shared across all five)", spec.id, account.Key, abisSharedAccountPolicyKey)
|
|
}
|
|
if len(account.DungeonIDs) != 5 {
|
|
t.Fatalf("dungeon %d: shared account policy must cover 5 dungeons, got %v", spec.id, account.DungeonIDs)
|
|
}
|
|
if account.Limit != abisAccountDailyBase {
|
|
t.Fatalf("dungeon %d: account limit=%d want=%d", spec.id, account.Limit, abisAccountDailyBase)
|
|
}
|
|
if character.Limit != spec.limit {
|
|
t.Fatalf("dungeon %d: character limit=%d want=%d", spec.id, character.Limit, spec.limit)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 冒险团分档加成必须落在 PVF 声明的区间上。
|
|
func TestAbisAdventureGroupAddition(t *testing.T) {
|
|
cases := []struct {
|
|
level uint32
|
|
want uint32
|
|
}{
|
|
{0, 0}, {1, 0}, {5, 0}, {6, 1}, {10, 1}, {11, 2}, {15, 2},
|
|
{16, 3}, {20, 3}, {21, 4}, {25, 4}, {26, 5}, {30, 5}, {31, 0},
|
|
}
|
|
for _, c := range cases {
|
|
if got := abisAdventureGroupAddition(c.level); got != c.want {
|
|
t.Errorf("manage level %d: bonus=%d want=%d", c.level, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 06:00 服务日边界:北京 05:59 属于前一天,06:00 属于新一天。
|
|
func TestAbisServiceWindowSixAMBoundary(t *testing.T) {
|
|
beijing := time.FixedZone("CST", 8*3600)
|
|
before := time.Date(2026, 10, 12, 5, 59, 0, 0, beijing)
|
|
after := time.Date(2026, 10, 12, 6, 0, 0, 0, beijing)
|
|
policy := abisEntryPoliciesForWindowProbe()
|
|
w1, err := abisPolicyWindow(policy, before)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
w2, err := abisPolicyWindow(policy, after)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if w1.Start.Equal(w2.Start) {
|
|
t.Fatalf("05:59 and 06:00 must be different service days, both start=%v", w1.Start)
|
|
}
|
|
t.Logf("05:59 -> window %v ; 06:00 -> window %v", w1.Start, w2.Start)
|
|
if w1.Start.Hour() != 6 || w2.Start.Hour() != 6 {
|
|
t.Fatalf("service day must start at 06:00, got %d and %d", w1.Start.Hour(), w2.Start.Hour())
|
|
}
|
|
}
|
|
|
|
func abisEntryPoliciesForWindowProbe() dnfdungeonadmission.Policy {
|
|
policies, _ := abisEntryPolicies(abisDungeonSpecs[0], 0)
|
|
return policies[0]
|
|
}
|
|
|
|
// 冒险团分档加成必须计入账号策略上限:账号额度 = 5 + 分档加成。
|
|
func TestAbisAccountPolicyIncludesAdventureGroupBonus(t *testing.T) {
|
|
cases := []struct {
|
|
manageLevel uint32
|
|
wantLimit uint32
|
|
}{
|
|
{0, 5}, {1, 5}, {5, 5}, {6, 6}, {10, 6}, {11, 7}, {16, 8},
|
|
{21, 9}, {26, 10}, {30, 10}, {31, 5},
|
|
}
|
|
for _, c := range cases {
|
|
policies, err := abisEntryPolicies(abisDungeonSpecs[0], c.manageLevel)
|
|
if err != nil {
|
|
t.Fatalf("manage level %d: %v", c.manageLevel, err)
|
|
}
|
|
if got := policies[0].Limit; got != c.wantLimit {
|
|
t.Errorf("manage level %d: account limit=%d want=%d", c.manageLevel, got, c.wantLimit)
|
|
}
|
|
// 共享键必须与等级无关,否则同一账号不同角色会各生成一条账号策略。
|
|
if policies[0].Key != abisSharedAccountPolicyKey {
|
|
t.Errorf("manage level %d: account key=%q want shared", c.manageLevel, policies[0].Key)
|
|
}
|
|
// 角色上限不受冒险团等级影响。
|
|
if got := policies[1].Limit; got != abisDungeonSpecs[0].limit {
|
|
t.Errorf("manage level %d: character limit=%d want=%d", c.manageLevel, got, abisDungeonSpecs[0].limit)
|
|
}
|
|
}
|
|
}
|