This commit is contained in:
xzb 2023-09-12 17:07:17 +08:00
parent c1dd45bdf5
commit 0124956a51
22 changed files with 57 additions and 2801 deletions

View File

@ -1,15 +0,0 @@
package components
import (
"joylink.club/ecs"
"joylink.club/rtsssimulation/components/cstate"
)
// 按钮状态组件
var ButtonStateComponent = ecs.NewComponentType[cstate.ButtonState]()
// 按钮操作组件
var ButtonPressOperatingComponent = ecs.NewComponentType[cstate.ButtonPressOperating]()
// 按钮确认组件
var ButtonConfirmOperatingComponent = ecs.NewComponentType[cstate.ButtonConfirmOperating]()

View File

@ -1,60 +0,0 @@
package components
import (
"joylink.club/ecs"
"joylink.club/rtsssimulation/components/cstate"
)
// 系统时钟组件
var SystemTimerComponent = ecs.NewComponentType[cstate.SystemTimer]()
// 模型仓库引用组件,单例
var ModelStorageRefComponent = ecs.NewComponentType[cstate.ModelStorageRef]()
// 身份组件
var DeviceIdentityComponent = ecs.NewComponentType[cstate.DeviceIdentity]()
// 存储屏蔽门标签组件
var PsdTagHandlerComponent = ecs.NewComponentType[cstate.EntityTagHandler]()
// 存储继电器标签组件
var RelayTagHandlerComponent = ecs.NewComponentType[cstate.EntityTagHandler]()
// 可移动设备组件
var MovableDeviceStateComponent = ecs.NewComponentType[cstate.MovableDeviceState]()
// 比率设备组件
var PercentageDeviceStateComponent = ecs.NewComponentType[cstate.PercentageDeviceState]()
// 道岔继电器状态组件
var SwitchRelayStateComponent = ecs.NewComponentType[cstate.SwitchRelayState]()
// 物理区段状态组件
var PhysicalSectionStateComponent = ecs.NewComponentType[cstate.PhysicalSectionState]()
// 信号机状态组件
var SignalStateComponent = ecs.NewComponentType[cstate.SignalState]()
// 站台单侧屏蔽门状态组件
var PsdStateComponent = ecs.NewComponentType[cstate.PsdState]()
// 应答器状态组件
var BaliseStateComponent = ecs.NewComponentType[cstate.BaliseState]()
// 列车状态组件
var TrainStateComponent = ecs.NewComponentType[cstate.TrainState]()
// 两档按钮/旋钮状态组件
var TowPositionButtonStateComponent = ecs.NewComponentType[cstate.TowPositionButtonState]()
// 继电器状态组件
var RelayStateComponent = ecs.NewComponentType[cstate.RelayState]()
// 紧急停车按钮状态组件
var EmpStateComponent = ecs.NewComponentType[cstate.EmpState]()
// 生成标签组件
// 用于标记实体便于查找
func NewComponentTag() *ecs.ComponentType[struct{}] {
return ecs.NewComponentType[struct{}]()
}

File diff suppressed because it is too large Load Diff

View File

@ -1,54 +0,0 @@
package cstate
import (
"time"
"github.com/yohamta/donburi/component"
"joylink.club/rtsssimulation/umi"
)
// 此文件中为与设备无关的仿真系统自身的状态定义
// 系统时钟,单例
type SystemTimer struct {
timer *time.Time
}
// 以指定时间构建
func NewSystemTimer(time *time.Time) *SystemTimer {
return &SystemTimer{
timer: time,
}
}
// 重置时间
func (me *SystemTimer) ResetTime(time time.Time) {
*me.timer = time
}
// 获取当前时间的副本
func (me *SystemTimer) Now() time.Time {
return *me.timer
}
// tick系统时钟,单位ms
func (me *SystemTimer) Tick(tick int) {
*me.timer = me.timer.Add(time.Duration(tick) * time.Millisecond)
}
/////////////////////////////////////////////////////////
// 实体标签
type EntityTag = component.IComponentType
type EntityTagHandler struct {
Tag EntityTag
}
/////////////////////////////////////////////////////////
// 模型仓库引用
// 用于world内使用查询模型
type ModelStorageRef struct {
ModelManager umi.IModelManager
}

View File

@ -1,156 +0,0 @@
package creator
import (
"time"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/components/cstate"
"joylink.club/rtsssimulation/system"
"joylink.club/rtsssimulation/umi"
)
// 仿真world配置
type WorldConfig struct {
//模型管理器,接收模型仓库管理器实例的指针
ModelManager umi.IModelManager
//world 系统
Systems []ecs.ISystem
//world tick
Tick int
//world 起始时间
InitTime time.Time
}
// 初始化仿真world
func InitializeWorld(config *WorldConfig) ecs.World {
world := ecs.NewWorld(config.Tick)
// 初始化系统
for _, sys := range config.Systems {
world.AddSystem(sys)
}
// 初始化实体
initEntites(config, world)
//
return world
}
// 初始化实体
func initEntites(config *WorldConfig, world ecs.World) {
modelStorageRefEntry := CreateModelStorageRefEntity(world)
components.ModelStorageRefComponent.Set(modelStorageRefEntry, &cstate.ModelStorageRef{ModelManager: config.ModelManager})
//world time
worldTime := CreateWorldTimeEntity(world)
components.SystemTimerComponent.Set(worldTime, cstate.NewSystemTimer(&config.InitTime))
//
foreachModels(config.ModelManager, umi.Switch, func(md umi.IDeviceModel) {
entry := CreateSwitchEntity(world)
components.DeviceIdentityComponent.Set(entry, &cstate.DeviceIdentity{Id: md.GetId()})
components.SwitchRelayStateComponent.Set(entry, &cstate.SwitchRelayState{DcJ: false, FcJ: false, DbJ: true, FbJ: false})
components.PercentageDeviceStateComponent.Set(entry, &cstate.PercentageDeviceState{Rate: system.SwitchNormalVaule, Target: system.SwitchNormalVaule})
components.MovableDeviceStateComponent.Set(entry, &cstate.MovableDeviceState{ToH: false, Speed: 0, Position: system.SwitchNormalVaule})
})
//
foreachModels(config.ModelManager, umi.Signal, func(md umi.IDeviceModel) {
entry := CreateSignalEntity(world)
components.DeviceIdentityComponent.Set(entry, &cstate.DeviceIdentity{Id: md.GetId()})
components.SignalStateComponent.Set(entry, &cstate.SignalState{Display: cstate.SignalAspect_No})
})
//
foreachModels(config.ModelManager, umi.Psd, func(md umi.IDeviceModel) {
psdEntry := CreatePsdEntity(world)
components.DeviceIdentityComponent.Set(psdEntry, &cstate.DeviceIdentity{Id: md.GetId()})
components.PsdStateComponent.Set(psdEntry, &cstate.PsdState{AllClosed: true, AllOpened: false, InterlockReleased: false})
//
psd := md.(umi.IPsdModel)
for _, psdCell := range psd.AllDeviceCells() {
cellEntry := CreatePsdCellEntity(world, psdEntry)
components.DeviceIdentityComponent.Set(cellEntry, &cstate.DeviceIdentity{Id: psdCell.GetId()})
components.PercentageDeviceStateComponent.Set(cellEntry, &cstate.PercentageDeviceState{Rate: system.PsdCellWholeCloseValue, Target: system.PsdCellWholeCloseValue})
components.MovableDeviceStateComponent.Set(cellEntry, &cstate.MovableDeviceState{ToH: true, Speed: 0, Position: system.PsdCellWholeCloseValue})
}
})
//
foreachModels(config.ModelManager, umi.TowPosButton, func(md umi.IDeviceModel) {
entry := CreateTowPosButtonEntity(world)
components.DeviceIdentityComponent.Set(entry, &cstate.DeviceIdentity{Id: md.GetId()})
components.TowPositionButtonStateComponent.Set(entry, &cstate.TowPositionButtonState{Pos1: false, Pos2: true})
})
}
func foreachModels(modelManager umi.IModelManager, deviceType umi.DeviceType, eachFunc func(deviceModel umi.IDeviceModel)) {
for _, model := range modelManager.FindByType(deviceType) {
eachFunc(model)
}
}
// //////////////////////////////////////////////////////////////////////
// 创建模型仓库引用实体
func CreateModelStorageRefEntity(w ecs.World) *ecs.Entry {
return w.Create(components.ModelStorageRefComponent)
}
// 创建world time 实体
func CreateWorldTimeEntity(w ecs.World) *ecs.Entry {
return w.Create(components.SystemTimerComponent)
}
// 创建道岔实体
func CreateSwitchEntity(w ecs.World) *ecs.Entry {
e := w.Create(components.DeviceIdentityComponent, components.SwitchRelayStateComponent, components.PercentageDeviceStateComponent, components.MovableDeviceStateComponent, components.RelayTagHandlerComponent)
components.RelayTagHandlerComponent.Set(e, &cstate.EntityTagHandler{Tag: components.NewComponentTag()})
return e
}
// 创建信号机实体
func CreateSignalEntity(w ecs.World) *ecs.Entry {
e := w.Create(components.DeviceIdentityComponent, components.SignalStateComponent, components.RelayTagHandlerComponent)
components.RelayTagHandlerComponent.Set(e, &cstate.EntityTagHandler{Tag: components.NewComponentTag()})
return e
}
// 创建物理区段实体
func CreatePhysicalSectionEntity(w ecs.World) *ecs.Entry {
return w.Create(components.DeviceIdentityComponent, components.PhysicalSectionStateComponent)
}
// 创建站台单侧屏蔽门实体
func CreatePsdEntity(w ecs.World) *ecs.Entry {
e := w.Create(components.DeviceIdentityComponent, components.PsdStateComponent, components.PsdTagHandlerComponent, components.RelayTagHandlerComponent)
components.PsdTagHandlerComponent.Set(e, &cstate.EntityTagHandler{Tag: components.NewComponentTag()})
components.RelayTagHandlerComponent.Set(e, &cstate.EntityTagHandler{Tag: components.NewComponentTag()})
return e
}
// 创建屏蔽门cell实体
func CreatePsdCellEntity(w ecs.World, psdEntry *ecs.Entry) *ecs.Entry {
return w.Create(components.DeviceIdentityComponent, components.PercentageDeviceStateComponent, components.MovableDeviceStateComponent, components.PsdTagHandlerComponent.Get(psdEntry).Tag)
}
// 创建应答器实体
func CreateBaliseEntity(w ecs.World) *ecs.Entry {
return w.Create(components.DeviceIdentityComponent, components.BaliseStateComponent)
}
// 创建列车实体
func CreateTrainEntity(w ecs.World) *ecs.Entry {
return w.Create(components.DeviceIdentityComponent, components.TrainStateComponent)
}
// 创建两档位按钮实体
func CreateTowPosButtonEntity(w ecs.World) *ecs.Entry {
return w.Create(components.DeviceIdentityComponent, components.TowPositionButtonStateComponent)
}
// 创建继电器实体
// deviceEntry: 被继电器控制的设备
func CreateRelayEntity(w ecs.World, deviceEntry *ecs.Entry) *ecs.Entry {
return w.Create(components.DeviceIdentityComponent, components.RelayStateComponent, components.RelayTagHandlerComponent.Get(deviceEntry).Tag)
}
// 创建紧急停车按钮实体
func CreateEmpEntity(w ecs.World) *ecs.Entry {
e := w.Create(components.DeviceIdentityComponent, components.EmpStateComponent, components.RelayTagHandlerComponent)
components.RelayTagHandlerComponent.Set(e, &cstate.EntityTagHandler{Tag: components.NewComponentTag()})
return e
}

View File

@ -1,132 +0,0 @@
package main
import (
"time"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components/cstate"
"joylink.club/rtsssimulation/creator"
"joylink.club/rtsssimulation/examples/test1/tmodel"
"joylink.club/rtsssimulation/examples/test1/tstorages"
"joylink.club/rtsssimulation/operate"
"joylink.club/rtsssimulation/system"
)
// 具体共享模型仓库key
var StorageKeyXaV1 = tstorages.StorageKey{LineId: "xa-1", Version: "0.1"}
func main() {
initShareModels()
// 通过共享仓库生成具体仿真world的模型仓库
woldModelStorage := tstorages.ShareStoragesMapper.CreateWorldStorageWithShare(StorageKeyXaV1, initLinkModels())
//
config := &creator.WorldConfig{
ModelManager: woldModelStorage,
Tick: 300,
InitTime: time.Now(),
Systems: []ecs.ISystem{
system.NewMovableDeviceSystem(),
system.NewPercentageDeviceSystem(),
system.NewSwitchSystem(),
system.NewPsdSystem(),
system.NewTimerSystem(),
system.NewDebugSystem()},
}
world := creator.InitializeWorld(config)
//
world.StartUp()
//
time.Sleep(2 * time.Second)
//
//testPsdOpt(world)
//testPsdCellOpt(world)
testSwitchTurn(world)
//
time.Sleep(120 * time.Second)
}
// 构建具体仿真link模型
func initLinkModels() *tstorages.ModelStorage {
mds := tstorages.NewModelStorage()
//
link1 := tmodel.NewLinkModel("link1")
link2 := tmodel.NewLinkModel("link2")
mds.AddModel(link1)
mds.AddModel(link2)
return mds
}
// 构建模型
func initShareModels() {
mds := tstorages.NewModelStorage()
//
signal1 := tmodel.NewSignalModel("signal1")
signal2 := tmodel.NewSignalModel("signal2")
mds.AddModel(signal1)
mds.AddModel(signal2)
//
switch1 := tmodel.NewSwitchModel("switch1")
switch1.TurnTime = 3000
switch2 := tmodel.NewSwitchModel("switch2")
switch2.TurnTime = 2500
mds.AddModel(switch1)
mds.AddModel(switch2)
//
psd1 := tmodel.NewPsdModel("psd1")
psd1.MoveTime = 5000
psd1Cell1 := tmodel.NewPsdCellModel("psd1Cell1", psd1)
psd1Cell2 := tmodel.NewPsdCellModel("psd1Cell2", psd1)
psd2 := tmodel.NewPsdModel("psd2")
psd2.MoveTime = 6000
psd2Cell1 := tmodel.NewPsdCellModel("psd2Cell1", psd2)
psd2Cell2 := tmodel.NewPsdCellModel("psd2Cell2", psd2)
mds.AddModel(psd1)
mds.AddModel(psd1Cell1)
mds.AddModel(psd1Cell2)
mds.AddModel(psd2)
mds.AddModel(psd2Cell1)
mds.AddModel(psd2Cell2)
//
button1 := tmodel.NewTowPosButtonModel("button1")
mds.AddModel(button1)
//
tstorages.ShareStoragesMapper.AddShareModelStorage(StorageKeyXaV1, mds)
}
////////////////////////////////////////////////////////////////
func testPsdOpt(w ecs.World) {
operate.FirePsdOperation(w, "psd1", true)
time.Sleep(5 * time.Second)
operate.FirePsdOperation(w, "psd1", false)
}
func testPsdCellOpt(w ecs.World) {
operate.FirePsdCellOperation(w, "psd1", "psd1Cell1", 0)
operate.FirePsdCellOperation(w, "psd1", "psd1Cell2", 0)
time.Sleep(10 * time.Second)
operate.FirePsdCellOperation(w, "psd1", "psd1Cell1", 100-20)
operate.FirePsdCellOperation(w, "psd1", "psd1Cell2", 100)
//
time.Sleep(10 * time.Second)
operate.FirePsdCellOperation(w, "psd2", "psd2Cell1", 0)
operate.FirePsdCellOperation(w, "psd2", "psd2Cell2", 0)
time.Sleep(10 * time.Second)
operate.FirePsdCellOperation(w, "psd2", "psd2Cell1", 100-20)
operate.FirePsdCellOperation(w, "psd2", "psd2Cell2", 100)
}
func testSwitchTurn(w ecs.World) {
operate.FireSwitchFcj(w, "switch1")
time.Sleep(3 * time.Second)
operate.FireSwitchDcj(w, "switch1")
}
func testSignalOpt(w ecs.World) {
operate.SetSignalDisplay(w, "siganl1", cstate.SignalAspect_B)
}
func testButtonOpt(world ecs.World) {
operate.FireTowPositionButtonMoving(world, "button1")
time.Sleep(3 * time.Second)
operate.FireTowPositionButtonArrivedPos1(world, "button1")
time.Sleep(3 * time.Second)
operate.FireTowPositionButtonArrivedPos2(world, "button1")
}

View File

@ -1,7 +1,6 @@
package tmodel
import (
"joylink.club/rtsssimulation/components/cstate"
"joylink.club/rtsssimulation/umi"
)
@ -10,10 +9,6 @@ type SignalModel struct {
DeviceModel
//信号机所在轨道
LinkOffset *LinkOffsetRef
//信号机类型,出厂已确定,即几个色灯、排列顺序
Type cstate.SignalAspect
//默认显示信号
DefaultDisplay cstate.SignalAspect
}
func NewSignalModel(id string) *SignalModel {

View File

@ -1,28 +0,0 @@
package operate
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/components/cstate"
"joylink.club/rtsssimulation/system"
)
// 应答器查询
var baliseQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.BaliseStateComponent))
//
// 发送消息到应答器
// 当要清空应答器中报文时,则message=nil
func SendMessageToTransponder(world ecs.World, transponderId string, message *cstate.BaliseContent) bool {
transponderEntry := system.QueryEntityById(world, baliseQuery, transponderId)
//
if transponderEntry == nil {
return false
}
//
components.BaliseStateComponent.Get(transponderEntry).Content = message
//
return true
}

View File

@ -1,42 +0,0 @@
package operate
import (
"fmt"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/system"
)
// 紧急停车按钮查询
var empQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.EmpStateComponent))
func findEmpEntry(world ecs.World, empId string) (*ecs.Entry, error) {
empEntry := system.QueryEntityById(world, empQuery, empId)
if empEntry == nil {
return nil, fmt.Errorf("紧急停车按钮[%s]实体不存在", empId)
} else {
return empEntry, nil
}
}
// 激活紧急停车按钮
func FireEmpPressed(world ecs.World, empId string) error {
entry, err := findEmpEntry(world, empId)
if err != nil {
return err
}
components.EmpStateComponent.Get(entry).Pressed = true
return nil
}
// 复位紧急停车按钮
func FireEmpReset(world ecs.World, empId string) error {
entry, err := findEmpEntry(world, empId)
if err != nil {
return err
}
components.EmpStateComponent.Get(entry).Pressed = false
return nil
}

View File

@ -1,37 +0,0 @@
package operate
import (
"fmt"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/system"
)
// 触发比率设备变动到目标比率
// lhDistance: 从L到H的总耗时单位ms
// targetRateValue: 变动的最终目标比率值,[0,100000]
func FirePercentageDevice(world ecs.World, deviceEntry *ecs.Entry, lhDistance int64, targetRateValue int64) error {
if targetRateValue < system.PercentageRateValueMin || targetRateValue > system.PercentageRateValueMax {
return fmt.Errorf("targetRateValue须在[%d,%d]范围内", system.PercentageRateValueMin, system.PercentageRateValueMax)
}
//
id := components.DeviceIdentityComponent.Get(deviceEntry).Id
if !deviceEntry.HasComponent(components.PercentageDeviceStateComponent) {
return fmt.Errorf("比率设备[%s]实体中没有百分比组件", id)
}
if !deviceEntry.HasComponent(components.MovableDeviceStateComponent) {
return fmt.Errorf("比率设备[%s]实体中没有按速度移动组件", id)
}
//
speed := int32(float64(world.Tick()) * (float64(system.PercentageRateValueMax) / float64(lhDistance)))
//
percent := components.PercentageDeviceStateComponent.Get(deviceEntry)
movable := components.MovableDeviceStateComponent.Get(deviceEntry)
//
percent.Target = targetRateValue
movable.Speed = speed
movable.ToH = targetRateValue > percent.Rate
//
return nil
}

View File

@ -1,104 +0,0 @@
package operate
import (
"fmt"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/system"
"joylink.club/rtsssimulation/umi"
)
const (
//屏蔽门完全关闭,百分比
PsdCellWholeCloseRate int8 = system.PercentageRateMax
//屏蔽门完全打开,百分比
PsdCellWholeOpenRate int8 = system.PercentageRateMin
)
// 车站单侧屏蔽门互锁解除操作
func FirePsdInterlockRelease(world ecs.World, psdId string, lockRelease bool) error {
psdEntry, err := findPsdEntry(world, psdId)
if nil != err {
return err
}
components.PsdStateComponent.Get(psdEntry).InterlockReleased = lockRelease
//
return nil
}
// 屏蔽门全开
func FirePsdWholeOpen(world ecs.World, psdId string) error {
return FirePsdOperation(world, psdId, false)
}
// 屏蔽门全关
func FirePsdWholeClose(world ecs.World, psdId string) error {
return FirePsdOperation(world, psdId, true)
}
////////////////////////////////////////////////////////////////////////////////////
// 车站单侧屏蔽门操作
// closeOpt true-关门操作false-开门操作
func FirePsdOperation(world ecs.World, psdId string, closeOpt bool) error {
psdEntry, err := findPsdEntry(world, psdId)
if nil != err {
return err
}
//屏蔽门标签
psdTag := components.PsdTagHandlerComponent.Get(psdEntry).Tag
psdCellQuery := ecs.NewQuery(filter.Contains(psdTag))
var errPercent error = nil
psdCellQuery.Each(world, func(psdCellEntry *ecs.Entry) {
if errPercent == nil {
if closeOpt {
errPercent = FirePercentageDevice(world, psdCellEntry, findPsdWholeMoveTime(world, psdId), system.GetRateValue(PsdCellWholeCloseRate))
} else {
errPercent = FirePercentageDevice(world, psdCellEntry, findPsdWholeMoveTime(world, psdId), system.GetRateValue(PsdCellWholeOpenRate))
}
}
})
//
return errPercent
}
// 车站单侧屏蔽门单元cell操作
// closeRate cell最终关上的百分比100-完全关上0-完全未关即完全打开,(0,100)内即半关闭
func FirePsdCellOperation(world ecs.World, psdId string, psdCellId string, closeRate int8) error {
if closeRate < 0 || closeRate > 100 {
return fmt.Errorf("屏蔽门单元操作closeRate(%d)不在[0,100]内", closeRate)
}
//
psdEntry, err := findPsdEntry(world, psdId)
if nil != err {
return err
}
//屏蔽门标签
psdTag := components.PsdTagHandlerComponent.Get(psdEntry).Tag
psdCellQuery := ecs.NewQuery(filter.Contains(psdTag))
psdCellEntry := system.QueryEntityById(world, psdCellQuery, psdCellId)
if psdCellEntry == nil {
return fmt.Errorf("屏蔽门[%s]的单元门[%s]的实体不存在", psdId, psdCellId)
}
//
return FirePercentageDevice(world, psdCellEntry, findPsdWholeMoveTime(world, psdId), system.GetRateValue(closeRate))
}
// 获取屏蔽门实体
func findPsdEntry(world ecs.World, psdId string) (*ecs.Entry, error) {
psdEntry := system.QueryEntityById(world, system.PsdQuery, psdId)
if psdEntry == nil {
return nil, fmt.Errorf("屏蔽门[%s]实体不存在", psdId)
} else {
return psdEntry, nil
}
}
// 获取屏蔽门从完全开到完全关所需时间单位ms
func findPsdWholeMoveTime(world ecs.World, psdId string) int64 {
psd := system.WorldModelStorage(world).FindById(psdId)
psdUmi := psd.(umi.IPsdModel)
return psdUmi.MovingTime()
}

View File

@ -1,38 +0,0 @@
package operate
import (
"fmt"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/components/cstate"
"joylink.club/rtsssimulation/system"
)
// 信号机显示状态查询
var signalQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.SignalStateComponent))
// 设置某个信号机的显示
// 返回值true-设置成功false-设置失败
func SetSignalDisplay(w ecs.World, signalId string, display cstate.SignalAspect) error {
signalEntry, err := findSignalEntry(w, signalId)
if err != nil {
return err
}
//
signalState := components.SignalStateComponent.Get(signalEntry)
signalState.Display = display
//
return nil
}
// 获取信号机实体
func findSignalEntry(w ecs.World, signalId string) (*ecs.Entry, error) {
var signalEntry *ecs.Entry = system.QueryEntityById(w, signalQuery, signalId)
if signalEntry != nil {
return signalEntry, nil
} else {
return nil, fmt.Errorf("信号机[%s]的实体不存在", signalId)
}
}

View File

@ -1,37 +0,0 @@
package operate
import (
"fmt"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/system"
)
const (
//道岔定位
SwitchNormalRate int8 = system.PercentageRateMin
//道岔反位
SwitchReverseRate int8 = system.PercentageRateMax
)
// 道岔定操
func FireSwitchDcj(w ecs.World, switchId string) error {
return fireSwitchTurn(w, switchId, true)
}
// 道岔反操
func FireSwitchFcj(w ecs.World, switchId string) error {
return fireSwitchTurn(w, switchId, false)
}
func fireSwitchTurn(w ecs.World, switchId string, turnNormal bool) error {
var switchEntry *ecs.Entry = system.QueryEntityById(w, system.SwitchQuery, switchId)
if switchEntry == nil {
return fmt.Errorf("道岔[%s]的实体不存在", switchId)
}
relay := components.SwitchRelayStateComponent.Get(switchEntry)
relay.DcJ = turnNormal
relay.FcJ = !turnNormal
//
return nil
}

View File

@ -1,56 +0,0 @@
package operate
import (
"fmt"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/system"
)
var towPosButtonsQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.TowPositionButtonStateComponent))
// 档位变换过程中指令
// 该指令执行后,按钮处于未知状态
func FireTowPositionButtonMoving(w ecs.World, buttonId string) error {
entry := system.QueryEntityById(w, towPosButtonsQuery, buttonId)
if nil == entry {
return fmt.Errorf("两档位按钮[%s]实体不存在", buttonId)
}
//
state := components.TowPositionButtonStateComponent.Get(entry)
state.Pos1 = false
state.Pos2 = false
//
return nil
}
// 档位变换到达pos1指令
// 执行该指令后按钮处于pos1稳定态
func FireTowPositionButtonArrivedPos1(w ecs.World, buttonId string) error {
return fireTowPositionButtonArrivedPos(w, buttonId, true)
}
// 档位变换到达pos2指令
// 执行该指令后按钮处于pos2稳定态
func FireTowPositionButtonArrivedPos2(w ecs.World, buttonId string) error {
return fireTowPositionButtonArrivedPos(w, buttonId, false)
}
func fireTowPositionButtonArrivedPos(w ecs.World, buttonId string, arrivedPos1 bool) error {
entry := system.QueryEntityById(w, towPosButtonsQuery, buttonId)
if nil == entry {
return fmt.Errorf("两档位按钮[%s]实体不存在", buttonId)
}
//
state := components.TowPositionButtonStateComponent.Get(entry)
if arrivedPos1 {
state.Pos1 = true
state.Pos2 = false
} else {
state.Pos1 = false
state.Pos2 = true
}
//
return nil
}

View File

@ -1,104 +0,0 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
)
// 按钮系统
type ButtonSystem struct {
}
// 按钮组件
var btnIdCom, btnStaCom, btnPreOperCom, btnConOperCom = components.DeviceIdentityComponent,
components.ButtonStateComponent, components.ButtonPressOperatingComponent, components.ButtonConfirmOperatingComponent
// 查询
var btnIdQuery = ecs.NewQuery(filter.Contains(btnIdCom))
var btnUpdateQuery = ecs.NewQuery(filter.Contains(btnStaCom, btnPreOperCom, btnConOperCom))
func NewButtonSystem() *ButtonSystem {
return &ButtonSystem{}
}
// 按钮操作
func PressDownAndUpButton(w ecs.World, btnId string, down bool) bool {
buttonEntry := queryButton(w, btnId)
if buttonEntry == nil {
return false
}
t, b := getButtonBaseInfo(btnId)
if !buttonEntry.HasComponent(btnPreOperCom) { // 操作组件
buttonEntry.AddComponent(btnPreOperCom)
}
preOper := btnPreOperCom.Get(buttonEntry)
preOper.Start, preOper.Down, preOper.NeedConfirm, preOper.OperateTime = true, down, b, t
return true
}
// 确认操作
func ConfirmButton(w ecs.World, btnId string, confirm bool) bool {
buttonEntry := queryButton(w, btnId)
if buttonEntry == nil {
return false
}
if !buttonEntry.HasComponent(btnConOperCom) { // 确认组件
buttonEntry.AddComponent(btnConOperCom)
}
conOper := btnConOperCom.Get(buttonEntry)
conOper.Confirm, conOper.Cancel = confirm, !confirm
return true
}
// 更新按钮状态
func (bs *ButtonSystem) Update(w ecs.World) {
btnUpdateQuery.Each(w, func(e *ecs.Entry) {
if e.HasComponent(btnPreOperCom) {
btnPreOper := btnPreOperCom.Get(e)
if btnPreOper.Start { // 按钮开始操作
if btnPreOper.OperateTime <= 0 { // 按钮操作时间大于0
btnPreOper.Start, btnPreOper.OperateTime = false, 0
} else {
btnPreOper.OperateTime -= int64(w.Tick())
if btnPreOper.NeedConfirm {
conOper := btnConOperCom.Get(e)
if e.HasComponent(btnConOperCom) && (conOper.Cancel || conOper.Confirm) {
if conOper.Confirm {
btnSta := btnStaCom.Get(e)
btnSta.PressDown = btnPreOper.Down
}
btnPreOper.Start, btnPreOper.OperateTime = false, 0
conOper.Cancel, conOper.Confirm = false, false
e.RemoveComponent(btnPreOperCom)
e.RemoveComponent(btnConOperCom)
}
} else {
btnSta := btnStaCom.Get(e)
btnSta.PressDown = btnPreOper.Down
btnPreOper.Start, btnPreOper.OperateTime = false, 0
e.RemoveComponent(btnPreOperCom)
}
}
} else {
e.RemoveComponent(btnPreOperCom)
}
}
})
}
// 查找按钮
func queryButton(w ecs.World, btnId string) *ecs.Entry {
var buttonEntry *ecs.Entry = nil
btnIdQuery.Each(w, func(e *ecs.Entry) {
if id := btnIdCom.Get(e).Id; id == btnId {
buttonEntry = e
}
})
return buttonEntry
}
// 获取按钮设置信息
func getButtonBaseInfo(btnId string) (int64, bool) {
return 15, false
}

View File

@ -1,123 +0,0 @@
package system
import (
"fmt"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
)
// 调试时显示一些信息
type DebugSystem struct {
}
func NewDebugSystem() *DebugSystem {
return &DebugSystem{}
}
// world 执行
func (me *DebugSystem) Update(w ecs.World) {
//debugMovableDevice(w)
//debugPsd(w)
debugSwitch(w)
//debugSignal(w)
//debugTowPosButton(w)
}
// 可按速度移动组件
func debugMovableDevice(w ecs.World) {
query := ecs.NewQuery(filter.Contains(components.PercentageDeviceStateComponent, components.MovableDeviceStateComponent))
query.Each(w, func(e *ecs.Entry) {
id := components.DeviceIdentityComponent.Get(e).Id
if "psd1Cell1" == id {
percent := components.PercentageDeviceStateComponent.Get(e)
movable := components.MovableDeviceStateComponent.Get(e)
fmt.Printf("==>>屏蔽门cell [%s],curRateValue = %d ,targetRateValue = %d , speed = %d position = %d\n", id, percent.Rate, percent.Target, movable.Speed, movable.Position)
}
})
}
// 两档位按钮旋钮
func debugTowPosButton(w ecs.World) {
towPosButtonsQuery := ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.TowPositionButtonStateComponent))
towPosButtonsQuery.Each(w, func(e *ecs.Entry) {
id := components.DeviceIdentityComponent.Get(e).Id
state := components.TowPositionButtonStateComponent.Get(e)
switch {
case state.Pos1 && !state.Pos2:
{
fmt.Printf("两档位按钮[%s],处于 一 档稳态\n", id)
}
case !state.Pos1 && state.Pos2:
{
fmt.Printf("两档位按钮[%s],处于 二 档稳态\n", id)
}
case !state.Pos1 && !state.Pos2:
{
fmt.Printf("两档位按钮[%s],处于未知或变换过程中 ......\n", id)
}
default:
{
fmt.Printf("两档位按钮[%s],异常同时处于 一二 档 \n", id)
}
}
})
}
// 屏蔽门状态
func debugPsd(w ecs.World) {
psdQuery := ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.PsdStateComponent, components.PsdTagHandlerComponent))
psdQuery.Each(w, func(e *ecs.Entry) {
psdId := components.DeviceIdentityComponent.Get(e).Id
psdState := components.PsdStateComponent.Get(e)
psdTag := components.PsdTagHandlerComponent.Get(e).Tag
fmt.Printf("屏蔽门[%s] ,全关=%t ,全开=%t ,互锁解除=%t > ", psdId, psdState.AllClosed, psdState.AllOpened, psdState.InterlockReleased)
//
psdCellQuery := ecs.NewQuery(filter.Contains(psdTag))
psdCellQuery.Each(w, func(e *ecs.Entry) {
psdCellId := components.DeviceIdentityComponent.Get(e).Id
psdCellPercent := components.PercentageDeviceStateComponent.Get(e)
psdCellMovable := components.MovableDeviceStateComponent.Get(e)
//
fmt.Printf("|| cell[%s] ,closeRate=%d ", psdCellId, GetRate(psdCellPercent.Rate))
if psdCellMovable.Speed > 0 {
if psdCellMovable.ToH {
fmt.Printf("== 关门操作中,移动速率=%d", psdCellMovable.Speed)
} else {
fmt.Printf("== 开门操作中,移动速率=%d", psdCellMovable.Speed)
}
}
})
//
fmt.Println()
})
}
// 显示信号机状态
func debugSignal(w ecs.World) {
siganlQuery := ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.SignalStateComponent))
siganlQuery.Each(w, func(e *ecs.Entry) {
id := components.DeviceIdentityComponent.Get(e).Id
state := components.SignalStateComponent.Get(e)
fmt.Printf("==>>信号机[%s],显示=%d\n", id, state.Display)
})
}
// 显示道岔状态
func debugSwitch(w ecs.World) {
switchesQuery := ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent, components.SwitchRelayStateComponent))
switchesQuery.Each(w, func(e *ecs.Entry) {
percent := components.PercentageDeviceStateComponent.Get(e)
movable := components.MovableDeviceStateComponent.Get(e)
id := components.DeviceIdentityComponent.Get(e).Id
curRate := GetRate(percent.Rate)
j := components.SwitchRelayStateComponent.Get(e)
fmt.Printf("道岔 [%s],当前位置百分比 [%d] ,Dcj = %t, Fcj = %t, Dbj = %t ,Fbj = %t ,", id, curRate, j.DcJ, j.FcJ, j.DbJ, j.FbJ)
if movable.Speed > 0 {
fmt.Printf(" ==> 正在转动,移动速率[%d]", movable.Speed)
}
fmt.Println()
})
}

View File

@ -1,31 +0,0 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
)
// 按速度移动的设备系统
// 只负责按速度移动位置,由该组件的观察者负责解释位置
type MovableDeviceSystem struct {
query *ecs.Query
}
func NewMovableDeviceSystem() *MovableDeviceSystem {
return &MovableDeviceSystem{query: ecs.NewQuery(filter.Contains(components.MovableDeviceStateComponent))}
}
// world 执行
func (me *MovableDeviceSystem) Update(world ecs.World) {
me.query.Each(world, func(e *ecs.Entry) {
md := components.MovableDeviceStateComponent.Get(e)
if md.Speed > 0 {
if md.ToH {
md.Position += int64(md.Speed)
} else {
md.Position -= int64(md.Speed)
}
}
})
}

View File

@ -1,63 +0,0 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
)
type PercentageDeviceSystem struct {
query *ecs.Query
}
func NewPercentageDeviceSystem() *PercentageDeviceSystem {
return &PercentageDeviceSystem{query: ecs.NewQuery(filter.Contains(components.PercentageDeviceStateComponent, components.MovableDeviceStateComponent))}
}
const (
PercentageRateValueMax int64 = 100000
PercentageRateValueMin int64 = 0
)
const (
PercentageRateMax int8 = 100
PercentageRateMin int8 = 0
)
// world 执行
func (me *PercentageDeviceSystem) Update(world ecs.World) {
me.query.Each(world, func(e *ecs.Entry) {
movable := components.MovableDeviceStateComponent.Get(e)
if movable.Speed > 0 {
percentage := components.PercentageDeviceStateComponent.Get(e)
if movable.ToH {
if movable.Position >= percentage.Target {
movable.Speed = 0
movable.Position = percentage.Target
}
} else {
if movable.Position <= percentage.Target {
movable.Speed = 0
movable.Position = percentage.Target
}
}
//
percentage.Rate = movable.Position
}
})
}
// 映射百分比到大数值
func GetRateValue(rate int8) int64 {
return int64(float64(float32(rate)/float32(100)) * float64(PercentageRateValueMax))
}
// 大数值映射到百分比
func GetRate(rateValue int64) int8 {
return int8((float64(rateValue) / float64(PercentageRateValueMax)) * float64(100))
}
// 比率值变动速率计算
func CalculateRateSpeed(tick int32, lhDistance int64) int32 {
return int32(float64(tick) * (float64(PercentageRateValueMax) / float64(lhDistance)))
}

View File

@ -1,52 +0,0 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/components/cstate"
)
var PsdQuery = ecs.NewQuery(filter.Contains(components.PsdStateComponent, components.PsdTagHandlerComponent))
const (
//屏蔽门完全关闭
PsdCellWholeCloseValue = PercentageRateValueMax
//屏蔽门完全打开
PsdCellWholeOpenValue = PercentageRateValueMin
)
type PsdSystem struct {
cellsQuery map[cstate.EntityTag]*ecs.Query
}
func NewPsdSystem() *PsdSystem {
return &PsdSystem{cellsQuery: make(map[cstate.EntityTag]*ecs.Query)}
}
// world 执行
func (me *PsdSystem) Update(world ecs.World) {
PsdQuery.Each(world, func(psdEntry *ecs.Entry) {
psdTag := components.PsdTagHandlerComponent.Get(psdEntry).Tag
psdCellQuery, ok := me.cellsQuery[psdTag]
if !ok {
psdCellQuery = ecs.NewQuery(filter.Contains(psdTag, components.PercentageDeviceStateComponent, components.MovableDeviceStateComponent))
me.cellsQuery[psdTag] = psdCellQuery
}
//
var allCellClosed, allCellOpened bool = true, true
psdCellQuery.Each(world, func(psdCellEntry *ecs.Entry) {
psdCellRate := components.PercentageDeviceStateComponent.Get(psdCellEntry).Rate
if allCellClosed {
allCellClosed = psdCellRate == PsdCellWholeCloseValue
}
if allCellOpened {
allCellOpened = psdCellRate == PsdCellWholeOpenValue
}
})
//
psdState := components.PsdStateComponent.Get(psdEntry)
psdState.AllClosed = allCellClosed
psdState.AllOpened = allCellOpened
})
}

View File

@ -1,68 +0,0 @@
package system
import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/umi"
)
var SwitchQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.SwitchRelayStateComponent, components.PercentageDeviceStateComponent))
const (
//道岔定位
SwitchNormalVaule int64 = PercentageRateValueMin
//道岔反位
SwitchReverseValue int64 = PercentageRateValueMax
)
// 道岔系统操作
type SwitchSystem struct {
}
func NewSwitchSystem() *SwitchSystem {
return &SwitchSystem{}
}
// world 执行
func (me *SwitchSystem) Update(w ecs.World) {
//根据定操反操继电器来设置道岔转动参数
SwitchQuery.Each(w, func(e *ecs.Entry) {
relay := components.SwitchRelayStateComponent.Get(e)
if relay.DcJ || relay.FcJ {
movable := components.MovableDeviceStateComponent.Get(e)
percent := components.PercentageDeviceStateComponent.Get(e)
switchId := components.DeviceIdentityComponent.Get(e).Id
if relay.DcJ {
movable.ToH = false
percent.Target = SwitchNormalVaule
}
if relay.FcJ {
movable.ToH = true
percent.Target = SwitchReverseValue
}
movable.Speed = CalculateRateSpeed(int32(w.Tick()), getSwitchTurnTime(w, switchId))
}
})
//观察道岔百分比组件来更新道岔逻辑继电器状态
SwitchQuery.Each(w, func(e *ecs.Entry) {
switchPercent := components.PercentageDeviceStateComponent.Get(e)
switchRelay := components.SwitchRelayStateComponent.Get(e)
if switchPercent.Rate == switchPercent.Target {
switchRelay.DcJ = false
switchRelay.FcJ = false
switchRelay.DbJ = switchPercent.Rate <= SwitchNormalVaule
switchRelay.FbJ = switchPercent.Rate >= SwitchReverseValue
} else {
switchRelay.DbJ = false
switchRelay.FbJ = false
}
})
}
// 获取道岔转动耗时ms
func getSwitchTurnTime(world ecs.World, switchId string) int64 {
dcModel := WorldModelStorage(world).FindById(switchId)
var dc umi.ISwitchModel = dcModel.(umi.ISwitchModel)
return dc.TurningTime()
}

View File

@ -3,14 +3,22 @@ package system
import (
"fmt"
"github.com/yohamta/donburi/component"
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
"joylink.club/rtsssimulation/umi"
)
// 实体身份定义
type EntityIdentity struct {
Id string
}
// 实体身份组件
var EntityIdentityComponent = ecs.NewComponentType[EntityIdentity]()
func FindEntityById(world ecs.World, id string) *ecs.Entry {
query := ecs.NewQuery(filter.Contains(components.DeviceIdentityComponent))
query := ecs.NewQuery(filter.Contains(EntityIdentityComponent))
return QueryEntityById(world, query, id)
}
func QueryEntityById(world ecs.World, q *ecs.Query, id string) *ecs.Entry {
@ -18,7 +26,7 @@ func QueryEntityById(world ecs.World, q *ecs.Query, id string) *ecs.Entry {
func() {
defer simpleRecover()
q.Each(world, func(e *ecs.Entry) {
if id == components.DeviceIdentityComponent.Get(e).Id {
if id == EntityIdentityComponent.Get(e).Id {
entry = e
panic(fmt.Sprintf("找到实体[%s],结束查找", id))
}
@ -33,33 +41,19 @@ func simpleRecover() {
recover()
}
// /////////////////////////////////////////////////////////////////////////
// 模型仓库查询
var worldModelStorageQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.ModelStorageRefComponent))
/////////////////////////////////////////////////////////
func WorldModelStorage(world ecs.World) umi.IModelManager {
e, ok := worldModelStorageQuery.First(world)
if ok {
return components.ModelStorageRefComponent.Get(e).ModelManager
} else {
return nil
}
// 实体标签
type EntityTag = component.IComponentType
type EntityTagHandler struct {
Tag EntityTag
}
// //////////////////////////////////////////////////////////////////////////
// 继电器系统
type relaySystem struct {
// key-设备id
relayQuery map[string]*ecs.Query
}
/////////////////////////////////////////////////////////
// 获取设备的相关继电器的查询
func (me *relaySystem) getDeviceRelayQuery(deviceEntry *ecs.Entry) *ecs.Query {
id := components.DeviceIdentityComponent.Get(deviceEntry).Id
query, ok := me.relayQuery[id]
if !ok {
query = ecs.NewQuery(filter.Contains(components.RelayTagHandlerComponent.Get(deviceEntry).Tag))
me.relayQuery[id] = query
}
return query
// 模型仓库引用
// 用于world内使用查询模型
type ModelStorageRef struct {
ModelManager umi.IModelManager
}

View File

@ -5,10 +5,11 @@ import (
"github.com/yohamta/donburi/filter"
"joylink.club/ecs"
"joylink.club/rtsssimulation/components"
)
var timerQuery *ecs.Query = ecs.NewQuery(filter.Contains(components.SystemTimerComponent))
var SystemTimerComponent = ecs.NewComponentType[SystemTimer]()
var timerQuery *ecs.Query = ecs.NewQuery(filter.Contains(SystemTimerComponent))
// 系统时钟操作
type TimerSystem struct {
@ -21,7 +22,7 @@ func NewTimerSystem() *TimerSystem {
// world 执行
func (me *TimerSystem) Update(w ecs.World) {
if e, ok := timerQuery.First(w); ok {
timer := components.SystemTimerComponent.Get(e)
timer := SystemTimerComponent.Get(e)
timer.Tick(w.Tick())
}
}
@ -29,7 +30,7 @@ func (me *TimerSystem) Update(w ecs.World) {
// 重置world时间
func ResetWorldTimer(w ecs.World, time time.Time) {
if e, ok := timerQuery.First(w); ok {
timer := components.SystemTimerComponent.Get(e)
timer := SystemTimerComponent.Get(e)
timer.ResetTime(time)
}
}
@ -37,9 +38,38 @@ func ResetWorldTimer(w ecs.World, time time.Time) {
// 获取world当前时间
func GetWorldNow(w ecs.World) *time.Time {
if e, ok := timerQuery.First(w); ok {
timer := components.SystemTimerComponent.Get(e)
timer := SystemTimerComponent.Get(e)
now := timer.Now()
return &now
}
return nil
}
/////////////////////////////////////////////////////////////////
// 系统时钟,单例
type SystemTimer struct {
timer *time.Time
}
// 以指定时间构建
func NewSystemTimer(time *time.Time) *SystemTimer {
return &SystemTimer{
timer: time,
}
}
// 重置时间
func (me *SystemTimer) ResetTime(time time.Time) {
*me.timer = time
}
// 获取当前时间的副本
func (me *SystemTimer) Now() time.Time {
return *me.timer
}
// tick系统时钟,单位ms
func (me *SystemTimer) Tick(tick int) {
*me.timer = me.timer.Add(time.Duration(tick) * time.Millisecond)
}