DNF90 服务端与启动器完整源码(含 GM 工具功能增强)
服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
This commit is contained in:
commit
645b64fe21
4388 files changed
+1405457
No files matched your search
@@ -0,0 +1,108 @@
|
||||
package quest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
dnfcerashop "longheng.io/server/internal/modules/dnf/cerashop"
|
||||
)
|
||||
|
||||
// 任务奖励里的代币券 / 欢乐代币券处理(纯函数部分)。
|
||||
//
|
||||
// 券在道具 PVF 里是普通 `[material]`、**没有 `[action type]`**,客户端根本没有任何
|
||||
// 途径把它们换成钱包余额;当普通道具发下去,玩家只会拿到一件永远用不掉的"材料"。
|
||||
// 所以发放前先把它们从奖励规则里摘出来,改成入账号钱包。
|
||||
|
||||
func finishVoucherTestRule(itemID, count int64) RewardItemRule {
|
||||
return RewardItemRule{ItemID: itemID, Count: count}
|
||||
}
|
||||
|
||||
// 拆分必须只摘出券,并且**保持非券规则的原有顺序**——顺序变了会改变落格结果,
|
||||
// 那是"修了 A 坏了 B"的典型来源。
|
||||
func TestSplitFinishVoucherRulesKeepsOrdinaryRulesInOrder(t *testing.T) {
|
||||
rules := []RewardItemRule{
|
||||
finishVoucherTestRule(100050, 1),
|
||||
finishVoucherTestRule(dnfcerashop.TokenCeraVoucherItemID, 100),
|
||||
finishVoucherTestRule(100056, 3),
|
||||
finishVoucherTestRule(dnfcerashop.HappyTokenCeraVoucherItemID, 7),
|
||||
finishVoucherTestRule(100057, 2),
|
||||
}
|
||||
vouchers, items := splitFinishVoucherRules(rules)
|
||||
if len(vouchers) != 2 || len(items) != 3 {
|
||||
t.Fatalf("vouchers=%+v items=%+v", vouchers, items)
|
||||
}
|
||||
for index, want := range []int64{100050, 100056, 100057} {
|
||||
if items[index].ItemID != want {
|
||||
t.Fatalf("非券规则顺序被改变: items[%d]=%d want=%d", index, items[index].ItemID, want)
|
||||
}
|
||||
}
|
||||
if vouchers[0].ItemID != dnfcerashop.TokenCeraVoucherItemID ||
|
||||
vouchers[1].ItemID != dnfcerashop.HappyTokenCeraVoucherItemID {
|
||||
t.Fatalf("券的顺序被改变: %+v", vouchers)
|
||||
}
|
||||
}
|
||||
|
||||
// 没有券时必须原样返回(不得产生任何副作用)。
|
||||
func TestSplitFinishVoucherRulesLeavesVoucherFreeRewardsUntouched(t *testing.T) {
|
||||
if vouchers, items := splitFinishVoucherRules([]RewardItemRule{finishVoucherTestRule(1, 1)}); len(vouchers) != 0 || len(items) != 1 {
|
||||
t.Fatalf("无券时不该有变化: vouchers=%+v items=%+v", vouchers, items)
|
||||
}
|
||||
if vouchers, items := splitFinishVoucherRules(nil); len(vouchers) != 0 || len(items) != 0 {
|
||||
t.Fatalf("空输入: vouchers=%+v items=%+v", vouchers, items)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFinishVoucherCountsSumsPerKind(t *testing.T) {
|
||||
counts, err := finishVoucherCounts([]RewardItemRule{
|
||||
finishVoucherTestRule(dnfcerashop.TokenCeraVoucherItemID, 100),
|
||||
finishVoucherTestRule(dnfcerashop.HappyTokenCeraVoucherItemID, 7),
|
||||
finishVoucherTestRule(dnfcerashop.TokenCeraVoucherItemID, 5),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if counts.TokenCera != 105 || counts.HappyTokenCera != 7 {
|
||||
t.Fatalf("counts=%+v want token=105 happy=7", counts)
|
||||
}
|
||||
}
|
||||
|
||||
// 坏值必须被挡住:券既然不走落格路径,就没有别的东西替我们校验这些字段了
|
||||
// (allocateFinishRewardItems 的那套校验对券不再执行)。
|
||||
func TestFinishVoucherCountsRejectsMalformedRules(t *testing.T) {
|
||||
cases := map[string]RewardItemRule{
|
||||
"zero_count": finishVoucherTestRule(dnfcerashop.TokenCeraVoucherItemID, 0),
|
||||
"negative": finishVoucherTestRule(dnfcerashop.TokenCeraVoucherItemID, -1),
|
||||
"non_voucher": finishVoucherTestRule(100050, 1),
|
||||
"zero_item": finishVoucherTestRule(0, 1),
|
||||
"oversized": finishVoucherTestRule(dnfcerashop.TokenCeraVoucherItemID, 1<<33),
|
||||
}
|
||||
for name, rule := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if _, err := finishVoucherCounts([]RewardItemRule{rule}); err == nil {
|
||||
t.Fatalf("坏值必须报错: %+v", rule)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 汇总后超过客户端可读范围(i32)时必须报错,而不是让它截断成负数。
|
||||
func TestFinishVoucherCountsRejectsPerKindOverflow(t *testing.T) {
|
||||
if _, err := finishVoucherCounts([]RewardItemRule{
|
||||
finishVoucherTestRule(dnfcerashop.TokenCeraVoucherItemID, 1<<31-1),
|
||||
finishVoucherTestRule(dnfcerashop.TokenCeraVoucherItemID, 1),
|
||||
}); err == nil {
|
||||
t.Fatal("代币券汇总溢出必须报错")
|
||||
}
|
||||
if _, err := finishVoucherCounts([]RewardItemRule{
|
||||
finishVoucherTestRule(dnfcerashop.HappyTokenCeraVoucherItemID, 1<<31-1),
|
||||
finishVoucherTestRule(dnfcerashop.HappyTokenCeraVoucherItemID, 1),
|
||||
}); err == nil {
|
||||
t.Fatal("欢乐代币券汇总溢出必须报错")
|
||||
}
|
||||
// 刚好到上限是允许的。
|
||||
counts, err := finishVoucherCounts([]RewardItemRule{
|
||||
finishVoucherTestRule(dnfcerashop.TokenCeraVoucherItemID, 1<<31-1),
|
||||
})
|
||||
if err != nil || counts.TokenCera != 1<<31-1 {
|
||||
t.Fatalf("刚好到上限应当允许: err=%v counts=%+v", err, counts)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user