Files
origin/util/blueprint/blueprint.go
2025-11-27 09:15:18 +08:00

224 lines
5.6 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 blueprint
import (
"fmt"
"sync/atomic"
"github.com/duanhf2012/origin/v2/log"
)
type Blueprint struct {
execNodes []IExecNode // 注册的定义执行结点
execNodeList []func() IExecNode
execPool *ExecPool
graphPool *GraphPool
blueprintModule IBlueprintModule
mapGraph map[int64]IGraph
seedID int64
cancelTimer func(*uint64) bool
execDefFilePath string // 执行结点定义文件路径
graphFilePath string // 蓝图文件路径
}
func (bm *Blueprint) RegisterExecNode(execNodeFunc func() IExecNode) {
bm.execNodeList = append(bm.execNodeList, execNodeFunc)
}
type IExecNodeType[T any] interface {
*T
IExecNode
}
// 生成一个泛型函数返回func() IExecNode类型
func NewExecNode[T any, P IExecNodeType[T]]() func() IExecNode {
return func() IExecNode {
var t T
return P(&t)
}
}
func (bm *Blueprint) regSysNodes() {
bm.RegisterExecNode(NewExecNode[AddInt]())
bm.RegisterExecNode(NewExecNode[SubInt]())
bm.RegisterExecNode(NewExecNode[MulInt]())
bm.RegisterExecNode(NewExecNode[DivInt]())
bm.RegisterExecNode(NewExecNode[ModInt]())
bm.RegisterExecNode(NewExecNode[RandNumber]())
bm.RegisterExecNode(NewExecNode[Entrance_ArrayParam]())
bm.RegisterExecNode(NewExecNode[Entrance_IntParam]())
bm.RegisterExecNode(NewExecNode[Entrance_Timer]())
bm.RegisterExecNode(NewExecNode[DebugOutput]())
bm.RegisterExecNode(NewExecNode[Sequence]())
bm.RegisterExecNode(NewExecNode[Foreach]())
bm.RegisterExecNode(NewExecNode[ForeachIntArray]())
bm.RegisterExecNode(NewExecNode[GetArrayInt]())
bm.RegisterExecNode(NewExecNode[GetArrayString]())
bm.RegisterExecNode(NewExecNode[GetArrayLen]())
bm.RegisterExecNode(NewExecNode[CreateIntArray]())
bm.RegisterExecNode(NewExecNode[CreateStringArray]())
bm.RegisterExecNode(NewExecNode[AppendIntegerToArray]())
bm.RegisterExecNode(NewExecNode[AppendStringToArray]())
bm.RegisterExecNode(NewExecNode[BoolIf]())
bm.RegisterExecNode(NewExecNode[GreaterThanInteger]())
bm.RegisterExecNode(NewExecNode[LessThanInteger]())
bm.RegisterExecNode(NewExecNode[EqualInteger]())
bm.RegisterExecNode(NewExecNode[RangeCompare]())
bm.RegisterExecNode(NewExecNode[EqualSwitch]())
bm.RegisterExecNode(NewExecNode[Probability]())
bm.RegisterExecNode(NewExecNode[CreateTimer]())
bm.RegisterExecNode(NewExecNode[AppendIntReturn]())
bm.RegisterExecNode(NewExecNode[AppendStringReturn]())
}
func (bm *Blueprint) StartHotReload() (func(),error) {
var execPool ExecPool
var graphPool GraphPool
// 加载配置结点生成名字对应的innerExecNode
err := execPool.Load(bm.execDefFilePath)
if err != nil {
return nil, err
}
// 将注册的实际执行结点与innerExecNode进行关联
for _, newExec := range bm.execNodeList {
e := newExec()
if !execPool.Register(e) {
return nil,fmt.Errorf("register exec failed,exec:%s", e.GetName())
}
}
// 加载所有的vgf蓝图文件
err = graphPool.Load(&execPool, bm.graphFilePath, bm.blueprintModule)
if err != nil {
return nil, err
}
// 返回配置加载后的刷新内存处理
return func() {
// 替换旧的执行池和图池
bm.execPool = &execPool
bm.graphPool = &graphPool
for _, gh := range bm.mapGraph {
gFileName := gh.GetGraphFileName()
bGraph := bm.graphPool.GetBaseGraph(gFileName)
if bGraph == nil {
log.Warn("GetBaseGraph fail", log.String("graph file name", gFileName))
bGraph = &baseGraph{entrance: map[int64]*execNode{}}
}
gh.HotReload(bGraph)
}
}, nil
}
func (bm *Blueprint) Init(execDefFilePath string, graphFilePath string, blueprintModule IBlueprintModule, cancelTimer func(*uint64) bool) error {
var execPool ExecPool
var graphPool GraphPool
// 加载配置结点生成名字对应的innerExecNode
err := execPool.Load(execDefFilePath)
if err != nil {
return err
}
// 注册系统执行结点
bm.regSysNodes()
// 将注册的实际执行结点与innerExecNode进行关联
for _, newExec := range bm.execNodeList {
e := newExec()
if !execPool.Register(e) {
return fmt.Errorf("register exec failed,exec:%s", e.GetName())
}
}
// 加载所有的vgf蓝图文件
err = graphPool.Load(&execPool, graphFilePath, blueprintModule)
if err != nil {
return err
}
bm.execPool = &execPool
bm.graphPool = &graphPool
bm.cancelTimer = cancelTimer
bm.blueprintModule = blueprintModule
bm.mapGraph = make(map[int64]IGraph, 128)
bm.execDefFilePath = execDefFilePath
bm.graphFilePath = graphFilePath
return nil
}
func (bm *Blueprint) Create(graphName string) int64 {
if graphName == "" {
return 0
}
graphID := atomic.AddInt64(&bm.seedID, 1)
gr := bm.graphPool.Create(graphName, graphID)
if gr == nil {
return 0
}
bm.mapGraph[graphID] = gr
return graphID
}
func (bm *Blueprint) TriggerEvent(graphID int64, eventID int64, args ...any) error {
graph := bm.mapGraph[graphID]
if graph == nil {
return fmt.Errorf("can not find graph:%d", graphID)
}
_, err := graph.Do(eventID, args...)
return err
}
func (bm *Blueprint) Do(graphID int64, entranceID int64, args ...any) (Port_Array, error) {
graph := bm.mapGraph[graphID]
if graph == nil {
return nil, fmt.Errorf("can not find graph:%d", graphID)
}
return graph.Do(entranceID, args...)
}
func (bm *Blueprint) ReleaseGraph(graphID int64) {
if graphID == 0 {
return
}
defer delete(bm.mapGraph, graphID)
graph := bm.mapGraph[graphID]
if graph == nil {
return
}
graph.Release()
}
func (bm *Blueprint) CancelTimerId(graphID int64, timerId *uint64) bool {
tId := *timerId
bm.cancelTimer(timerId)
graph := bm.mapGraph[graphID]
if graph == nil {
return false
}
gr, ok := graph.(*Graph)
if !ok {
return false
}
delete(gr.mapTimerID, tId)
return true
}