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,236 @@
|
||||
// skillprobe dumps the PVF learnability fields for one job/skill pair so the
|
||||
// grow-type rejection can be checked against the shipped Script.pvf.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"longheng.io/server/internal/modules/dnf/pvf"
|
||||
dnfquest "longheng.io/server/internal/modules/dnf/quest"
|
||||
dnfrepo "longheng.io/server/internal/modules/dnf/repository"
|
||||
dnfskill "longheng.io/server/internal/modules/dnf/skill"
|
||||
platformpvf "longheng.io/server/internal/platform/pvf"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pvfPath := flag.String("pvf", `runtime/data/dnf/Script.pvf`, "Script.pvf path")
|
||||
job := flag.Int("job", 2, "job byte")
|
||||
skill := flag.Int("skill", 28, "skill id")
|
||||
list := flag.Bool("list", false, "list every skill of the job with grow-type fitness")
|
||||
quests := flag.Bool("quests", false, "list job-change quests of the job with eligibility")
|
||||
level := flag.Int("level", 50, "character level for -quests eligibility")
|
||||
grow := flag.Int("grow", 0, "packed grow_type for -quests eligibility")
|
||||
onlyClassChange := flag.Bool("classchange", false, "with -quests, print only [job change quest] type 1")
|
||||
diff := flag.Bool("diff", false, "list the rows the branch relaxation newly permits and the rows the awakening dimension still blocks")
|
||||
stageaudit := flag.Bool("stageaudit", false, "distribution of [skill fitness second growtype] across the whole PVF")
|
||||
flag.Parse()
|
||||
|
||||
archive, err := platformpvf.LoadArchive(platformpvf.Options{Path: *pvfPath})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
index, err := pvf.Build(context.Background(), archive, pvf.BuildOptions{Lists: []string{dnfskill.DefaultList}})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
catalog, err := dnfskill.Load(context.Background(), index, dnfskill.Options{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if *list {
|
||||
rows := make([]dnfskill.Skill, 0)
|
||||
for _, definition := range catalog.Skills() {
|
||||
if int(definition.Job) == *job {
|
||||
rows = append(rows, definition)
|
||||
}
|
||||
}
|
||||
sort.Slice(rows, func(i, j int) bool { return rows[i].ID < rows[j].ID })
|
||||
for _, d := range rows {
|
||||
fmt.Printf("skill=%-5d lvl=%-3d growTypes=%v growMax=%v secondGrow=%v secondMax=%v supports0=%t supports1=%t supportsC=%t name=%s\n",
|
||||
d.ID, d.RequiredLevel, d.GrowTypes, d.GrowTypeMaximumLevels,
|
||||
d.SecondGrowTypes, d.SecondGrowTypeMaximumLevels,
|
||||
d.SupportsGrowType(0), d.SupportsGrowType(1), d.SupportsCharacterGrowth(0), d.Name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if *diff {
|
||||
// Report what the tree-authority rule changes for one job/grow type:
|
||||
// rows newly learnable through the relaxed profession-branch dimension,
|
||||
// and rows still blocked by the awakening-stage dimension.
|
||||
first := *grow & 0x0f
|
||||
stage := (*grow >> 4) & 0x0f
|
||||
newly := make([]dnfskill.Skill, 0)
|
||||
blocked := make([]dnfskill.Skill, 0)
|
||||
for _, definition := range catalog.Skills() {
|
||||
if int(definition.Job) != *job {
|
||||
continue
|
||||
}
|
||||
if !definition.SupportsCharacterAwakening(*grow) {
|
||||
// The awakening dimension still gates the purchase, so the row
|
||||
// stays unlearnable no matter how the tree renders it.
|
||||
if definition.RequiredLevel <= *level {
|
||||
blocked = append(blocked, definition)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if definition.MaximumLearnableLevelForTree(*level, *grow) > definition.MaximumLearnableLevel(*level, *grow) {
|
||||
newly = append(newly, definition)
|
||||
}
|
||||
}
|
||||
sort.Slice(newly, func(i, j int) bool { return newly[i].ID < newly[j].ID })
|
||||
sort.Slice(blocked, func(i, j int) bool { return blocked[i].ID < blocked[j].ID })
|
||||
fmt.Printf("job=%d level=%d growType=0x%02X (branch=%d awakeningStage=%d)\n", *job, *level, *grow, first, stage)
|
||||
fmt.Printf(" newly learnable through the branch relaxation = %d\n", len(newly))
|
||||
for _, d := range newly {
|
||||
fmt.Printf(" skill=%-5d lvl=%-3d tree=%-3d old=%-3d growTypes=%v secondGrow=%v name=%q\n",
|
||||
d.ID, d.RequiredLevel,
|
||||
d.MaximumLearnableLevelForTree(*level, *grow), d.MaximumLearnableLevel(*level, *grow),
|
||||
d.GrowTypes, d.SecondGrowTypes, d.Name)
|
||||
}
|
||||
fmt.Printf(" still blocked by the awakening dimension = %d\n", len(blocked))
|
||||
for _, d := range blocked {
|
||||
fmt.Printf(" skill=%-5d lvl=%-3d secondGrow=%v secondMax=%v name=%q\n",
|
||||
d.ID, d.RequiredLevel, d.SecondGrowTypes, d.SecondGrowTypeMaximumLevels, d.Name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if *stageaudit {
|
||||
// Distribution of the awakening-stage dimension across the whole PVF, so
|
||||
// the stage gate can be checked against the shipped document.
|
||||
counts := make(map[int]int)
|
||||
rows := make([]dnfskill.Skill, 0)
|
||||
for _, definition := range catalog.Skills() {
|
||||
if len(definition.SecondGrowTypes) == 0 {
|
||||
continue
|
||||
}
|
||||
minimum := 0xff
|
||||
for _, stage := range definition.SecondGrowTypes {
|
||||
if stage >= 0 && stage < minimum {
|
||||
minimum = stage
|
||||
}
|
||||
}
|
||||
counts[minimum]++
|
||||
rows = append(rows, definition)
|
||||
}
|
||||
stages := make([]int, 0, len(counts))
|
||||
for stage := range counts {
|
||||
stages = append(stages, stage)
|
||||
}
|
||||
sort.Ints(stages)
|
||||
fmt.Printf("skills declaring [skill fitness second growtype] = %d\n", len(rows))
|
||||
for _, stage := range stages {
|
||||
fmt.Printf(" minimum awakening stage %d -> %d skills\n", stage, counts[stage])
|
||||
}
|
||||
for stage := range counts {
|
||||
if stage < 2 {
|
||||
continue
|
||||
}
|
||||
fmt.Printf(" --- stage >= %d examples ---\n", stage)
|
||||
shown := 0
|
||||
for _, d := range rows {
|
||||
minimum := 0xff
|
||||
for _, s := range d.SecondGrowTypes {
|
||||
if s >= 0 && s < minimum {
|
||||
minimum = s
|
||||
}
|
||||
}
|
||||
if minimum != stage {
|
||||
continue
|
||||
}
|
||||
fmt.Printf(" job=%-3d skill=%-5d lvl=%-3d secondGrow=%v name=%q\n",
|
||||
d.Job, d.ID, d.RequiredLevel, d.SecondGrowTypes, d.Name)
|
||||
shown++
|
||||
if shown >= 8 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if path := flag.Arg(0); path != "" {
|
||||
text, err := archive.ReadText(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("=== raw %s ===\n%s\n", path, text)
|
||||
return
|
||||
}
|
||||
|
||||
if *quests {
|
||||
questIndex, err := pvf.Build(context.Background(), archive, pvf.BuildOptions{
|
||||
Lists: []string{dnfquest.DefaultList},
|
||||
Prefixes: []string{"n_quest/"},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
questCatalog, err := dnfquest.Load(context.Background(), questIndex)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
eligibility := dnfquest.CharacterEligibility{
|
||||
Level: *level, Job: *job, GrowType: *grow,
|
||||
}
|
||||
result := questCatalog.Acceptable(eligibility, dnfrepo.QuestRecord{})
|
||||
acceptable := make(map[int64]struct{}, len(result.IDs))
|
||||
for _, id := range result.IDs {
|
||||
acceptable[int64(id)] = struct{}{}
|
||||
}
|
||||
fmt.Printf("job=%d level=%d growType=%d acceptable=%d\n", *job, *level, *grow, len(result.IDs))
|
||||
byChange := map[int]int{}
|
||||
for _, definition := range questCatalog.Definitions() {
|
||||
change := definition.JobChangeQuest
|
||||
if change < 1 || change > 20 {
|
||||
continue
|
||||
}
|
||||
byChange[change]++
|
||||
if *onlyClassChange && change != 1 {
|
||||
continue
|
||||
}
|
||||
_, ok := acceptable[definition.ID]
|
||||
fmt.Printf(" quest=%-6d jobChange=%-2d level=%d-%d job=%q target=%q rules=%v acceptable=%t path=%s reward=%q%v name=%q\n",
|
||||
definition.ID, change, definition.LevelMin, definition.LevelMax,
|
||||
definition.Job, definition.TargetCharacter, definition.TargetCharacterRules, ok,
|
||||
definition.Path, definition.RewardType, definition.RewardIntData, definition.Name)
|
||||
}
|
||||
counts := make([]int, 0, len(byChange))
|
||||
for change := range byChange {
|
||||
counts = append(counts, change)
|
||||
}
|
||||
sort.Ints(counts)
|
||||
for _, change := range counts {
|
||||
fmt.Printf(" [jobChange=%d definitions=%d]\n", change, byChange[change])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
definition, ok := catalog.Find(byte(*job), uint16(*skill))
|
||||
if !ok {
|
||||
fmt.Printf("job=%d skill=%d NOT FOUND\n", *job, *skill)
|
||||
return
|
||||
}
|
||||
fmt.Printf("job=%d skill=%d name=%q path=%s\n", definition.Job, definition.ID, definition.Name, definition.Path)
|
||||
fmt.Printf(" requiredLevel=%d active=%t skillClass=%d kind=%q\n",
|
||||
definition.RequiredLevel, definition.Active, definition.SkillClass, definition.Kind)
|
||||
fmt.Printf(" growTypes=%v\n", definition.GrowTypes)
|
||||
fmt.Printf(" growTypeMaximumLevels=%v\n", definition.GrowTypeMaximumLevels)
|
||||
fmt.Printf(" secondGrowTypes=%v\n", definition.SecondGrowTypes)
|
||||
fmt.Printf(" secondGrowTypeMaximumLevels=%v\n", definition.SecondGrowTypeMaximumLevels)
|
||||
fmt.Printf(" learnableForTree(level=%d, growType=0x%02X)=%d\n",
|
||||
*level, *grow, definition.MaximumLearnableLevelForTree(*level, *grow))
|
||||
fmt.Printf(" learnableFitnessAware(level=%d, growType=0x%02X)=%d\n",
|
||||
*level, *grow, definition.MaximumLearnableLevel(*level, *grow))
|
||||
for branch := 0; branch <= 4; branch++ {
|
||||
fmt.Printf(" branch=%d supportsGrowType=%t\n", branch, definition.SupportsGrowType(branch))
|
||||
}
|
||||
for _, packed := range []int{0, 1, 0x11, 0x21, 0x31} {
|
||||
fmt.Printf(" packedGrowType=0x%02X supportsCharacterGrowth=%t\n", packed, definition.SupportsCharacterGrowth(packed))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user