服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
85 lines
2.2 KiB
Go
85 lines
2.2 KiB
Go
// pvfref 在 PVF 全库按**子串**搜引用,只打印命中文件与命中片段。
|
||
//
|
||
// 与 cmd/scratch/pvfgrep 的区别:pvfgrep 走 dnfpvf.Index(受前缀/扩展名限制),
|
||
// pvfref 直接用 platform/pvf 的 RangePaths 遍历**全部 100 万+ 成员**,
|
||
// 因此能找到 ui/ 下的 .ani / .xui 等界面资源引用。
|
||
//
|
||
// 跑法:
|
||
//
|
||
// go run ./cmd/scratch/pvfref -pvf Script.pvf -find interface2_reward_ver2_cn \
|
||
// -ext .ani,.xui,.als -limit 40
|
||
package main
|
||
|
||
import (
|
||
"flag"
|
||
"fmt"
|
||
"strings"
|
||
|
||
platformpvf "longheng.io/server/internal/platform/pvf"
|
||
)
|
||
|
||
func main() {
|
||
pvfPath := flag.String("pvf", "", "Script.pvf (required)")
|
||
find := flag.String("find", "", "要搜索的子串 (required)")
|
||
extFlag := flag.String("ext", "", "只搜这些扩展名,逗号分隔;留空=全部")
|
||
limit := flag.Int("limit", 40, "最多命中文件数")
|
||
width := flag.Int("width", 90, "命中片段前后各取多少字符")
|
||
flag.Parse()
|
||
if *pvfPath == "" || *find == "" {
|
||
panic("-pvf and -find are required")
|
||
}
|
||
needle := strings.ToLower(*find)
|
||
var exts []string
|
||
for _, e := range strings.Split(*extFlag, ",") {
|
||
if e = strings.ToLower(strings.TrimSpace(e)); e != "" {
|
||
exts = append(exts, e)
|
||
}
|
||
}
|
||
archive, err := platformpvf.Open(*pvfPath)
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
fmt.Printf("PVF %s 成员 %d 搜索 %q\n", *pvfPath, archive.FileCount(), *find)
|
||
|
||
files, scanned := 0, 0
|
||
archive.RangePaths(func(p string) bool {
|
||
lower := strings.ToLower(p)
|
||
if len(exts) > 0 {
|
||
ok := false
|
||
for _, e := range exts {
|
||
if strings.HasSuffix(lower, e) {
|
||
ok = true
|
||
break
|
||
}
|
||
}
|
||
if !ok {
|
||
return true
|
||
}
|
||
}
|
||
scanned++
|
||
text, readErr := archive.ReadText(p)
|
||
if readErr != nil || !strings.Contains(strings.ToLower(text), needle) {
|
||
return true
|
||
}
|
||
files++
|
||
fmt.Printf("\n=== %s ===\n", p)
|
||
for _, line := range strings.Split(text, "\n") {
|
||
at := strings.Index(strings.ToLower(line), needle)
|
||
if at < 0 {
|
||
continue
|
||
}
|
||
from := at - *width
|
||
if from < 0 {
|
||
from = 0
|
||
}
|
||
to := at + len(*find) + *width
|
||
if to > len(line) {
|
||
to = len(line)
|
||
}
|
||
fmt.Printf(" >> %s\n", strings.TrimSpace(line[from:to]))
|
||
}
|
||
return files < *limit
|
||
})
|
||
fmt.Printf("\n扫描 %d 个文件,命中 %d 个\n", scanned, files)
|
||
}
|