Files
ngzz-mc/internal/mods/registry.go

81 lines
2.3 KiB
Go
Raw Normal View History

// Package mods Mod 运行时:generation 版本化注册表、Lua 沙箱、注册 API 与热重载(热更新.md §4、Mod开发指南.md)。
package mods
import (
"fmt"
"sync"
)
// Entry 一个注册条目。
type Entry struct {
Key string // 注册键(如 "block:ruby_ore")
Kind string // block / item / recipe / event / command
Gen uint64 // 注册代数(热更新.md §4.1)
Source string // 来源 Mod ID
Data any // 条目数据(结构由注册方定义)
}
// Registry 注册表(generation 版本化)。
type Registry struct {
mu sync.RWMutex
entries map[string]Entry
gen map[string]uint64 // 来源 → 当前代数
}
// NewRegistry 创建注册表。
func NewRegistry() *Registry {
return &Registry{entries: make(map[string]Entry), gen: make(map[string]uint64)}
}
// Reload 重载一个来源的注册(热更新.md §4.1–§4.2 两阶段 + 提交):
// 先以新代数执行 register;成功才回收旧代条目;失败保留旧版并返回错误。
func (r *Registry) Reload(source string, register func(gen uint64) error) error {
r.mu.Lock()
next := r.gen[source] + 1
r.mu.Unlock()
if err := register(next); err != nil {
return fmt.Errorf("mods.Registry.Reload %s: %w(保留旧版本)", source, err)
}
// 提交:回收旧代
r.mu.Lock()
defer r.mu.Unlock()
for k, e := range r.entries {
if e.Source == source && e.Gen != next {
delete(r.entries, k)
}
}
r.gen[source] = next
return nil
}
// Register 写入条目(register 回调内调用)。
func (r *Registry) Register(source string, gen uint64, kind, key string, data any) error {
r.mu.Lock()
defer r.mu.Unlock()
k := kind + ":" + key
if old, dup := r.entries[k]; dup && old.Source != source {
return fmt.Errorf("mods.Register: 注册键 %q 与 %q 冲突", k, old.Source)
}
r.entries[k] = Entry{Key: k, Kind: kind, Gen: gen, Source: source, Data: data}
return nil
}
// Entries 导出全部条目(只读副本)。
func (r *Registry) Entries() []Entry {
r.mu.RLock()
defer r.mu.RUnlock()
out := make([]Entry, 0, len(r.entries))
for _, e := range r.entries {
out = append(out, e)
}
return out
}
// Gen 返回来源的当前代数。
func (r *Registry) Gen(source string) uint64 {
r.mu.RLock()
defer r.mu.RUnlock()
return r.gen[source]
}