服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
113 lines
3.5 KiB
Go
113 lines
3.5 KiB
Go
package pvf
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseScriptViewFlatAndDuplicateSections(t *testing.T) {
|
|
view := ParseScriptView("[rarity]\n3\n[name]\n`first`\n[rarity]\n4")
|
|
var sections, rarityTokens int
|
|
for _, element := range view.Elements {
|
|
if element.Kind == ScriptElementSection {
|
|
sections++
|
|
}
|
|
if element.Kind == ScriptElementToken && element.Section == "rarity" {
|
|
rarityTokens++
|
|
if element.Index != 0 {
|
|
t.Fatalf("rarity token index = %d, want 0", element.Index)
|
|
}
|
|
}
|
|
}
|
|
if sections != 3 || rarityTokens != 2 {
|
|
t.Fatalf("sections=%d rarityTokens=%d", sections, rarityTokens)
|
|
}
|
|
}
|
|
|
|
func TestParseScriptViewNestedDirectTokens(t *testing.T) {
|
|
view := ParseScriptView("[parent]\n1\n[child]\n2\n[/child]\n3\n[/parent]")
|
|
got := make([]string, 0)
|
|
for _, element := range view.Elements {
|
|
if element.Kind == ScriptElementToken {
|
|
got = append(got, element.Section+":"+element.Value)
|
|
}
|
|
}
|
|
want := []string{"parent:1", "child:2", "parent:3"}
|
|
if len(got) != len(want) {
|
|
t.Fatalf("tokens = %#v", got)
|
|
}
|
|
for i := range want {
|
|
if got[i] != want[i] {
|
|
t.Fatalf("tokens = %#v, want %#v", got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseScriptViewPairedChildInsideUnpairedSection(t *testing.T) {
|
|
view := ParseScriptViewWithNestedSections("[independent drop]\n1 2\n[list]\n100 200\n[/list]\n3 4\n[next]\n5", func(parent, child string) bool {
|
|
return parent == "independent drop" && child == "list"
|
|
})
|
|
var parentID int
|
|
var got []string
|
|
for _, element := range view.Elements {
|
|
if element.Kind != ScriptElementToken {
|
|
continue
|
|
}
|
|
if element.Value == "1" {
|
|
parentID = element.SectionID
|
|
}
|
|
got = append(got, element.Section+":"+element.Value)
|
|
if element.Value == "3" && (element.SectionID != parentID || element.Index != 2) {
|
|
t.Fatalf("token after list did not resume parent: %#v", element)
|
|
}
|
|
}
|
|
want := []string{"independent drop:1", "independent drop:2", "list:100", "list:200", "independent drop:3", "independent drop:4", "next:5"}
|
|
if strings.Join(got, ",") != strings.Join(want, ",") {
|
|
t.Fatalf("tokens = %#v, want %#v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestParseScriptViewUsesUTF16Offsets(t *testing.T) {
|
|
view := ParseScriptView("[name]\n`😀中`")
|
|
for _, element := range view.Elements {
|
|
if element.Kind != ScriptElementToken {
|
|
continue
|
|
}
|
|
if element.Start != 7 || element.End != 12 {
|
|
t.Fatalf("range = [%d,%d), want [7,12)", element.Start, element.End)
|
|
}
|
|
return
|
|
}
|
|
t.Fatal("name token not found")
|
|
}
|
|
|
|
func TestParseScriptViewNormalizesLineEndingOffsets(t *testing.T) {
|
|
text := "[name]\n`line1\r\nline2`\r[rarity]\r\n3"
|
|
normalized := strings.NewReplacer("\r\n", "\n", "\r", "\n").Replace(text)
|
|
view := ParseScriptView(text)
|
|
|
|
var section, token *ScriptElement
|
|
for i := range view.Elements {
|
|
element := &view.Elements[i]
|
|
if element.Kind == ScriptElementSection && element.Section == "rarity" {
|
|
section = element
|
|
}
|
|
if element.Kind == ScriptElementToken && element.Section == "rarity" {
|
|
token = element
|
|
}
|
|
}
|
|
if section == nil || token == nil {
|
|
t.Fatalf("rarity elements not found: %#v", view.Elements)
|
|
}
|
|
|
|
wantSectionStart := strings.Index(normalized, "[rarity]")
|
|
wantSectionEnd := wantSectionStart + len("[rarity]")
|
|
wantTokenStart := strings.LastIndex(normalized, "3")
|
|
if section.Start != wantSectionStart || section.End != wantSectionEnd {
|
|
t.Fatalf("section range = [%d,%d), want [%d,%d)", section.Start, section.End, wantSectionStart, wantSectionEnd)
|
|
}
|
|
if token.Start != wantTokenStart || token.End != wantTokenStart+1 {
|
|
t.Fatalf("token range = [%d,%d), want [%d,%d)", token.Start, token.End, wantTokenStart, wantTokenStart+1)
|
|
}
|
|
}
|