Compare commits

..

4 Commits

Author SHA1 Message Date
boyce
21e9b2cd4b 修改ws版本以及结点优化 2025-10-29 11:03:06 +08:00
boyce
969fbe818c 优化portId,提高兼容性 2025-10-28 11:11:36 +08:00
boyce
f3ea9d7c7f 将port index改为id,提高兼容性 2025-10-28 10:36:24 +08:00
boyce
70389b644d 新增结点 2025-10-22 16:13:03 +08:00
12 changed files with 225 additions and 123 deletions

2
go.mod
View File

@@ -12,7 +12,7 @@ require (
github.com/goccy/go-json v0.10.2
github.com/gomodule/redigo v1.8.8
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.0
github.com/gorilla/websocket v1.5.3
github.com/json-iterator/go v1.1.12
github.com/nats-io/nats.go v1.34.1
github.com/pierrec/lz4/v4 v4.1.21

4
go.sum
View File

@@ -88,8 +88,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=

View File

@@ -6,6 +6,8 @@ import (
)
type Blueprint struct {
execNodes []IExecNode // 注册的定义执行结点
execPool ExecPool
graphPool GraphPool
@@ -15,13 +17,51 @@ type Blueprint struct {
cancelTimer func(*uint64)bool
}
func (bm *Blueprint) RegExecNode(execNode IExecNode) {
bm.execNodes = append(bm.execNodes, execNode)
}
func (bm *Blueprint) regSysNode(){
bm.RegExecNode(&AddInt{})
bm.RegExecNode(&SubInt{})
bm.RegExecNode(&MulInt{})
bm.RegExecNode(&DivInt{})
bm.RegExecNode(&ModInt{})
bm.RegExecNode(&RandNumber{})
bm.RegExecNode(&Entrance_ArrayParam{})
bm.RegExecNode(&Entrance_IntParam{})
bm.RegExecNode(&Entrance_Timer{})
bm.RegExecNode(&Output{})
bm.RegExecNode(&Sequence{})
bm.RegExecNode(&Foreach{})
bm.RegExecNode(&ForeachIntArray{})
bm.RegExecNode(&GetArrayInt{})
bm.RegExecNode(&GetArrayString{})
bm.RegExecNode(&GetArrayLen{})
bm.RegExecNode(&CreateIntArray{})
bm.RegExecNode(&CreateStringArray{})
bm.RegExecNode(&AppendIntegerToArray{})
bm.RegExecNode(&AppendStringToArray{})
bm.RegExecNode(&BoolIf{})
bm.RegExecNode(&GreaterThanInteger{})
bm.RegExecNode(&LessThanInteger{})
bm.RegExecNode(&EqualInteger{})
bm.RegExecNode(&RangeCompare{})
bm.RegExecNode(&Probability{})
bm.RegExecNode(&CreateTimer{})
}
func (bm *Blueprint) Init(execDefFilePath string, graphFilePath string, blueprintModule IBlueprintModule,cancelTimer func(*uint64)bool) error {
bm.regSysNode()
err := bm.execPool.Load(execDefFilePath)
if err != nil {
return err
}
for _, e := range execNodes {
for _, e := range bm.execNodes {
if !bm.execPool.Register(e) {
return fmt.Errorf("register exec failed,exec:%s", e.GetName())
}

View File

@@ -5,18 +5,7 @@ import (
)
func TestExecMgr(t *testing.T) {
var bp Blueprint
err := bp.Init("D:\\Develop\\OriginNodeEditor\\json", "D:\\Develop\\OriginNodeEditor\\vgf", nil)
if err != nil {
t.Fatalf("init failed,err:%v", err)
}
graphTest1 := bp.Create("testArrayOperator", 0)
err = graphTest1.Do(EntranceID_IntParam, 20, 1, 3)
if err != nil {
t.Fatalf("Do EntranceID_IntParam failed,err:%v", err)
}
graphTest1.Release()
//graphTest2 := bp.Create("testForeach")
//err = graphTest2.Do(EntranceID_IntParam, 1, 2, 3)
//if err != nil {

View File

@@ -23,7 +23,6 @@ type IInnerExecNode interface {
GetInPort(index int) IPort
GetOutPort(index int) IPort
GetInPortParamStartIndex() int
GetOutPortParamStartIndex() int
}
@@ -43,10 +42,9 @@ type innerExecNode struct {
Package string
Description string
inPort []IPort
outPort []IPort
inPort []IPort // 下标即为portId
outPort []IPort // 下标即为portId
inPortParamStartIndex int // 输入参数的起始索引,用于排除执行入口
outPortParamStartIndex int // 输出参数的起始索引,用于排除执行出口
IExecNode
@@ -67,49 +65,104 @@ type InputConfig struct {
DataType string `json:"data_type"`
HasInput bool `json:"has_input"`
PinWidget string `json:"pin_widget"`
PortId int `json:"port_id"`
}
type OutInputConfig struct {
type OutputConfig struct {
Name string `json:"name"`
PortType string `json:"type"`
DataType string `json:"data_type"`
HasInput bool `json:"has_input"`
PortId int `json:"port_id"`
}
type BaseExecConfig struct {
Name string `json:"name"`
Title string `json:"title"`
Package string `json:"package"`
Description string `json:"description"`
IsPure bool `json:"is_pure"`
Inputs []InputConfig `json:"inputs"`
Outputs []OutInputConfig `json:"outputs"`
Name string `json:"name"`
Title string `json:"title"`
Package string `json:"package"`
Description string `json:"description"`
IsPure bool `json:"is_pure"`
Inputs []InputConfig `json:"inputs"`
Outputs []OutputConfig `json:"outputs"`
}
func (em *innerExecNode) AppendInPort(port ...IPort) {
if len(em.inPort) == 0 {
em.inPortParamStartIndex = -1
}
for i := 0; i < len(port); i++ {
if !port[i].IsPortExec() && em.inPortParamStartIndex < 0 {
em.inPortParamStartIndex = len(em.inPort)
func (bc *BaseExecConfig) GetMaxInPortId() int {
maxPortId := -1
for i := range bc.Inputs {
if bc.Inputs[i].PortId > maxPortId {
maxPortId = bc.Inputs[i].PortId
}
em.inPort = append(em.inPort, port[i])
}
return maxPortId
}
func (em *innerExecNode) AppendOutPort(port ...IPort) {
if len(em.outPort) == 0 {
em.outPortParamStartIndex = -1
}
for i := 0; i < len(port); i++ {
if !port[i].IsPortExec() && em.outPortParamStartIndex < 0 {
em.outPortParamStartIndex = len(em.outPort)
func (bc *BaseExecConfig) GetMaxOutPortId() int {
maxPortId := -1
for i := range bc.Outputs {
if bc.Outputs[i].PortId > maxPortId {
maxPortId = bc.Outputs[i].PortId
}
em.outPort = append(em.outPort, port[i])
}
return maxPortId
}
//func (em *innerExecNode) AppendInPort(port ...IPort) {
// if len(em.inPort) == 0 {
// em.inPortParamStartIndex = -1
// }
//
// for i := 0; i < len(port); i++ {
// if !port[i].IsPortExec() && em.inPortParamStartIndex < 0 {
// em.inPortParamStartIndex = len(em.inPort)
// }
//
// em.inPort = append(em.inPort, port[i])
// }
//}
func (em *innerExecNode) PrepareMaxInPortId(maxInPortId int) {
em.inPort = make([]IPort, 0, maxInPortId+1)
}
func (em *innerExecNode) PrepareMaxOutPortId(maxOutPortId int) {
em.outPort = make([]IPort, 0, maxOutPortId+1)
}
func (em *innerExecNode) SetInPortById(id int, port IPort) bool {
if id < 0 || id >= len(em.inPort) {
return false
}
em.inPort[id] = port
return true
}
func (em *innerExecNode) SetOutPortById(id int, port IPort) bool {
if id < 0 || id >= len(em.outPort) {
return false
}
em.outPort[id] = port
// 分析执行的
em.outPortParamStartIndex = -1
for i := range em.outPort {
if em.outPort[i] == nil {
continue
}
// 遇到非Exec结点即为输出参数开始位置
if !em.outPort[i].IsPortExec() {
em.outPortParamStartIndex = i
break
}
}
return true
}
func (em *innerExecNode) GetOutPortParamStartIndex() int {
return em.outPortParamStartIndex
}
func (em *innerExecNode) GetName() string {
@@ -123,6 +176,10 @@ func (em *innerExecNode) SetExec(exec IExecNode) {
func (em *innerExecNode) CloneInOutPort() ([]IPort, []IPort) {
inPorts := make([]IPort, 0, 2)
for _, port := range em.inPort {
if port == nil {
inPorts = append(inPorts, nil)
}
if port.IsPortExec() {
// 执行入口, 不需要克隆,占位处理
inPorts = append(inPorts, nil)
@@ -134,6 +191,10 @@ func (em *innerExecNode) CloneInOutPort() ([]IPort, []IPort) {
outPorts := make([]IPort, 0, 2)
for _, port := range em.outPort {
if port == nil {
outPorts = append(outPorts, nil)
}
if port.IsPortExec() {
outPorts = append(outPorts, nil)
continue
@@ -182,14 +243,6 @@ func (em *innerExecNode) GetOutPort(index int) IPort {
return em.outPort[index]
}
func (em *innerExecNode) GetInPortParamStartIndex() int {
return em.inPortParamStartIndex
}
func (em *innerExecNode) GetOutPortParamStartIndex() int {
return em.outPortParamStartIndex
}
func (en *BaseExecNode) GetBluePrintModule() IBlueprintModule {
return en.gr.IBlueprintModule
}
@@ -530,8 +583,7 @@ func (en *BaseExecNode) setVariableName(name string) bool {
return false
}
func (en *BaseExecNode) GetBlueprintModule() IBlueprintModule{
func (en *BaseExecNode) GetBlueprintModule() IBlueprintModule {
if en.gr == nil {
return nil
}

View File

@@ -7,6 +7,7 @@ import (
"path/filepath"
"strconv"
"strings"
"sort"
)
// 格式说明Entrance_ID
@@ -83,6 +84,15 @@ func (em *ExecPool) processJSONFile(filePath string) error {
}
for i := range baseExecConfig {
// 排序
sort.Slice(baseExecConfig[i].Inputs, func(left, right int) bool {
return baseExecConfig[i].Inputs[left].PortId < baseExecConfig[i].Inputs[right].PortId
})
sort.Slice(baseExecConfig[i].Outputs, func(left, right int) bool {
return baseExecConfig[i].Outputs[left].PortId < baseExecConfig[i].Outputs[right].PortId
})
exec, err := em.createExecFromJSON(baseExecConfig[i])
if err != nil {
return err
@@ -125,6 +135,8 @@ func (em *ExecPool) createExecFromJSON(baseExecConfig BaseExecConfig) (IInnerExe
baseExec.Title = baseExecConfig.Title
baseExec.Package = baseExecConfig.Package
baseExec.Description = baseExecConfig.Description
baseExec.PrepareMaxInPortId(baseExecConfig.GetMaxInPortId())
baseExec.PrepareMaxOutPortId(baseExecConfig.GetMaxOutPortId())
// exec数量
inExecNum := 0
@@ -143,7 +155,8 @@ func (em *ExecPool) createExecFromJSON(baseExecConfig BaseExecConfig) (IInnerExe
}
inExecNum++
baseExec.AppendInPort(NewPortExec())
baseExec.SetInPortById(input.PortId, NewPortExec())
// baseExec.AppendInPort(NewPortExec())
continue
}
@@ -152,7 +165,7 @@ func (em *ExecPool) createExecFromJSON(baseExecConfig BaseExecConfig) (IInnerExe
return nil, err
}
baseExec.AppendInPort(port)
baseExec.SetInPortById(input.PortId, port)
}
hasData := false
@@ -168,16 +181,17 @@ func (em *ExecPool) createExecFromJSON(baseExecConfig BaseExecConfig) (IInnerExe
}
if portType == Config_PortType_Exec {
baseExec.AppendOutPort(NewPortExec())
baseExec.SetOutPortById(output.PortId, NewPortExec())
continue
}
hasData = true
port, err := em.createPortByDataType(baseExec.Name, output.Name, output.DataType)
if err != nil {
return nil, err
}
baseExec.AppendOutPort(port)
baseExec.SetOutPortById(output.PortId, port)
}
return &baseExec, nil
}
@@ -201,7 +215,7 @@ func (em *ExecPool) Register(exec IExecNode) bool {
return false
}
if _, ok := em.execNodeMap[innerNode.GetName()]; ok {
if _, ok = em.execNodeMap[innerNode.GetName()]; ok {
return false
}
@@ -275,12 +289,13 @@ func (em *ExecPool) loadSysExec() error {
func (em *ExecPool) regGetVariables(typ string) error {
var baseExec innerExecNode
baseExec.Name = genGetVariablesNodeName(typ)
baseExec.PrepareMaxOutPortId(0)
outPort := NewPortByType(typ)
if outPort == nil {
return fmt.Errorf("invalid type %s", typ)
}
baseExec.AppendOutPort(outPort)
baseExec.SetOutPortById(0, outPort)
var getVariablesNode GetVariablesNode
getVariablesNode.nodeName = baseExec.GetName()
@@ -311,9 +326,14 @@ func (em *ExecPool) regSetVariables(typ string) error {
inPort := NewPortByType(typ)
outExecPort := NewPortByType(Config_PortType_Exec)
outPort := NewPortByType(typ)
baseExec.PrepareMaxInPortId(1)
baseExec.PrepareMaxOutPortId(1)
baseExec.AppendInPort(inExecPort, inPort)
baseExec.AppendOutPort(outExecPort, outPort)
baseExec.SetInPortById(0, inExecPort)
baseExec.SetInPortById(1, inPort)
baseExec.SetOutPortById(0, outExecPort)
baseExec.SetOutPortById(1, outPort)
baseExec.IExecNode = &SetVariablesNode{nodeName: baseExec.GetName()}
if !em.loadBaseExec(&baseExec) {

View File

@@ -2,21 +2,23 @@ package blueprint
import (
"fmt"
"github.com/goccy/go-json"
"time"
"github.com/duanhf2012/origin/v2/service"
"github.com/goccy/go-json"
)
const ReturnVarial = "g_Return"
type IGraph interface {
Do(entranceID int64, args ...any) (Port_Array,error)
Do(entranceID int64, args ...any) (Port_Array, error)
Release()
}
type IBlueprintModule interface {
SafeAfterFunc(timerId *uint64, d time.Duration, AdditionData interface{}, cb func(uint64, interface{}))
TriggerEvent(graphID int64, eventID int64, args ...any) error
CancelTimerId(graphID int64,timerId *uint64) bool
CancelTimerId(graphID int64, timerId *uint64) bool
GetGameService() service.IService
GetBattleService() service.IService
}
@@ -52,8 +54,8 @@ type edgeConfig struct {
SourceNodeID string `json:"source_node_id"`
DesNodeId string `json:"des_node_id"`
SourcePortIndex int `json:"source_port_index"`
DesPortIndex int `json:"des_port_index"`
SourcePortId int `json:"source_port_id"`
DesPortId int `json:"des_port_id"`
}
type MultiTypeValue struct {
@@ -134,10 +136,10 @@ func (gc *graphConfig) GetNodeByID(nodeID string) *nodeConfig {
return nil
}
func (gr *Graph) Do(entranceID int64, args ...any) (Port_Array,error) {
func (gr *Graph) Do(entranceID int64, args ...any) (Port_Array, error) {
entranceNode := gr.entrance[entranceID]
if entranceNode == nil {
return nil,fmt.Errorf("entranceID:%d not found", entranceID)
return nil, fmt.Errorf("entranceID:%d not found", entranceID)
}
gr.variables = map[string]IPort{}
@@ -150,17 +152,17 @@ func (gr *Graph) Do(entranceID int64, args ...any) (Port_Array,error) {
return nil, err
}
if gr.globalVariables!= nil {
if gr.globalVariables != nil {
port := gr.globalVariables[ReturnVarial]
if port != nil {
array,ok := port.GetArray()
if ok{
return array,nil
array, ok := port.GetArray()
if ok {
return array, nil
}
}
}
return nil,nil
return nil, nil
}
func (gr *Graph) GetNodeInPortValue(nodeID string, inPortIndex int) IPort {

View File

@@ -2,10 +2,11 @@ package blueprint
import (
"fmt"
"github.com/goccy/go-json"
"os"
"path/filepath"
"strings"
"github.com/goccy/go-json"
)
type GraphPool struct {
@@ -206,7 +207,7 @@ func (gp *GraphPool) prepareOneNode(mapNodeExec map[string]*execNode, nodeExec *
func (gp *GraphPool) findOutNextNode(graphConfig *graphConfig, mapNodeExec map[string]*execNode, sourceNodeID string, sourcePortIdx int) *execNode {
// 找到出口的NodeID
for _, edge := range graphConfig.Edges {
if edge.SourceNodeID == sourceNodeID && edge.SourcePortIndex == sourcePortIdx {
if edge.SourceNodeID == sourceNodeID && edge.SourcePortId == sourcePortIdx {
return mapNodeExec[edge.DesNodeId]
}
}
@@ -254,7 +255,7 @@ func (gp *GraphPool) prepareOneEntrance(graphName string, entranceID int64, node
func (gp *GraphPool) findPreInPortNode(mapNodes map[string]*execNode, nodeExec *execNode, graphConfig *graphConfig, portIdx int) *prePortNode {
for _, edge := range graphConfig.Edges {
if edge.DesNodeId == nodeExec.Id && edge.DesPortIndex == portIdx {
if edge.DesNodeId == nodeExec.Id && edge.DesPortId == portIdx {
srcNode := mapNodes[edge.SourceNodeID]
if srcNode == nil {
return nil
@@ -262,7 +263,7 @@ func (gp *GraphPool) findPreInPortNode(mapNodes map[string]*execNode, nodeExec *
var preNode prePortNode
preNode.node = srcNode
preNode.outPortIndex = edge.SourcePortIndex
preNode.outPortId = edge.SourcePortId
return &preNode
}

View File

@@ -5,14 +5,6 @@ import (
"math/rand"
)
func init() {
RegExecNode(&AddInt{})
RegExecNode(&SubInt{})
RegExecNode(&MulInt{})
RegExecNode(&DivInt{})
RegExecNode(&ModInt{})
RegExecNode(&RandNumber{})
}
// AddInt 加(int)
type AddInt struct {

View File

@@ -5,8 +5,8 @@ import (
)
type prePortNode struct {
node *execNode // 上个结点
outPortIndex int // 对应上一个结点的OutPort索引
node *execNode // 上个结点
outPortId int // 对应上一个结点的OutPortId
}
type execNode struct {
@@ -142,9 +142,9 @@ func (en *execNode) doSetInPort(gr *Graph, index int, inPort IPort) error {
// 判断上一个结点是否已经执行过
if _, ok := gr.context[preNode.node.Id]; ok {
outPort := gr.GetNodeOutPortValue(preNode.node.Id, preNode.outPortIndex)
outPort := gr.GetNodeOutPortValue(preNode.node.Id, preNode.outPortId)
if outPort == nil {
return fmt.Errorf("pre node %s out port index %d not found", preNode.node.Id, preNode.outPortIndex)
return fmt.Errorf("pre node %s out port index %d not found", preNode.node.Id, preNode.outPortId)
}
inPort.SetValue(outPort)
@@ -175,12 +175,12 @@ func (en *execNode) Do(gr *Graph, outPortArgs ...any) error {
// 处理InPort结点值
var err error
for index := range inPorts {
if en.execNode.IsInPortExec(index) {
for portId := range inPorts {
if en.execNode.IsInPortExec(portId) {
continue
}
err = en.doSetInPort(gr, index, inPorts[index])
err = en.doSetInPort(gr, portId, inPorts[portId])
if err != nil {
return err
}

View File

@@ -1,7 +1,4 @@
package blueprint
var execNodes []IExecNode
func RegExecNode(exec IExecNode) {
execNodes = append(execNodes, exec)
}

View File

@@ -2,9 +2,10 @@ package blueprint
import (
"fmt"
"github.com/duanhf2012/origin/v2/log"
"math/rand/v2"
"time"
"github.com/duanhf2012/origin/v2/log"
)
// 系统入口ID定义1000以内
@@ -14,29 +15,7 @@ const (
EntranceID_Timer = 3
)
func init() {
RegExecNode(&Entrance_ArrayParam{})
RegExecNode(&Entrance_IntParam{})
RegExecNode(&Entrance_Timer{})
RegExecNode(&Output{})
RegExecNode(&Sequence{})
RegExecNode(&Foreach{})
RegExecNode(&GetArrayInt{})
RegExecNode(&GetArrayString{})
RegExecNode(&GetArrayLen{})
RegExecNode(&CreateIntArray{})
RegExecNode(&CreateStringArray{})
RegExecNode(&AppendIntegerToArray{})
RegExecNode(&AppendStringToArray{})
RegExecNode(&BoolIf{})
RegExecNode(&GreaterThanInteger{})
RegExecNode(&LessThanInteger{})
RegExecNode(&EqualInteger{})
RegExecNode(&RangeCompare{})
RegExecNode(&Probability{})
RegExecNode(&CreateTimer{})
}
type Entrance_ArrayParam struct {
BaseExecNode
@@ -125,6 +104,36 @@ func (em *Sequence) Exec() (int, error) {
return -1, nil
}
type ForeachIntArray struct {
BaseExecNode
}
func (em *ForeachIntArray) GetName() string {
return "ForeachIntArray"
}
func (em *ForeachIntArray) Exec() (int, error) {
array, ok := em.GetInPortArray(1)
if !ok {
return 0, fmt.Errorf("ForeachIntArray Exec inParam 1 not found")
}
for i := range array {
em.ExecContext.OutputPorts[2].SetInt(array[i].IntVal)
err := em.DoNext(0)
if err != nil {
return -1, err
}
}
err := em.DoNext(1)
if err != nil {
return -1, err
}
return -1, nil
}
type Foreach struct {
BaseExecNode
}
@@ -649,8 +658,8 @@ func (em *CreateTimer) Exec() (int, error) {
if err != nil {
log.Warnf("CreateTimer SafeAfterFunc error timerId:%d err:%v", timerId, err)
}
em.gr.IBlueprintModule.CancelTimerId(graphID,&timerId)
em.gr.IBlueprintModule.CancelTimerId(graphID, &timerId)
})
em.gr.mapTimerID[timerId] = struct{}{}