143 lines
4.8 KiB
Go
143 lines
4.8 KiB
Go
package catalogs
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
)
|
|
|
|
var _ = json.RawMessage{}
|
|
var _ = sync.Mutex{}
|
|
var _ = os.ReadFile
|
|
var _ = filepath.Join
|
|
|
|
// One comment attached to a post. The body lives in the client's TuiteCommentConfig; only the id and its author travel.
|
|
type TuiteComment4229938 struct {
|
|
Id uint32 `json:"id"`
|
|
Publisher uint32 `json:"publisher"`
|
|
}
|
|
|
|
// One 眼界 (Tuite) post instance as the server publishes it, from Configs/TuitePosts.json.
|
|
type TuitePost4229938 struct {
|
|
Id uint32 `json:"id"`
|
|
Publisher uint32 `json:"publisher"`
|
|
Likes int32 `json:"likes"`
|
|
Views int32 `json:"views"`
|
|
Comments []TuiteComment4229938 `json:"comments"`
|
|
Raid []uint32 `json:"raid"`
|
|
AreaId uint32 `json:"areaId"`
|
|
TuiteType uint32 `json:"tuiteType"`
|
|
TaskEvent uint32 `json:"taskEvent"`
|
|
HasVideo bool `json:"hasVideo"`
|
|
}
|
|
|
|
//
|
|
// A publishing NPC's display identity, mirrored from the client's TuiteNPCConfig.
|
|
// Only needed for comments: a post's author comes from TuiteConfig.Publisher and the client
|
|
// resolves it locally (GetTuiteInfo -> TuiteNPCConfig.GetConfig(cfg.Publisher)), but a
|
|
// comment's author is carried by the server in ClientTuiteComment.RoleInfo.
|
|
//
|
|
type TuiteNpc4229938 struct {
|
|
Id uint32 `json:"id"`
|
|
Name string `json:"name"`
|
|
Avatar uint32 `json:"avatar"`
|
|
}
|
|
|
|
//
|
|
// Reads Configs/TuitePosts.json — a projection of the client's own TuiteConfig (204 rows),
|
|
// TuiteCommentConfig (1031 rows) and TuiteNPCConfig (562 rows), built by _gen_tuite_posts.py.
|
|
// This is what fills the 眼界 (Tuite) app: every list in
|
|
// SocialNetWorkUtils.lua (GetRecommendList:143 / GetExploreTuiteList:400 /
|
|
// GetFollowList:431 / GetTuiteListByPubisher:445 / GetCollectionList:1687 / GetLocalTuiteList:3046)
|
|
// reads gPlayerManager.infoMinor.bindData.playerTuiteInfo.TuiteList, and
|
|
// GetTuiteInfo(v) then only does LTConfig.TuiteConfig.GetConfig(v.CfgId) to get the
|
|
// body text, publisher, area and type. So the server owns just the instance — id, counters,
|
|
// publish time and the collect/like/follow flags — and every body stays client-side.
|
|
// The list is published through the login frame's
|
|
// PlayerClientInfoMinor.PlayerTuiteInfo (PlayerInfoMinorData.lua:25), the same channel the
|
|
// 趴卜 schedule uses, so no extra notify is needed.
|
|
// ⛑ HasVideo is deliberately never published as HasTimeline: the timeline blob the
|
|
// client feeds to PlayMultiVideo is one the client itself authors and uploads
|
|
// (AskTuiteUpdateTimelineInfo, 102400-byte limit), so there is no server-side copy of the
|
|
// five video posts' data. Marking them HasTimeline = true would make the client ask for a
|
|
// blob we cannot produce; leaving it false costs only the video, never the post.
|
|
// A missing or malformed file leaves the catalogue empty and LoadError explains why.
|
|
//
|
|
var (
|
|
TuiteCatalog4229938_cacheLock sync.RWMutex
|
|
TuiteCatalog4229938_cached = false
|
|
TuiteCatalog4229938_entries []any
|
|
)
|
|
|
|
// LoadTuiteCatalog4229938 loads catalog records from client config directory
|
|
func LoadTuiteCatalog4229938(configDir string) ([]any, error) {
|
|
TuiteCatalog4229938_cacheLock.RLock()
|
|
if TuiteCatalog4229938_cached {
|
|
defer TuiteCatalog4229938_cacheLock.RUnlock()
|
|
return TuiteCatalog4229938_entries, nil
|
|
}
|
|
TuiteCatalog4229938_cacheLock.RUnlock()
|
|
|
|
TuiteCatalog4229938_cacheLock.Lock()
|
|
defer TuiteCatalog4229938_cacheLock.Unlock()
|
|
if TuiteCatalog4229938_cached { return TuiteCatalog4229938_entries, nil }
|
|
|
|
filePath := filepath.Join(configDir, "TuiteCatalog.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)
|
|
}
|
|
}
|
|
|
|
TuiteCatalog4229938_entries = result
|
|
TuiteCatalog4229938_cached = true
|
|
return result, nil
|
|
}
|
|
|
|
func TuiteCatalog4229938_Find(id uint32) *TuitePost4229938 {
|
|
// Catalog helper TuiteCatalog4229938_Find
|
|
return nil
|
|
}
|
|
|
|
//
|
|
// Position of a post in the catalogue, or -1. Both the login frame and the detail handlers
|
|
// derive PublishTime from it, so the "多久以前" a row shows in the list matches the one
|
|
// on its detail page (the detail INVOKE carries no time of its own).
|
|
//
|
|
func TuiteCatalog4229938_IndexOf(id uint32) int32 {
|
|
// Catalog helper TuiteCatalog4229938_IndexOf
|
|
return 0
|
|
}
|
|
|
|
// Same 10-minute spacing the login frame uses, newest (index 0) first.
|
|
func TuiteCatalog4229938_PublishTimeFor(id uint32, now int64) uint32 {
|
|
// Catalog helper TuiteCatalog4229938_PublishTimeFor
|
|
return 0
|
|
}
|
|
|
|
func TuiteCatalog4229938_Comments(node any) []TuiteComment4229938 {
|
|
// Catalog helper TuiteCatalog4229938_Comments
|
|
return nil
|
|
}
|
|
|
|
func TuiteCatalog4229938_U32List(node any, name string) []uint32 {
|
|
// Catalog helper TuiteCatalog4229938_U32List
|
|
return nil
|
|
}
|
|
|