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

164 lines
6.2 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
// One prop the server restocks: a pathId, a world placement and its blob uid.
type PropRestockItem4229938 struct {
PathId int32 `json:"pathId"`
Name string `json:"name"`
X float32 `json:"x"`
Y float32 `json:"y"`
Z float32 `json:"z"`
Yaw float32 `json:"yaw"`
UniqueId uint64 `json:"uniqueId"`
}
//
// All props captured from the client's own LX6.Item.GadgetBlob that belong to one
// 40 m world cell of one map.
//
//
// Map this cell belongs to: 23300888 = 新启, 23300999 = 重霄·凌云. Cell indices are only
// unique within a raid — two maps reuse the same (cx,cz), so a raid-less table would
// stock map B's props while the player stands in map A.
//
type PropRestockCell4229938 struct {
Raid uint32 `json:"raid"`
Cx int32 `json:"cx"`
Cz int32 `json:"cz"`
Items []PropRestockItem4229938 `json:"items"`
}
//
// Reads Configs/PropRestock.json — the general-purpose restock table for blob props the client
// never instantiates on its own (indoor furniture, vending machines, claw machines, mini-game
// cabinets, basketball courts, bouncy beds, market stalls...).
//
//
// Same data source and same channel as the gym equipment, just not scoped to a venue:
// the placements come straight out of GadgetBlob.tmpPackedGadgetExtendInfo.basePackedInfo
// via GetGadgetBlobData(uid), so pathId / pos / euler / uniqueId are all official values.
// ⛔ Two hard rules that this whole feature rests on (both learned 2026-09-23):
// 1. PackedGadgetInfo.iScale must be 0. 100 yields an entity that exists, has the
// right name/uid/position and even a working interact point, but transform scale (0,0,1) —
// a zero-scale shell with no prefab and a collapsed interact radius.
// 2. Pushing blob data into the client does not instantiate anything. Driving
// ReadHeadInfo + InitSimpleGrid + OnAoiAddBlobCfgByGridIndex leaves
// GadgetInstanceRoot's child count untouched; only SyncGadgetAdd / AddList / AOI do.
// Doors (SpoonSlot_*) are deliberately excluded from the generated file: the T2-11 door
// system already owns them and a double push fights itself.
//
var (
PropRestockCatalog4229938_cacheLock sync.RWMutex
PropRestockCatalog4229938_cached = false
PropRestockCatalog4229938_entries []any
)
// LoadPropRestockCatalog4229938 loads catalog records from client config directory
func LoadPropRestockCatalog4229938(configDir string) ([]any, error) {
PropRestockCatalog4229938_cacheLock.RLock()
if PropRestockCatalog4229938_cached {
defer PropRestockCatalog4229938_cacheLock.RUnlock()
return PropRestockCatalog4229938_entries, nil
}
PropRestockCatalog4229938_cacheLock.RUnlock()
PropRestockCatalog4229938_cacheLock.Lock()
defer PropRestockCatalog4229938_cacheLock.Unlock()
if PropRestockCatalog4229938_cached { return PropRestockCatalog4229938_entries, nil }
filePath := filepath.Join(configDir, "PropRestockCatalog.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)
}
}
PropRestockCatalog4229938_entries = result
PropRestockCatalog4229938_cached = true
return result, nil
}
//
// Every cell of within of the player's
// cell (Chebyshev distance).
//
//
// ⛔ The raid filter is not optional: (cx,cz) is only unique inside one map. Cell (28,39) in
// 新启 and cell (28,39) in 重霄·凌云 are different places with different props, and stocking
// one for the other litters the wrong map with furniture.
//
func PropRestockCatalog4229938_NearCell(raid uint32, cx int32, cz int32, radiusCells int32) []PropRestockCell4229938 {
// Catalog helper PropRestockCatalog4229938_NearCell
return nil
}
// How many cells the table holds for one map (0 = nothing captured there yet).
func PropRestockCatalog4229938_CountForRaid(raid uint32) int32 {
// Catalog helper PropRestockCatalog4229938_CountForRaid
return 0
}
func PropRestockCatalog4229938_LoadTriple() any {
// Catalog helper PropRestockCatalog4229938_LoadTriple
var zero any; return zero
}
//
// u64 that the capture script emits as a JSON string (no double round-trip). System.Text.Json
// throws InvalidOperationException ("requires an element of type 'Number'") if you call
// TryGetUInt64 on a string element, so accept both shapes — one bad uid must not kill the file.
//
//
// ★★★★★ 2026-09-28 —— uid 超出 ulong 时**必须仍给一个稳定的值**,绝不能退化成 0。
// 病因(实测,用户报「两个摊叠在一起」):PropRestock.json 里 Gadget_DaQiQiu_Position
// 那条的 uid 是 "19900000000000007919",而 ulong.MaxValue = 18446744073709551615
// ⇒ 旧代码 ulong.TryParse 失败 ⇒ 返回 0 ⇒ SpawnGadgetAsync 里
// id = uniqueId != 0 ? uniqueId : state.NextSpawnedGadgetId++ **每次补货都 mint 一个新 id**
// ⇒ 同一坐标 (-4750.5,168.6,-2827.6) yaw 315.0 上出现**第二个**气球板实例。
// 实测两次补货:08:41:55 → id=9500000000000;08:42:00 → id=9500000000008。
// (同一批的另外 26 件 uid 正常 ⇒ id 完全一致 ⇒ 幂等;只有这一件在涨。)
// 为什么"幂等"是关键:StartGadgetGrid / StopGadgetGrid 会 ResetPropRestock,
// 而客户端**按 gadgetUId 去重**——id 稳定 ⇒ 重摆同一件是 no-op;id 每次变 ⇒ 每重摆一次就多一个。
// R95 只删掉了摊位表那一份重复(保留本表这份),**没发现本表这份的 uid 根本解析不出来**。
// 修法:按 mod 2^64 回绕(唯一、确定、跨次补货恒定),并把这件事记进 LoadWarnings。
//
func PropRestockCatalog4229938_U64(source any, name string) uint64 {
// Catalog helper PropRestockCatalog4229938_U64
return 0
}
func PropRestockCatalog4229938_Str(source any, name string) string {
// Catalog helper PropRestockCatalog4229938_Str
return ""
}
func PropRestockCatalog4229938_Floats(source any, name string, take int32) []float32 {
// Catalog helper PropRestockCatalog4229938_Floats
return nil
}