fix(go): repair migration wire contracts and runtime lifecycle; document incomplete port

This commit is contained in:
CAtlas0784 committed 2026-10-29 15:35:35 +07:00
1 parent e43a310617
commit 32e47014b5
35 files changed
+16826 -438

No files matched your search

+53 -55
View File
@@ -1,81 +1,79 @@
package catalogs
package catalogs
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"sync"
)
var _ = json.RawMessage{}
var _ = sync.Mutex{}
var _ = os.ReadFile
var _ = filepath.Join
// One grantable item row surfaced by the 道具 panel section.
type ItemCatalogEntry4229938 struct {
Id uint32 `json:"id"`
Name string `json:"name"`
Id uint32 `json:"id"`
Name string `json:"name"`
Quality uint32 `json:"quality"`
SubType uint32 `json:"subType"`
}
//
// Build-4229938 backpack item catalog, read from ItemCatalog.json in the configured client-data
// directory.
// That file is a slim projection of the client's ConsumableConfig.json — the only table in the
// config dump whose rows carry the LT.ConfigGen.ICommonItemConfig interface fields, i.e.
// the real backpack item table (Id / Name / Quality / SubType). Ids live in 36000000..36999999,
// which also contains the three wallet currencies (36920001/2/3); callers that grant "everything"
// must skip those so the wallet and the backpack do not disagree.
//
var (
ItemCatalog4229938_cacheLock sync.RWMutex
ItemCatalog4229938_cached = false
ItemCatalog4229938_entries []any
)
var itemCatalogState = struct {
sync.RWMutex
byPath map[string][]ItemCatalogEntry4229938
current []ItemCatalogEntry4229938
}{byPath: make(map[string][]ItemCatalogEntry4229938)}
// LoadItemCatalog4229938 loads catalog records from client config directory
// LoadItemCatalog4229938 accepts the legacy slim ItemCatalog table or the
// ConsumableConfig projection shipped in this Go repository. Cache keys include
// the source path, so loading another configuration cannot reuse the first table.
func LoadItemCatalog4229938(configDir string) ([]any, error) {
ItemCatalog4229938_cacheLock.RLock()
if ItemCatalog4229938_cached {
defer ItemCatalog4229938_cacheLock.RUnlock()
return ItemCatalog4229938_entries, nil
}
ItemCatalog4229938_cacheLock.RUnlock()
ItemCatalog4229938_cacheLock.Lock()
defer ItemCatalog4229938_cacheLock.Unlock()
if ItemCatalog4229938_cached { return ItemCatalog4229938_entries, nil }
filePath := filepath.Join(configDir, "ItemCatalog.json.json")
data, err := os.ReadFile(filePath)
path, err := filepath.Abs(filepath.Join(configDir, "ItemCatalog.json"))
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)
itemCatalogState.Lock()
defer itemCatalogState.Unlock()
entries, ok := itemCatalogState.byPath[path]
if !ok {
data, err := os.ReadFile(path)
if errors.Is(err, os.ErrNotExist) {
data, err = os.ReadFile(filepath.Join(configDir, "ConsumableConfig.json"))
}
if err != nil {
return nil, err
}
var raw struct {
Records []ItemCatalogEntry4229938 `json:"records"`
}
if err = json.Unmarshal(data, &raw); err != nil {
return nil, err
}
if raw.Records == nil {
return nil, fmt.Errorf("item catalog missing records array")
}
entries = make([]ItemCatalogEntry4229938, 0, len(raw.Records))
for _, entry := range raw.Records {
if entry.Id != 0 {
entries = append(entries, entry)
}
}
itemCatalogState.byPath[path] = entries
}
itemCatalogState.current = entries
result := make([]any, len(entries))
for i, entry := range entries {
result[i] = entry
}
ItemCatalog4229938_entries = result
ItemCatalog4229938_cached = true
return result, nil
}
func ItemCatalog4229938_Find(id uint32) *ItemCatalogEntry4229938 {
// Catalog helper ItemCatalog4229938_Find
itemCatalogState.RLock()
defer itemCatalogState.RUnlock()
for _, entry := range itemCatalogState.current {
if entry.Id == id {
copy := entry
return &copy
}
}
return nil
}
+51
View File
@@ -0,0 +1,51 @@
package catalogs
import (
"os"
"path/filepath"
"testing"
)
func TestItemCatalogPathsAndLookup(t *testing.T) {
for _, file := range []string{"ItemCatalog.json", "ConsumableConfig.json"} {
dir := t.TempDir()
if err := os.WriteFile(filepath.Join(dir, file), []byte(`{"records":[{"Id":36000000,"Name":"Test","Quality":2,"SubType":18}]}`), 0600); err != nil {
t.Fatal(err)
}
entries, err := LoadItemCatalog4229938(dir)
if err != nil || len(entries) != 1 {
t.Fatalf("%s: %v %v", file, entries, err)
}
entry := ItemCatalog4229938_Find(36000000)
if entry == nil || entry.Name != "Test" || entry.Quality != 2 {
t.Fatalf("bad projection: %+v", entry)
}
entry.Name = "mutated"
if ItemCatalog4229938_Find(36000000).Name != "Test" {
t.Fatal("caller mutated cache")
}
}
empty := t.TempDir()
if _, err := LoadItemCatalog4229938(empty); err == nil {
t.Fatal("reused another directory's cache")
}
if err := os.WriteFile(filepath.Join(empty, "ItemCatalog.json"), []byte(`{"records":[]}`), 0600); err != nil {
t.Fatal(err)
}
if entries, err := LoadItemCatalog4229938(empty); err != nil || len(entries) != 0 {
t.Fatalf("retry after missing file: %v %v", entries, err)
}
if ItemCatalog4229938_Find(36000000) != nil {
t.Fatal("stale current catalog")
}
}
func TestShippedItemCatalog(t *testing.T) {
entries, err := LoadItemCatalog4229938("../../data/client_data/Configs")
if err != nil || len(entries) == 0 {
t.Fatalf("shipped consumables not loadable: %v", err)
}
if entry := ItemCatalog4229938_Find(36000000); entry == nil || entry.SubType != 18 {
t.Fatalf("missing known item: %+v", entry)
}
}