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,145 @@
|
||||
// avatarcompoundcheck 用来核对时装合成器的 PVF 数据。
|
||||
//
|
||||
// go run ./cmd/scratch/avatarcompoundcheck scan 列出每个职业分表的稀有池/普通池及各候选自己的 grade
|
||||
// go run ./cmd/scratch/avatarcompoundcheck 112510093 ... 打印指定装备的 name/grade/rarity/equipment type
|
||||
//
|
||||
// scan 的结论:16 张分表 586 个稀有候选的 PVF grade 全是 3,普通候选全是 2,
|
||||
// 也就是分表里的 [grade] 1 与 [upper grade] 2 说的是**投入的来源装扮**,
|
||||
// 不是产出物品的档次。
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
dnfpvf "longheng.io/server/internal/modules/dnf/pvf"
|
||||
platformpvf "longheng.io/server/internal/platform/pvf"
|
||||
)
|
||||
|
||||
func resolvePath(archive *platformpvf.Archive, listPath, reference string) string {
|
||||
reference = strings.TrimSpace(strings.Trim(reference, "`\"'"))
|
||||
for _, candidate := range []string{reference, path.Join(path.Dir(listPath), reference)} {
|
||||
if file, ok := archive.FindFile(candidate); ok {
|
||||
return file.ArchivePath
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func main() {
|
||||
pvfPath := flag.String("pvf", `../runtime/data/dnf/Script.pvf`, "Script.pvf path")
|
||||
flag.Parse()
|
||||
archive, err := platformpvf.Open(*pvfPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
text, err := archive.ReadText("equipment/equipment.lst")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
doc, err := dnfpvf.Parse("equipment/equipment.lst", text)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
byID := map[int64]string{}
|
||||
for _, entry := range dnfpvf.ParseList(doc) {
|
||||
byID[entry.ID] = resolvePath(archive, "equipment/equipment.lst", entry.Path)
|
||||
}
|
||||
|
||||
grade := func(id int64) int64 {
|
||||
p := byID[id]
|
||||
if p == "" {
|
||||
return -1
|
||||
}
|
||||
txt, e := archive.ReadText(p)
|
||||
if e != nil {
|
||||
return -1
|
||||
}
|
||||
d, e := dnfpvf.Parse(p, txt)
|
||||
if e != nil {
|
||||
return -1
|
||||
}
|
||||
g, _ := d.Int("grade")
|
||||
return g
|
||||
}
|
||||
|
||||
if len(flag.Args()) == 1 && flag.Args()[0] == "scan" {
|
||||
idxText, _ := archive.ReadText("etc/chn_compound/compoundavatar.etc")
|
||||
idxDoc, _ := dnfpvf.Parse("etc/chn_compound/compoundavatar.etc", idxText)
|
||||
seen := map[int64]int{}
|
||||
for _, tok := range idxDoc.Tokens {
|
||||
name := strings.TrimSpace(strings.Trim(tok.Value, "`"))
|
||||
if !strings.HasSuffix(strings.ToLower(name), ".etc") {
|
||||
continue
|
||||
}
|
||||
tp := "etc/chn_compound/" + strings.ToLower(name)
|
||||
tt, readErr := archive.ReadText(tp)
|
||||
if readErr != nil {
|
||||
fmt.Println(tp, "ERR", readErr)
|
||||
continue
|
||||
}
|
||||
td, parseErr := dnfpvf.Parse(tp, tt)
|
||||
if parseErr != nil {
|
||||
continue
|
||||
}
|
||||
g, _ := td.Int("grade")
|
||||
ug, _ := td.Int("upper grade")
|
||||
fmt.Printf("== %s grade=%d upper=%d\n", name, g, ug)
|
||||
for _, part := range []string{"hat", "hair", "face", "neck", "coat", "pants", "belt", "shoes"} {
|
||||
vals := td.Ints(part + " avatar")
|
||||
if len(vals) < 3 {
|
||||
continue
|
||||
}
|
||||
n := int(vals[0])
|
||||
pairs := vals[1:]
|
||||
specials := ""
|
||||
for i := 0; i*2+1 < len(pairs) && i < n; i++ {
|
||||
gr := grade(pairs[i*2])
|
||||
specials += fmt.Sprintf(" %d(w=%d,g=%d)", pairs[i*2], pairs[i*2+1], gr)
|
||||
seen[gr]++
|
||||
}
|
||||
normals := ""
|
||||
for i := n; i*2+1 < len(pairs); i++ {
|
||||
normals += fmt.Sprintf(" %d(w=%d,g=%d)", pairs[i*2], pairs[i*2+1], grade(pairs[i*2]))
|
||||
}
|
||||
fmt.Printf(" %-6s specials:%s | normals:%s\n", part, specials, normals)
|
||||
}
|
||||
}
|
||||
fmt.Println("special grade histogram:", seen)
|
||||
return
|
||||
}
|
||||
|
||||
for _, id := range flag.Args() {
|
||||
var itemID int64
|
||||
fmt.Sscan(id, &itemID)
|
||||
p := byID[itemID]
|
||||
if p == "" {
|
||||
fmt.Printf("%d: NOT IN equipment.lst\n", itemID)
|
||||
continue
|
||||
}
|
||||
t, readErr := archive.ReadText(p)
|
||||
if readErr != nil {
|
||||
fmt.Printf("%d %s: read error %v\n", itemID, p, readErr)
|
||||
continue
|
||||
}
|
||||
d, parseErr := dnfpvf.Parse(p, t)
|
||||
if parseErr != nil {
|
||||
fmt.Printf("%d %s: parse error %v\n", itemID, p, parseErr)
|
||||
continue
|
||||
}
|
||||
g, hasGrade := d.Int("grade")
|
||||
rarity, hasRarity := d.Int("rarity")
|
||||
name := ""
|
||||
if tokens, ok := d.Section("name"); ok && len(tokens) > 0 {
|
||||
name = tokens[0].Value
|
||||
}
|
||||
eqType := ""
|
||||
if tokens, ok := d.Section("equipment type"); ok && len(tokens) > 0 {
|
||||
eqType = tokens[0].Value
|
||||
}
|
||||
fmt.Printf("%d %s name=%q grade=%d(%v) rarity=%d(%v) type=%s\n",
|
||||
itemID, p, name, g, hasGrade, rarity, hasRarity, eqType)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user