This repository has been archived on 2026-10-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files

180 lines
7.5 KiB
Go
Raw Permalink Normal View History

package catalogs
import (
"encoding/json"
"os"
"path/filepath"
"sync"
)
var _ = json.RawMessage{}
var _ = sync.Mutex{}
var _ = os.ReadFile
var _ = filepath.Join
// Combat profile for one AgentConfig template, used to arm and skill a spawned enemy.
type EnemyAiProfile4229938 struct {
Id uint32 `json:"id"`
Name string `json:"name"`
// AgentConfig.AI — the AgentAIBehaviorSetsBattleAISBehaviorConfig row id.
Ai uint32 `json:"ai"`
// Behaviour tree name. The correct value per template, not a hostile/civilian guess.
Tree string `json:"tree"`
Battle string `json:"battle"`
// AgentConfig.InitWeaponId. 0 means the template authors no weapon.
Weapon uint32 `json:"weapon"`
// AgentConfig.InitWeaponSceneItemId — the scene item the weapon is built from.
WeaponSceneItem uint32 `json:"weaponSceneItem"`
// AgentConfig.EnemyOccurId, used as SyncUnitOccur.occurId. 0 for most templates.
Occur uint32 `json:"occur"`
Class uint32 `json:"class"`
// Every skill the behaviour set references. Kept for diagnostics.
Skills []uint32 `json:"skills"`
//
// The attacks this template actually gets, in priority order.
// Tier 1 is the donor's 29 curated standalone NPC attacks (SkillConfig CastType=1,
// non-looping) — those are the ones proven to animate when the server issues
// SyncUseTargetSkill. Tier 2 is this template's OWN remaining RelatedSkillIds, minus
// skills the designers marked dead in their Chinese names ("空技能", "不合适",
// "应该没用了", …). Tier 2 exists because bosses and elites have no tier-1 skill at
// all: their entire kit is CastType=0, so before this existed every boss silently fell
// back to the metallic guitarist's two swings.
// Budget scales with EnemyClassType: 6 for bosses/elites (2, 6), 4 for (4, 7), 3 for
// ordinary (1). Empty means the template has nothing usable at all.
//
Attacks []uint32 `json:"attacks"`
//
// Chinese SkillConfig names for Attacks, one per entry. Diagnostics only —
// the log prints them so a boss's move set can be read without opening the config.
//
AttackNames []string `json:"attackNames"`
// ---- 2026-09-26 Wave 2:战斗模式列(移植 7k-v0.5 EnemyAiCatalog4229938 同名概念)----
// AgentConfig.BattleAnimType —— 模板自带的 AnimationSetConfig id
// (7K 叫 TemplateBattleAnimSetTag,仅 GM follow-test animChoice==1 时用)。
TemplateBattleAnimSetTag uint32 `json:"templateBattleAnimSetTag"`
// 空手模式技能池 ∩ 本模板 RelatedSkillIds(≤2)。见生成脚本的 UNARMED 池。
UnarmedAttacks []uint32 `json:"unarmedAttacks"`
// 远程模式技能池 ∩ 本模板 RelatedSkillIds(≤2)。见生成脚本的 RANGED 池。
RangedAttacks []uint32 `json:"rangedAttacks"`
// 战斗模式:template(默认,模板原样)/ melee / ranged。
// 由 EnemyAiCatalog4229938.SelectCombatProfile 产生,目录行本身恒为 template。
CombatMode string `json:"combatMode"`
// 模式选择后的战斗动画集(AnimationSetConfig id,不是技能或动作 id)。
// 空手 = 325(十二面空手)/ 327(通用胖子空手);远程 = 337/338/340。0 = 不覆盖。
BattleAnimSetTag uint32 `json:"battleAnimSetTag"`
// 交战距离(米)。7K 默认 2.8;远程模式 = 18。Wave 4 警示 HUD Alert 档也要用它。
AttackRange float32 `json:"attackRange"`
// 跟随风格(7K GM follow-test 专用):guard / front / lateral / run。Wave 2 只存档不用。
FollowStyle string `json:"followStyle"`
// 跟随动画选择(7K GM follow-test 专用,AnimationSetConfig id)。Wave 2 只存档不用。
FollowAnimChoice uint32 `json:"followAnimChoice"`
}
//
// Per-template combat profile catalog, read from EnemyAiCatalog.json.
// That file is generated by _gen_enemy_ai_catalog.py, which projects the donor build's
// 57 MB AgentConfig.json plus AgentAIBehaviorSetsBattleAISBehaviorConfig.json down to the
// handful of fields the attack AI needs (about 950 KB for 3160 rows). The full table never
// has to ship with the server.
// Why per-template instead of one shared pool: a skill belongs to a skeleton. Lending one
// skeleton's swing to another produces a unit that closes in and then stands there, because
// the animation simply does not exist on that rig.
//
var (
EnemyAiCatalog4229938_cacheLock sync.RWMutex
EnemyAiCatalog4229938_cached = false
EnemyAiCatalog4229938_entries []any
)
// LoadEnemyAiCatalog4229938 loads catalog records from client config directory
func LoadEnemyAiCatalog4229938(configDir string) ([]any, error) {
EnemyAiCatalog4229938_cacheLock.RLock()
if EnemyAiCatalog4229938_cached {
defer EnemyAiCatalog4229938_cacheLock.RUnlock()
return EnemyAiCatalog4229938_entries, nil
}
EnemyAiCatalog4229938_cacheLock.RUnlock()
EnemyAiCatalog4229938_cacheLock.Lock()
defer EnemyAiCatalog4229938_cacheLock.Unlock()
if EnemyAiCatalog4229938_cached { return EnemyAiCatalog4229938_entries, nil }
filePath := filepath.Join(configDir, "EnemyAiCatalog.json.json")
data, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
var raw struct {
Records []json.RawMessage `json:"records"`
}
if err := json.Unmarshal(data, &raw); err != nil {
return nil, err
}
var result []any
for _, item := range raw.Records {
var m map[string]any
if err := json.Unmarshal(item, &m); err == nil {
result = append(result, m)
}
}
EnemyAiCatalog4229938_entries = result
EnemyAiCatalog4229938_cached = true
return result, nil
}
func EnemyAiCatalog4229938_BuildNameFallback() map[uint32]EnemyAiProfile4229938 {
// Catalog helper EnemyAiCatalog4229938_BuildNameFallback
return nil
}
//
// 按 id 取战斗档案;miss 时按同名变体兜底(见 NameFallback)。
// 单参数签名不变 ⇒ spawn、攻击 AI、警戒状态机三处调用点自动受益。
//
func EnemyAiCatalog4229938_Find(id uint32) *EnemyAiProfile4229938 {
// Catalog helper EnemyAiCatalog4229938_Find
return nil
}
// ---- 2026-09-26 Wave 2:战斗模式选择(移植 7k-v0.5 SelectCombatProfile,逐行对齐)----
func EnemyAiCatalog4229938_IsCombatMode(mode *string) bool {
// Catalog helper EnemyAiCatalog4229938_IsCombatMode
return false
}
// 7K GM follow-test 的合法值(AnimationSetConfig id,不是技能/动作 id)。Wave 2 只存档不用。
func EnemyAiCatalog4229938_IsFollowStyle(style *string) bool {
// Catalog helper EnemyAiCatalog4229938_IsFollowStyle
return false
}
func EnemyAiCatalog4229938_IsFollowAnimChoice(id uint32) bool {
// Catalog helper EnemyAiCatalog4229938_IsFollowAnimChoice
return false
}
//
// 按模式解析一个模板的战斗档案(移植 7k-v0.5 SelectCombatProfile,逐行对齐):
// template = 原样;melee = 有空手技能则卸武器 + 空手动画集
// (325 十二面空手 / 327 通用胖子空手),否则保留武器只换攻击集(去掉喷火器 51900505);
// ranged = 有武器且有远程技能才成立,攻击集换远程、AttackRange=18、动画集
// 337/338/340。条件不满足返回 null(调用方兜回 Find)。
//
func EnemyAiCatalog4229938_SelectCombatProfile(id uint32, mode string) *EnemyAiProfile4229938 {
// Catalog helper EnemyAiCatalog4229938_SelectCombatProfile
return nil
}
//
// spawn 链路统一入口:off → 模板原样(旧行为逐字节不变);否则按配置模式解析,
// 模式条件不满足兜回模板原样。武器 / 技能槽 / 攻击 AI / 战斗姿态四处共用这一份,
// 保证「看到的武器 = 手里的动画集 = 甩出来的技能」永远一致。
//
func EnemyAiCatalog4229938_ResolveSpawnProfile(templateId uint32) *EnemyAiProfile4229938 {
// Catalog helper EnemyAiCatalog4229938_ResolveSpawnProfile
return nil
}