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

81 lines
2.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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]
}