服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
128 lines
4.0 KiB
Go
128 lines
4.0 KiB
Go
package services
|
|
|
|
import (
|
|
"pvfine/internal/pvf"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"unicode/utf16"
|
|
)
|
|
|
|
const safeUpgradeSample = `[safe upgrade]
|
|
0 1 0 0 1 10327281 40 124448
|
|
1 1 0 0 1 10327281 41 124448
|
|
2 1 0 0 1 10327281 43 124448
|
|
3 1 0 0 1 10327281 44 124448
|
|
4 1 20000 5000 1 10327281 81 247893
|
|
5 1 30000 5000 1 10327281 91 276207
|
|
6 1 40000 5000 1 10327281 99 298734
|
|
7 1 50000 5000 1 10327281 110 332572
|
|
8 1 60000 5000 1 10327281 124 377149
|
|
9 1 70000 5000 1 10327281 145 436960
|
|
10 1 90000 2000 1 10327281 491 1485598
|
|
11 1 94000 1000 2 10327281 1529 4626036
|
|
[/safe upgrade]`
|
|
|
|
func TestSafeUpgradeSampleAndSource(t *testing.T) {
|
|
text := strings.ReplaceAll("# 😀\n"+safeUpgradeSample, "\n", "\r\n")
|
|
rows, err := parseSafeUpgrade(text)
|
|
if err != nil || len(rows) != 12 {
|
|
t.Fatalf("parse: %v %v", rows, err)
|
|
}
|
|
source := utf16.Encode([]rune(strings.ReplaceAll(text, "\r\n", "\n")))
|
|
for i, row := range rows {
|
|
if len(row.Fields) != 8 || row.Fields[0].Value != float64(i) {
|
|
t.Fatalf("row %d: %+v", i, row)
|
|
}
|
|
for _, field := range row.Fields {
|
|
if got := string(utf16.Decode(source[field.Start:field.End])); got != strconv.FormatInt(int64(field.Value), 10) {
|
|
t.Fatal("source position lost")
|
|
}
|
|
}
|
|
}
|
|
last := rows[11].Fields
|
|
if last[2].Value != 94000 || last[3].Value != 1000 || last[4].Value != 2 || last[5].Value != 10327281 || last[6].Value != 1529 || last[7].Value != 4626036 {
|
|
t.Fatal("fields shifted")
|
|
}
|
|
normal := "[table]\n[table type]\n`normal` " + upgradeTypedRow + "\n[/table]\n"
|
|
doc, err := parseUpgrade(normal+text, "normal")
|
|
if err != nil || len(doc.Rows) != 1 || len(doc.SafeRows) != 12 || doc.SafeIssue != "" {
|
|
t.Fatalf("combined: %+v %v", doc, err)
|
|
}
|
|
doc, err = parseUpgrade(normal+"[safe upgrade]\n1 2\n[/safe upgrade]", "normal")
|
|
if err != nil || len(doc.Rows) != 1 || doc.SafeIssue == "" {
|
|
t.Fatal("malformed safe data blocked normal editor")
|
|
}
|
|
}
|
|
|
|
func TestSafeUpgradeMaterialNames(t *testing.T) {
|
|
a := pvf.New()
|
|
for path, text := range map[string]string{
|
|
"stackable/stackable.lst": "3037 `cube.stk` 10327281 `core.stk`",
|
|
"stackable/cube.stk": "[name]\n`无色小晶块`",
|
|
"stackable/core.stk": "[name]\n`炉岩核`",
|
|
} {
|
|
if _, err := a.AddFileText(path, text, pvf.TypeScript); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
indexes := []int32{}
|
|
for _, kind := range []string{"normal", "amplify"} {
|
|
path := "etc/upgrade.etc"
|
|
if kind == "amplify" {
|
|
path = "etc/amplifyupgrade.etc"
|
|
}
|
|
index, err := a.AddFileText(path, "[table]\n[table type]\n`"+kind+"` "+upgradeTypedRow+"\n[/table]\n"+safeUpgradeSample, pvf.TypeScript)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
indexes = append(indexes, index)
|
|
}
|
|
c := NewCore()
|
|
if err := c.setArchive(a); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(c.closeArchive)
|
|
s := NewFileGUIService(c)
|
|
for _, index := range indexes {
|
|
text, _ := a.Text(index)
|
|
doc, err := s.ReadUpgrade(index, text)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if doc.Rows[0].CostName != "无色小晶块" {
|
|
t.Fatalf("normal name: %+v", doc.Rows[0])
|
|
}
|
|
for _, row := range doc.SafeRows {
|
|
if row.CostName != "炉岩核" {
|
|
t.Fatalf("safe name: %+v", row)
|
|
}
|
|
}
|
|
draft := strings.ReplaceAll(text, "10327281", "999999")
|
|
unknown, err := s.ReadUpgrade(index, draft)
|
|
if err != nil || unknown.SafeRows[0].CostName != "" {
|
|
t.Fatalf("unknown draft: %+v %v", unknown, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSafeUpgradeMalformedAndAbsent(t *testing.T) {
|
|
for _, text := range []string{
|
|
"[safe upgrade]\n[/safe upgrade]",
|
|
"[safe upgrade]\n1 2 3\n[/safe upgrade]",
|
|
strings.Replace(safeUpgradeSample, "94000", "1.5", 1),
|
|
strings.Replace(safeUpgradeSample, "94000", "2147483648", 1),
|
|
strings.Replace(safeUpgradeSample, "94000", "100001", 1),
|
|
strings.Replace(safeUpgradeSample, "94000", "-1", 1),
|
|
safeUpgradeSample + "\n" + safeUpgradeSample,
|
|
} {
|
|
if _, err := parseSafeUpgrade(text); err == nil {
|
|
t.Fatalf("accepted malformed: %s", text)
|
|
}
|
|
}
|
|
rows, err := parseSafeUpgrade("[other]\n1")
|
|
if err != nil || len(rows) != 0 {
|
|
t.Fatal("absent section rejected")
|
|
}
|
|
}
|