165 lines
6.2 KiB
Go
165 lines
6.2 KiB
Go
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
|
||
}
|
||
|