docs: 优化泛型结构体函数的文档展示
This commit is contained in:
parent
5ea3202732
commit
6e6f33899b
|
@ -201,6 +201,32 @@ type Controller[Type generic.Basic, ID generic.Basic, Data any, EntityID generic
|
|||
mutex sync.RWMutex
|
||||
}
|
||||
```
|
||||
#### func (*Controller) GetGlobalData(activityId ID) Data
|
||||
> 获取特定活动全局数据
|
||||
***
|
||||
#### func (*Controller) GetEntityData(activityId ID, entityId EntityID) EntityData
|
||||
> 获取特定活动实体数据
|
||||
***
|
||||
#### func (*Controller) IsOpen(activityId ID) bool
|
||||
> 活动是否开启
|
||||
***
|
||||
#### func (*Controller) IsShow(activityId ID) bool
|
||||
> 活动是否展示
|
||||
***
|
||||
#### func (*Controller) IsOpenOrShow(activityId ID) bool
|
||||
> 活动是否开启或展示
|
||||
***
|
||||
#### func (*Controller) Refresh(activityId ID)
|
||||
> 刷新活动
|
||||
***
|
||||
#### func (*Controller) InitializeNoneData(handler func (activityId ID, data *DataMeta[Data])) NoneDataActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
***
|
||||
#### func (*Controller) InitializeGlobalData(handler func (activityId ID, data *DataMeta[Data])) GlobalDataActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
***
|
||||
#### func (*Controller) InitializeEntityData(handler func (activityId ID, entityId EntityID, data *EntityDataMeta[EntityData])) EntityDataActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
***
|
||||
#### func (*Controller) InitializeGlobalAndEntityData(handler func (activityId ID, data *DataMeta[Data]), entityHandler func (activityId ID, entityId EntityID, data *EntityDataMeta[EntityData])) GlobalAndEntityDataActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
***
|
||||
<span id="struct_BasicActivityController"></span>
|
||||
### BasicActivityController `INTERFACE`
|
||||
|
||||
|
|
|
@ -65,6 +65,63 @@ type TurnBased[CampID comparable, EntityID comparable, Camp generic.IdR[CampID],
|
|||
closed bool
|
||||
}
|
||||
```
|
||||
#### func (*TurnBased) Close()
|
||||
> 关闭回合制
|
||||
***
|
||||
#### func (*TurnBased) AddCamp(camp Camp, entity Entity, entities ...Entity)
|
||||
> 添加阵营
|
||||
***
|
||||
#### func (*TurnBased) SetActionTimeout(actionTimeoutHandler func ( Camp, Entity) time.Duration)
|
||||
> 设置行动超时时间处理函数
|
||||
> - 默认情况下行动超时时间函数将始终返回 0
|
||||
***
|
||||
#### func (*TurnBased) Run()
|
||||
> 运行
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestTurnBased_Run(t *testing.T) {
|
||||
tbi := fight.NewTurnBased[string, string, *Camp, *Entity](func(camp *Camp, entity *Entity) time.Duration {
|
||||
return time.Duration(float64(time.Second) / entity.speed)
|
||||
})
|
||||
tbi.SetActionTimeout(func(camp *Camp, entity *Entity) time.Duration {
|
||||
return time.Second * 5
|
||||
})
|
||||
tbi.RegTurnBasedEntityActionTimeoutEvent(func(controller fight.TurnBasedControllerInfo[string, string, *Camp, *Entity]) {
|
||||
t.Log("时间", time.Now().Unix(), "回合", controller.GetRound(), "阵营", controller.GetCamp().GetId(), "实体", controller.GetEntity().GetId(), "超时")
|
||||
})
|
||||
tbi.RegTurnBasedRoundChangeEvent(func(controller fight.TurnBasedControllerInfo[string, string, *Camp, *Entity]) {
|
||||
t.Log("时间", time.Now().Unix(), "回合", controller.GetRound(), "回合切换")
|
||||
})
|
||||
tbi.RegTurnBasedEntitySwitchEvent(func(controller fight.TurnBasedControllerAction[string, string, *Camp, *Entity]) {
|
||||
switch controller.GetEntity().GetId() {
|
||||
case "1":
|
||||
go func() {
|
||||
time.Sleep(time.Second * 2)
|
||||
controller.Finish()
|
||||
}()
|
||||
case "2":
|
||||
controller.Refresh(time.Second)
|
||||
case "4":
|
||||
controller.Stop()
|
||||
}
|
||||
t.Log("时间", time.Now().Unix(), "回合", controller.GetRound(), "阵营", controller.GetCamp().GetId(), "实体", controller.GetEntity().GetId(), "开始行动")
|
||||
})
|
||||
tbi.AddCamp(&Camp{id: "1"}, &Entity{id: "1", speed: 1}, &Entity{id: "2", speed: 1})
|
||||
tbi.AddCamp(&Camp{id: "2"}, &Entity{id: "3", speed: 1}, &Entity{id: "4", speed: 1})
|
||||
tbi.Run()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
<span id="struct_TurnBasedControllerInfo"></span>
|
||||
### TurnBasedControllerInfo `INTERFACE`
|
||||
|
||||
|
@ -97,6 +154,34 @@ type TurnBasedController[CampID comparable, EntityID comparable, Camp generic.Id
|
|||
tb *TurnBased[CampID, EntityID, Camp, Entity]
|
||||
}
|
||||
```
|
||||
#### func (*TurnBasedController) GetRound() int
|
||||
> 获取当前回合数
|
||||
***
|
||||
#### func (*TurnBasedController) GetCamp() Camp
|
||||
> 获取当前操作阵营
|
||||
***
|
||||
#### func (*TurnBasedController) GetEntity() Entity
|
||||
> 获取当前操作实体
|
||||
***
|
||||
#### func (*TurnBasedController) GetActionTimeoutDuration() time.Duration
|
||||
> 获取当前行动超时时长
|
||||
***
|
||||
#### func (*TurnBasedController) GetActionStartTime() time.Time
|
||||
> 获取当前行动开始时间
|
||||
***
|
||||
#### func (*TurnBasedController) GetActionEndTime() time.Time
|
||||
> 获取当前行动结束时间
|
||||
***
|
||||
#### func (*TurnBasedController) Finish()
|
||||
> 结束当前操作,将立即切换到下一个操作实体
|
||||
***
|
||||
#### func (*TurnBasedController) Stop()
|
||||
> 在当前回合执行完毕后停止回合进程
|
||||
***
|
||||
#### func (*TurnBasedController) Refresh(duration time.Duration) time.Time
|
||||
> 刷新当前操作实体的行动超时时间
|
||||
> - 当不在行动阶段时,将返回 time.Time 零值
|
||||
***
|
||||
<span id="struct_TurnBasedEntitySwitchEventHandler"></span>
|
||||
### TurnBasedEntitySwitchEventHandler `STRUCT`
|
||||
|
||||
|
|
|
@ -70,6 +70,132 @@ type RoomController[EntityID comparable, RoomID comparable, Entity generic.IdR[E
|
|||
owner *EntityID
|
||||
}
|
||||
```
|
||||
#### func (*RoomController) HasOwner() bool
|
||||
> 判断是否有房主
|
||||
***
|
||||
#### func (*RoomController) IsOwner(entityId EntityID) bool
|
||||
> 判断是否为房主
|
||||
***
|
||||
#### func (*RoomController) GetOwner() Entity
|
||||
> 获取房主
|
||||
***
|
||||
#### func (*RoomController) GetOwnerID() EntityID
|
||||
> 获取房主 ID
|
||||
***
|
||||
#### func (*RoomController) GetOwnerExist() ( Entity, bool)
|
||||
> 获取房间,并返回房主是否存在的状态
|
||||
***
|
||||
#### func (*RoomController) SetOwner(entityId EntityID)
|
||||
> 设置房主
|
||||
***
|
||||
#### func (*RoomController) DelOwner()
|
||||
> 删除房主,将房间设置为无主的状态
|
||||
***
|
||||
#### func (*RoomController) JoinSeat(entityId EntityID, seat ...int) error
|
||||
> 设置特定对象加入座位,当具体的座位不存在的时候,将会自动分配座位
|
||||
> - 当目标座位存在玩家或未添加到房间中的时候,将会返回错误
|
||||
***
|
||||
#### func (*RoomController) LeaveSeat(entityId EntityID)
|
||||
> 离开座位
|
||||
***
|
||||
#### func (*RoomController) GetSeat(entityId EntityID) int
|
||||
> 获取座位
|
||||
***
|
||||
#### func (*RoomController) GetFirstNotEmptySeat() int
|
||||
> 获取第一个非空座位号,如果没有非空座位,将返回 UnknownSeat
|
||||
***
|
||||
#### func (*RoomController) GetFirstEmptySeatEntity() (entity Entity)
|
||||
> 获取第一个空座位上的实体,如果没有空座位,将返回空实体
|
||||
***
|
||||
#### func (*RoomController) GetRandomEntity() (entity Entity)
|
||||
> 获取随机实体,如果房间中没有实体,将返回空实体
|
||||
***
|
||||
#### func (*RoomController) GetNotEmptySeat() []int
|
||||
> 获取非空座位
|
||||
***
|
||||
#### func (*RoomController) GetEmptySeat() []int
|
||||
> 获取空座位
|
||||
> - 空座位需要在有对象离开座位后才可能出现
|
||||
***
|
||||
#### func (*RoomController) HasSeat(entityId EntityID) bool
|
||||
> 判断是否有座位
|
||||
***
|
||||
#### func (*RoomController) GetSeatEntityCount() int
|
||||
> 获取座位上的实体数量
|
||||
***
|
||||
#### func (*RoomController) GetSeatEntities() map[EntityID]Entity
|
||||
> 获取座位上的实体
|
||||
***
|
||||
#### func (*RoomController) GetSeatEntitiesByOrdered() []Entity
|
||||
> 有序的获取座位上的实体
|
||||
***
|
||||
#### func (*RoomController) GetSeatEntitiesByOrderedAndContainsEmpty() []Entity
|
||||
> 获取有序的座位上的实体,包含空座位
|
||||
***
|
||||
#### func (*RoomController) GetSeatEntity(seat int) (entity Entity)
|
||||
> 获取座位上的实体
|
||||
***
|
||||
#### func (*RoomController) ContainEntity(id EntityID) bool
|
||||
> 房间内是否包含实体
|
||||
***
|
||||
#### func (*RoomController) GetRoom() Room
|
||||
> 获取原始房间实例,该实例为被接管的房间的原始实例
|
||||
***
|
||||
#### func (*RoomController) GetEntities() map[EntityID]Entity
|
||||
> 获取所有实体
|
||||
***
|
||||
#### func (*RoomController) HasEntity(id EntityID) bool
|
||||
> 判断是否有实体
|
||||
***
|
||||
#### func (*RoomController) GetEntity(id EntityID) Entity
|
||||
> 获取实体
|
||||
***
|
||||
#### func (*RoomController) GetEntityExist(id EntityID) ( Entity, bool)
|
||||
> 获取实体,并返回实体是否存在的状态
|
||||
***
|
||||
#### func (*RoomController) GetEntityIDs() []EntityID
|
||||
> 获取所有实体ID
|
||||
***
|
||||
#### func (*RoomController) GetEntityCount() int
|
||||
> 获取实体数量
|
||||
***
|
||||
#### func (*RoomController) ChangePassword(password *string)
|
||||
> 修改房间密码
|
||||
> - 当房间密码为 nil 时,将会取消密码
|
||||
***
|
||||
#### func (*RoomController) AddEntity(entity Entity) error
|
||||
> 添加实体,如果房间存在密码,应使用 AddEntityByPassword 函数进行添加,否则将始终返回 ErrRoomPasswordNotMatch 错误
|
||||
> - 当房间已满时,将会返回 ErrRoomFull 错误
|
||||
***
|
||||
#### func (*RoomController) AddEntityByPassword(entity Entity, password string) error
|
||||
> 通过房间密码添加实体到该房间中
|
||||
> - 当未设置房间密码时,password 参数将会被忽略
|
||||
> - 当房间密码不匹配时,将会返回 ErrRoomPasswordNotMatch 错误
|
||||
> - 当房间已满时,将会返回 ErrRoomFull 错误
|
||||
***
|
||||
#### func (*RoomController) RemoveEntity(id EntityID)
|
||||
> 移除实体
|
||||
> - 当实体被移除时如果实体在座位上,将会自动离开座位
|
||||
> - 如果实体为房主,将会根据 RoomControllerOptions.WithOwnerInherit 函数的设置进行继承
|
||||
***
|
||||
#### func (*RoomController) RemoveAllEntities()
|
||||
> 移除该房间中的所有实体
|
||||
> - 当实体被移除时如果实体在座位上,将会自动离开座位
|
||||
> - 如果实体为房主,将会根据 RoomControllerOptions.WithOwnerInherit 函数的设置进行继承
|
||||
***
|
||||
#### func (*RoomController) Destroy()
|
||||
> 销毁房间,房间会从 RoomManager 中移除,同时所有房间的实体、座位等数据都会被清空
|
||||
> - 该函数与 RoomManager.DestroyRoom 相同,RoomManager.DestroyRoom 函数为该函数的快捷方式
|
||||
***
|
||||
#### func (*RoomController) GetRoomManager() *RoomManager[EntityID, RoomID, Entity, Room]
|
||||
> 获取该房间控制器所属的房间管理器
|
||||
***
|
||||
#### func (*RoomController) GetRoomID() RoomID
|
||||
> 获取房间 ID
|
||||
***
|
||||
#### func (*RoomController) Broadcast(handler func ( Entity), conditions ...func ( Entity) bool)
|
||||
> 广播,该函数会将所有房间中满足 conditions 的对象传入 handler 中进行处理
|
||||
***
|
||||
<span id="struct_RoomManager"></span>
|
||||
### RoomManager `STRUCT`
|
||||
房间管理器是用于对房间进行管理的基本单元,通过该实例可以对房间进行增删改查等操作
|
||||
|
@ -81,6 +207,53 @@ type RoomManager[EntityID comparable, RoomID comparable, Entity generic.IdR[Enti
|
|||
rooms map[RoomID]*RoomController[EntityID, RoomID, Entity, Room]
|
||||
}
|
||||
```
|
||||
#### func (*RoomManager) AssumeControl(room Room, options ...*RoomControllerOptions[EntityID, RoomID, Entity, Room]) *RoomController[EntityID, RoomID, Entity, Room]
|
||||
> 将房间控制权交由 RoomManager 接管,返回 RoomController 实例
|
||||
> - 当任何房间需要被 RoomManager 管理时,都应该调用该方法获取到 RoomController 实例后进行操作
|
||||
> - 房间被接管后需要在释放房间控制权时调用 RoomController.Destroy 方法,否则将会导致 RoomManager 一直持有房间资源
|
||||
**示例代码:**
|
||||
|
||||
```go
|
||||
|
||||
func ExampleRoomManager_AssumeControl() {
|
||||
var rm = space.NewRoomManager[string, int64, *Player, *Room]()
|
||||
var room = &Room{Id: 1}
|
||||
var controller = rm.AssumeControl(room)
|
||||
if err := controller.AddEntity(&Player{Id: "1"}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(controller.GetEntityCount())
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func (*RoomManager) DestroyRoom(id RoomID)
|
||||
> 销毁房间,该函数为 RoomController.Destroy 的快捷方式
|
||||
***
|
||||
#### func (*RoomManager) GetRoom(id RoomID) *RoomController[EntityID, RoomID, Entity, Room]
|
||||
> 通过房间 ID 获取对应房间的控制器 RoomController,当房间不存在时将返回 nil
|
||||
***
|
||||
#### func (*RoomManager) GetRooms() map[RoomID]*RoomController[EntityID, RoomID, Entity, Room]
|
||||
> 获取包含所有房间 ID 到对应控制器 RoomController 的映射
|
||||
> - 返回值的 map 为拷贝对象,可安全的对其进行增删等操作
|
||||
***
|
||||
#### func (*RoomManager) GetRoomCount() int
|
||||
> 获取房间管理器接管的房间数量
|
||||
***
|
||||
#### func (*RoomManager) GetRoomIDs() []RoomID
|
||||
> 获取房间管理器接管的所有房间 ID
|
||||
***
|
||||
#### func (*RoomManager) HasEntity(entityId EntityID) bool
|
||||
> 判断特定对象是否在任一房间中,当对象不在任一房间中时将返回 false
|
||||
***
|
||||
#### func (*RoomManager) GetEntityRooms(entityId EntityID) map[RoomID]*RoomController[EntityID, RoomID, Entity, Room]
|
||||
> 获取特定对象所在的房间,返回值为房间 ID 到对应控制器 RoomController 的映射
|
||||
> - 由于一个对象可能在多个房间中,因此返回值为 map 类型
|
||||
***
|
||||
#### func (*RoomManager) Broadcast(handler func ( Entity), conditions ...func ( Entity) bool)
|
||||
> 向所有房间对象广播消息,该方法将会遍历所有房间控制器并调用 RoomController.Broadcast 方法
|
||||
***
|
||||
<span id="struct_RoomAssumeControlEventHandle"></span>
|
||||
### RoomAssumeControlEventHandle `STRUCT`
|
||||
|
||||
|
@ -98,3 +271,14 @@ type RoomControllerOptions[EntityID comparable, RoomID comparable, Entity generi
|
|||
ownerInheritHandler func(controller *RoomController[EntityID, RoomID, Entity, Room]) *EntityID
|
||||
}
|
||||
```
|
||||
#### func (*RoomControllerOptions) WithOwnerInherit(inherit bool, inheritHandler ...func (controller *RoomController[EntityID, RoomID, Entity, Room]) *EntityID) *RoomControllerOptions[EntityID, RoomID, Entity, Room]
|
||||
> 设置房间所有者是否继承,默认为 false
|
||||
> - inherit: 是否继承,当未设置 inheritHandler 且 inherit 为 true 时,将会按照随机或根据座位号顺序继承房间所有者
|
||||
> - inheritHandler: 继承处理函数,当 inherit 为 true 时,该函数将会被调用,传入当前房间中的所有实体,返回值为新的房间所有者
|
||||
***
|
||||
#### func (*RoomControllerOptions) WithMaxEntityCount(maxEntityCount int) *RoomControllerOptions[EntityID, RoomID, Entity, Room]
|
||||
> 设置房间最大实体数量
|
||||
***
|
||||
#### func (*RoomControllerOptions) WithPassword(password string) *RoomControllerOptions[EntityID, RoomID, Entity, Room]
|
||||
> 设置房间密码
|
||||
***
|
||||
|
|
|
@ -176,6 +176,15 @@ type Action[P Producer, M Message[P]] struct {
|
|||
d *Dispatcher[P, M]
|
||||
}
|
||||
```
|
||||
#### func (*Action) Name() string
|
||||
> 获取消息分发器名称
|
||||
***
|
||||
#### func (*Action) UnExpel()
|
||||
> 取消特定生产者的驱逐计划
|
||||
***
|
||||
#### func (*Action) Expel()
|
||||
> 设置该消息分发器即将被驱逐,当消息分发器中没有任何消息时,会自动关闭
|
||||
***
|
||||
<span id="struct_Handler"></span>
|
||||
### Handler `STRUCT`
|
||||
消息处理器
|
||||
|
@ -212,6 +221,362 @@ type Dispatcher[P Producer, M Message[P]] struct {
|
|||
abort chan struct{}
|
||||
}
|
||||
```
|
||||
#### func (*Dispatcher) SetProducerDoneHandler(p P, handler func (p P, dispatcher *Action[P, M])) *Dispatcher[P, M]
|
||||
> 设置特定生产者所有消息处理完成时的回调函数
|
||||
> - 如果 handler 为 nil,则会删除该生产者的回调函数
|
||||
>
|
||||
> 需要注意的是,该 handler 中
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestDispatcher_SetProducerDoneHandler(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
producer string
|
||||
messageFinish *atomic.Bool
|
||||
cancel bool
|
||||
}{{name: "TestDispatcher_SetProducerDoneHandlerNotCancel", producer: "producer", cancel: false}, {name: "TestDispatcher_SetProducerDoneHandlerCancel", producer: "producer", cancel: true}}
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
c.messageFinish = &atomic.Bool{}
|
||||
w := new(sync.WaitGroup)
|
||||
d := dispatcher.NewDispatcher(1024, c.name, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
w.Done()
|
||||
})
|
||||
d.Put(&TestMessage{producer: c.producer})
|
||||
d.SetProducerDoneHandler(c.producer, func(p string, dispatcher *dispatcher.Action[string, *TestMessage]) {
|
||||
c.messageFinish.Store(true)
|
||||
})
|
||||
if c.cancel {
|
||||
d.SetProducerDoneHandler(c.producer, nil)
|
||||
}
|
||||
w.Add(1)
|
||||
d.Start()
|
||||
w.Wait()
|
||||
if c.cancel && c.messageFinish.Load() {
|
||||
t.Errorf("%s should cancel, but not", c.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Dispatcher) SetClosedHandler(handler func (dispatcher *Action[P, M])) *Dispatcher[P, M]
|
||||
> 设置消息分发器关闭时的回调函数
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestDispatcher_SetClosedHandler(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
handlerFinishMsgCount *atomic.Int64
|
||||
msgTime time.Duration
|
||||
msgCount int
|
||||
}{{name: "TestDispatcher_SetClosedHandler_Normal", msgTime: 0, msgCount: 1}, {name: "TestDispatcher_SetClosedHandler_MessageCount1024", msgTime: 0, msgCount: 1024}, {name: "TestDispatcher_SetClosedHandler_MessageTime1sMessageCount3", msgTime: 1 * time.Second, msgCount: 3}}
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
c.handlerFinishMsgCount = &atomic.Int64{}
|
||||
w := new(sync.WaitGroup)
|
||||
d := dispatcher.NewDispatcher(1024, c.name, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
time.Sleep(c.msgTime)
|
||||
c.handlerFinishMsgCount.Add(1)
|
||||
})
|
||||
d.SetClosedHandler(func(dispatcher *dispatcher.Action[string, *TestMessage]) {
|
||||
w.Done()
|
||||
})
|
||||
for i := 0; i < c.msgCount; i++ {
|
||||
d.Put(&TestMessage{producer: "producer"})
|
||||
}
|
||||
w.Add(1)
|
||||
d.Start()
|
||||
d.Expel()
|
||||
w.Wait()
|
||||
if c.handlerFinishMsgCount.Load() != int64(c.msgCount) {
|
||||
t.Errorf("%s should finish %d messages, but finish %d", c.name, c.msgCount, c.handlerFinishMsgCount.Load())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Dispatcher) Name() string
|
||||
> 获取消息分发器名称
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestDispatcher_Name(t *testing.T) {
|
||||
var cases = []struct{ name string }{{name: "TestDispatcher_Name_Normal"}}
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
d := dispatcher.NewDispatcher(1024, c.name, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
})
|
||||
if d.Name() != c.name {
|
||||
t.Errorf("%s should equal %s, but not", c.name, c.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Dispatcher) Unique(name string) bool
|
||||
> 设置唯一消息键,返回是否已存在
|
||||
***
|
||||
#### func (*Dispatcher) AntiUnique(name string)
|
||||
> 取消唯一消息键
|
||||
***
|
||||
#### func (*Dispatcher) Expel()
|
||||
> 设置该消息分发器即将被驱逐,当消息分发器中没有任何消息时,会自动关闭
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestDispatcher_Expel(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
handlerFinishMsgCount *atomic.Int64
|
||||
msgTime time.Duration
|
||||
msgCount int
|
||||
}{{name: "TestDispatcher_Expel_Normal", msgTime: 0, msgCount: 1}, {name: "TestDispatcher_Expel_MessageCount1024", msgTime: 0, msgCount: 1024}, {name: "TestDispatcher_Expel_MessageTime1sMessageCount3", msgTime: 1 * time.Second, msgCount: 3}}
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
c.handlerFinishMsgCount = &atomic.Int64{}
|
||||
w := new(sync.WaitGroup)
|
||||
d := dispatcher.NewDispatcher(1024, c.name, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
time.Sleep(c.msgTime)
|
||||
c.handlerFinishMsgCount.Add(1)
|
||||
})
|
||||
d.SetClosedHandler(func(dispatcher *dispatcher.Action[string, *TestMessage]) {
|
||||
w.Done()
|
||||
})
|
||||
for i := 0; i < c.msgCount; i++ {
|
||||
d.Put(&TestMessage{producer: "producer"})
|
||||
}
|
||||
w.Add(1)
|
||||
d.Start()
|
||||
d.Expel()
|
||||
w.Wait()
|
||||
if c.handlerFinishMsgCount.Load() != int64(c.msgCount) {
|
||||
t.Errorf("%s should finish %d messages, but finish %d", c.name, c.msgCount, c.handlerFinishMsgCount.Load())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Dispatcher) UnExpel()
|
||||
> 取消特定生产者的驱逐计划
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestDispatcher_UnExpel(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
closed *atomic.Bool
|
||||
isUnExpel bool
|
||||
expect bool
|
||||
}{{name: "TestDispatcher_UnExpel_Normal", isUnExpel: true, expect: false}, {name: "TestDispatcher_UnExpel_NotExpel", isUnExpel: false, expect: true}}
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
c.closed = &atomic.Bool{}
|
||||
w := new(sync.WaitGroup)
|
||||
d := dispatcher.NewDispatcher(1024, c.name, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
w.Done()
|
||||
})
|
||||
d.SetClosedHandler(func(dispatcher *dispatcher.Action[string, *TestMessage]) {
|
||||
c.closed.Store(true)
|
||||
})
|
||||
d.Put(&TestMessage{producer: "producer"})
|
||||
w.Add(1)
|
||||
if c.isUnExpel {
|
||||
d.Expel()
|
||||
d.UnExpel()
|
||||
} else {
|
||||
d.Expel()
|
||||
}
|
||||
d.Start()
|
||||
w.Wait()
|
||||
if c.closed.Load() != c.expect {
|
||||
t.Errorf("%s should %v, but %v", c.name, c.expect, c.closed.Load())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Dispatcher) IncrCount(producer P, i int64)
|
||||
> 主动增量设置特定生产者的消息计数,这在等待异步消息完成后再关闭消息分发器时非常有用
|
||||
> - 如果 i 为负数,则会减少消息计数
|
||||
***
|
||||
#### func (*Dispatcher) Put(message M)
|
||||
> 将消息放入分发器
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestDispatcher_Put(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
producer string
|
||||
messageDone *atomic.Bool
|
||||
}{{name: "TestDispatcher_Put_Normal", producer: "producer"}}
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
c.messageDone = &atomic.Bool{}
|
||||
w := new(sync.WaitGroup)
|
||||
w.Add(1)
|
||||
d := dispatcher.NewDispatcher(1024, c.name, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
c.messageDone.Store(true)
|
||||
w.Done()
|
||||
})
|
||||
d.Start()
|
||||
d.Put(&TestMessage{producer: c.producer})
|
||||
d.Expel()
|
||||
w.Wait()
|
||||
if !c.messageDone.Load() {
|
||||
t.Errorf("%s should done, but not", c.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Dispatcher) Start() *Dispatcher[P, M]
|
||||
> 以非阻塞的方式开始进行消息分发,当消息分发器中没有任何消息并且处于驱逐计划 Expel 时,将会自动关闭
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestDispatcher_Start(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
producer string
|
||||
messageDone *atomic.Bool
|
||||
}{{name: "TestDispatcher_Start_Normal", producer: "producer"}}
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
c.messageDone = &atomic.Bool{}
|
||||
w := new(sync.WaitGroup)
|
||||
w.Add(1)
|
||||
d := dispatcher.NewDispatcher(1024, c.name, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
c.messageDone.Store(true)
|
||||
w.Done()
|
||||
})
|
||||
d.Start()
|
||||
d.Put(&TestMessage{producer: c.producer})
|
||||
d.Expel()
|
||||
w.Wait()
|
||||
if !c.messageDone.Load() {
|
||||
t.Errorf("%s should done, but not", c.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Dispatcher) Closed() bool
|
||||
> 判断消息分发器是否已关闭
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestDispatcher_Closed(t *testing.T) {
|
||||
var cases = []struct{ name string }{{name: "TestDispatcher_Closed_Normal"}}
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
w := new(sync.WaitGroup)
|
||||
w.Add(1)
|
||||
d := dispatcher.NewDispatcher(1024, c.name, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
})
|
||||
d.SetClosedHandler(func(dispatcher *dispatcher.Action[string, *TestMessage]) {
|
||||
w.Done()
|
||||
})
|
||||
d.Start()
|
||||
d.Expel()
|
||||
w.Wait()
|
||||
if !d.Closed() {
|
||||
t.Errorf("%s should closed, but not", c.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
<span id="struct_Manager"></span>
|
||||
### Manager `STRUCT`
|
||||
消息分发器管理器
|
||||
|
@ -229,6 +594,295 @@ type Manager[P Producer, M Message[P]] struct {
|
|||
createdHandler func(name string)
|
||||
}
|
||||
```
|
||||
#### func (*Manager) Wait()
|
||||
> 等待所有消息分发器关闭
|
||||
***
|
||||
#### func (*Manager) SetDispatcherClosedHandler(handler func (name string)) *Manager[P, M]
|
||||
> 设置消息分发器关闭时的回调函数
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestManager_SetDispatcherClosedHandler(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
setCloseHandler bool
|
||||
}{{name: "TestManager_SetDispatcherClosedHandler_Set", setCloseHandler: true}, {name: "TestManager_SetDispatcherClosedHandler_NotSet", setCloseHandler: false}}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
var closed atomic.Bool
|
||||
m := dispatcher.NewManager[string, *TestMessage](1024, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
})
|
||||
if c.setCloseHandler {
|
||||
m.SetDispatcherClosedHandler(func(name string) {
|
||||
closed.Store(true)
|
||||
})
|
||||
}
|
||||
m.BindProducer(c.name, c.name)
|
||||
m.UnBindProducer(c.name)
|
||||
m.Wait()
|
||||
if c.setCloseHandler && !closed.Load() {
|
||||
t.Errorf("SetDispatcherClosedHandler() should be called")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Manager) SetDispatcherCreatedHandler(handler func (name string)) *Manager[P, M]
|
||||
> 设置消息分发器创建时的回调函数
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestManager_SetDispatcherCreatedHandler(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
setCreatedHandler bool
|
||||
}{{name: "TestManager_SetDispatcherCreatedHandler_Set", setCreatedHandler: true}, {name: "TestManager_SetDispatcherCreatedHandler_NotSet", setCreatedHandler: false}}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
var created atomic.Bool
|
||||
m := dispatcher.NewManager[string, *TestMessage](1024, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
})
|
||||
if c.setCreatedHandler {
|
||||
m.SetDispatcherCreatedHandler(func(name string) {
|
||||
created.Store(true)
|
||||
})
|
||||
}
|
||||
m.BindProducer(c.name, c.name)
|
||||
m.UnBindProducer(c.name)
|
||||
m.Wait()
|
||||
if c.setCreatedHandler && !created.Load() {
|
||||
t.Errorf("SetDispatcherCreatedHandler() should be called")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Manager) HasDispatcher(name string) bool
|
||||
> 检查是否存在指定名称的消息分发器
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestManager_HasDispatcher(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
bindName string
|
||||
has bool
|
||||
}{{name: "TestManager_HasDispatcher_Has", bindName: "TestManager_HasDispatcher_Has", has: true}, {name: "TestManager_HasDispatcher_NotHas", bindName: "TestManager_HasDispatcher_NotHas", has: false}}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
m := dispatcher.NewManager[string, *TestMessage](1024, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
})
|
||||
m.BindProducer(c.bindName, c.bindName)
|
||||
var cond string
|
||||
if c.has {
|
||||
cond = c.bindName
|
||||
}
|
||||
if m.HasDispatcher(cond) != c.has {
|
||||
t.Errorf("HasDispatcher() should return %v", c.has)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Manager) GetDispatcherNum() int
|
||||
> 获取当前正在工作的消息分发器数量
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestManager_GetDispatcherNum(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
num int
|
||||
}{{name: "TestManager_GetDispatcherNum_N1", num: -1}, {name: "TestManager_GetDispatcherNum_0", num: 0}, {name: "TestManager_GetDispatcherNum_1", num: 1}, {name: "TestManager_GetDispatcherNum_2", num: 2}}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
m := dispatcher.NewManager[string, *TestMessage](1024, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
})
|
||||
switch {
|
||||
case c.num <= 0:
|
||||
return
|
||||
case c.num == 1:
|
||||
if m.GetDispatcherNum() != 1 {
|
||||
t.Errorf("GetDispatcherNum() should return 1")
|
||||
}
|
||||
return
|
||||
default:
|
||||
for i := 0; i < c.num-1; i++ {
|
||||
m.BindProducer(fmt.Sprintf("%s_%d", c.name, i), fmt.Sprintf("%s_%d", c.name, i))
|
||||
}
|
||||
if m.GetDispatcherNum() != c.num {
|
||||
t.Errorf("GetDispatcherNum() should return %v", c.num)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Manager) GetSystemDispatcher() *Dispatcher[P, M]
|
||||
> 获取系统消息分发器
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestManager_GetSystemDispatcher(t *testing.T) {
|
||||
var cases = []struct{ name string }{{name: "TestManager_GetSystemDispatcher"}}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
m := dispatcher.NewManager[string, *TestMessage](1024, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
})
|
||||
if m.GetSystemDispatcher() == nil {
|
||||
t.Errorf("GetSystemDispatcher() should not return nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Manager) GetDispatcher(p P) *Dispatcher[P, M]
|
||||
> 获取生产者正在使用的消息分发器,如果生产者没有绑定消息分发器,则会返回系统消息分发器
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestManager_GetDispatcher(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
bindName string
|
||||
}{{name: "TestManager_GetDispatcher", bindName: "TestManager_GetDispatcher"}}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
m := dispatcher.NewManager[string, *TestMessage](1024, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
})
|
||||
m.BindProducer(c.bindName, c.bindName)
|
||||
if m.GetDispatcher(c.bindName) == nil {
|
||||
t.Errorf("GetDispatcher() should not return nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Manager) BindProducer(p P, name string)
|
||||
> 绑定生产者使用特定的消息分发器,如果生产者已经绑定了消息分发器,则会先解绑
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestManager_BindProducer(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
bindName string
|
||||
}{{name: "TestManager_BindProducer", bindName: "TestManager_BindProducer"}}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
m := dispatcher.NewManager[string, *TestMessage](1024, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
})
|
||||
m.BindProducer(c.bindName, c.bindName)
|
||||
if m.GetDispatcher(c.bindName) == nil {
|
||||
t.Errorf("GetDispatcher() should not return nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Manager) UnBindProducer(p P)
|
||||
> 解绑生产者使用特定的消息分发器
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestManager_UnBindProducer(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
bindName string
|
||||
}{{name: "TestManager_UnBindProducer", bindName: "TestManager_UnBindProducer"}}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
m := dispatcher.NewManager[string, *TestMessage](1024, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
})
|
||||
m.BindProducer(c.bindName, c.bindName)
|
||||
m.UnBindProducer(c.bindName)
|
||||
if m.GetDispatcher(c.bindName) != m.GetSystemDispatcher() {
|
||||
t.Errorf("GetDispatcher() should return SystemDispatcher")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
<span id="struct_Message"></span>
|
||||
### Message `INTERFACE`
|
||||
|
||||
|
|
|
@ -59,10 +59,8 @@ type Dispatcher[P Producer, M Message[P]] struct {
|
|||
abort chan struct{}
|
||||
}
|
||||
|
||||
// SetProducerDoneHandler 设置特定生产者所有消息处理完成时的回调函数
|
||||
// SetProducerDoneHandler 设置特定生产者的所有消息处理完成时的回调函数
|
||||
// - 如果 handler 为 nil,则会删除该生产者的回调函数
|
||||
//
|
||||
// 需要注意的是,该 handler 中
|
||||
func (d *Dispatcher[P, M]) SetProducerDoneHandler(p P, handler func(p P, dispatcher *Action[P, M])) *Dispatcher[P, M] {
|
||||
d.lock.Lock()
|
||||
if handler == nil {
|
||||
|
|
|
@ -152,6 +152,59 @@ type Lockstep[ClientID comparable, Command any] struct {
|
|||
lockstepStoppedEventHandles []StoppedEventHandle[ClientID, Command]
|
||||
}
|
||||
```
|
||||
#### func (*Lockstep) JoinClient(client Client[ClientID])
|
||||
> 将客户端加入到广播队列中,通常在开始广播前使用
|
||||
> - 如果客户端在开始广播后加入,将丢失之前的帧数据,如要从特定帧开始追帧请使用 JoinClientWithFrame
|
||||
***
|
||||
#### func (*Lockstep) JoinClientWithFrame(client Client[ClientID], frameIndex int64)
|
||||
> 加入客户端到广播队列中,并从特定帧开始追帧
|
||||
> - 可用于重连及状态同步、帧同步混用的情况
|
||||
> - 混用:服务端记录指令时同时做一次状态计算,新客户端加入时直接同步当前状态,之后从特定帧开始广播
|
||||
***
|
||||
#### func (*Lockstep) GetClientCount() int
|
||||
> 获取客户端数量
|
||||
***
|
||||
#### func (*Lockstep) DropCache(handler func (frame int64) bool)
|
||||
> 丢弃特定帧的缓存,当 handler 返回 true 时将丢弃缓存
|
||||
***
|
||||
#### func (*Lockstep) LeaveClient(clientId ClientID)
|
||||
> 将客户端从广播队列中移除
|
||||
***
|
||||
#### func (*Lockstep) StartBroadcast()
|
||||
> 开始广播
|
||||
> - 在开始广播后将持续按照设定的帧率进行帧数推进,并在每一帧推进时向客户端进行同步,需提前将客户端加入广播队列 JoinClient
|
||||
> - 广播过程中使用 AddCommand 将该帧数据追加到当前帧中
|
||||
***
|
||||
#### func (*Lockstep) StopBroadcast()
|
||||
> 停止广播
|
||||
***
|
||||
#### func (*Lockstep) IsRunning() bool
|
||||
> 是否正在广播
|
||||
***
|
||||
#### func (*Lockstep) AddCommand(command Command)
|
||||
> 添加命令到当前帧
|
||||
***
|
||||
#### func (*Lockstep) AddCommands(commands []Command)
|
||||
> 添加命令到当前帧
|
||||
***
|
||||
#### func (*Lockstep) GetCurrentFrame() int64
|
||||
> 获取当前帧
|
||||
***
|
||||
#### func (*Lockstep) GetClientCurrentFrame(clientId ClientID) int64
|
||||
> 获取客户端当前帧
|
||||
***
|
||||
#### func (*Lockstep) GetFrameLimit() int64
|
||||
> 获取帧上限
|
||||
> - 未设置时将返回0
|
||||
***
|
||||
#### func (*Lockstep) GetCurrentCommands() []Command
|
||||
> 获取当前帧还未结束时的所有指令
|
||||
***
|
||||
#### func (*Lockstep) RegLockstepStoppedEvent(handle StoppedEventHandle[ClientID, Command])
|
||||
> 当广播停止时将触发被注册的事件处理函数
|
||||
***
|
||||
#### func (*Lockstep) OnLockstepStoppedEvent()
|
||||
***
|
||||
<span id="struct_Option"></span>
|
||||
### Option `STRUCT`
|
||||
|
||||
|
|
|
@ -83,6 +83,18 @@ type TwoDimensional[EID generic.Basic, PosType generic.SignedNumber, E TwoDimens
|
|||
repartitionQueue []func()
|
||||
}
|
||||
```
|
||||
#### func (*TwoDimensional) AddEntity(entity E)
|
||||
***
|
||||
#### func (*TwoDimensional) DeleteEntity(entity E)
|
||||
***
|
||||
#### func (*TwoDimensional) Refresh(entity E)
|
||||
***
|
||||
#### func (*TwoDimensional) GetFocus(id EID) map[EID]E
|
||||
***
|
||||
#### func (*TwoDimensional) SetSize(width int, height int)
|
||||
***
|
||||
#### func (*TwoDimensional) SetAreaSize(width int, height int)
|
||||
***
|
||||
<span id="struct_TwoDimensionalEntity"></span>
|
||||
### TwoDimensionalEntity `INTERFACE`
|
||||
基于2D定义的AOI对象功能接口
|
||||
|
|
|
@ -127,6 +127,25 @@ type Area[ID comparable, AreaInfo any] struct {
|
|||
evaluate AreaEvaluateHandle[ID, AreaInfo]
|
||||
}
|
||||
```
|
||||
#### func (*Area) GetAreaInfo() AreaInfo
|
||||
> 获取编排区域的信息
|
||||
***
|
||||
#### func (*Area) GetItems() map[ID]Item[ID]
|
||||
> 获取编排区域中的所有成员
|
||||
***
|
||||
#### func (*Area) IsAllow(item Item[ID]) (constraintErr error, conflictItems map[ID]Item[ID], allow bool)
|
||||
> 检测一个成员是否可以被添加到该编排区域中
|
||||
***
|
||||
#### func (*Area) IsConflict(item Item[ID]) bool
|
||||
> 检测一个成员是否会造成冲突
|
||||
***
|
||||
#### func (*Area) GetConflictItems(item Item[ID]) map[ID]Item[ID]
|
||||
> 获取与一个成员产生冲突的所有其他成员
|
||||
***
|
||||
#### func (*Area) GetScore(extra ...Item[ID]) float64
|
||||
> 获取该编排区域的评估分数
|
||||
> - 当 extra 不为空时,将会将 extra 中的内容添加到 items 中进行评估
|
||||
***
|
||||
<span id="struct_AreaOption"></span>
|
||||
### AreaOption `STRUCT`
|
||||
编排区域选项
|
||||
|
@ -157,6 +176,65 @@ type Arrangement[ID comparable, AreaInfo any] struct {
|
|||
conflictHandles []ConflictHandle[ID, AreaInfo]
|
||||
}
|
||||
```
|
||||
#### func (*Arrangement) AddArea(areaInfo AreaInfo, options ...AreaOption[ID, AreaInfo])
|
||||
> 添加一个编排区域
|
||||
***
|
||||
#### func (*Arrangement) AddItem(item Item[ID])
|
||||
> 添加一个成员
|
||||
***
|
||||
#### func (*Arrangement) Arrange() (areas []*Area[ID, AreaInfo], noSolution map[ID]Item[ID])
|
||||
> 编排
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestArrangement_Arrange(t *testing.T) {
|
||||
var a = arrangement.NewArrangement[int, *Team]()
|
||||
a.AddArea(&Team{ID: 1}, arrangement.WithAreaConstraint[int, *Team](func(area *arrangement.Area[int, *Team], item arrangement.Item[int]) error {
|
||||
if len(area.GetItems()) >= 2 {
|
||||
return errors.New("too many")
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
a.AddArea(&Team{ID: 2}, arrangement.WithAreaConstraint[int, *Team](func(area *arrangement.Area[int, *Team], item arrangement.Item[int]) error {
|
||||
if len(area.GetItems()) >= 1 {
|
||||
return errors.New("too many")
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
a.AddArea(&Team{ID: 3}, arrangement.WithAreaConstraint[int, *Team](func(area *arrangement.Area[int, *Team], item arrangement.Item[int]) error {
|
||||
if len(area.GetItems()) >= 2 {
|
||||
return errors.New("too many")
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
for i := 0; i < 10; i++ {
|
||||
a.AddItem(&Player{ID: i + 1})
|
||||
}
|
||||
res, no := a.Arrange()
|
||||
for _, area := range res {
|
||||
var str = fmt.Sprintf("area %d: ", area.GetAreaInfo().ID)
|
||||
for id := range area.GetItems() {
|
||||
str += fmt.Sprintf("%d ", id)
|
||||
}
|
||||
fmt.Println(str)
|
||||
}
|
||||
var noStr = "no: "
|
||||
for _, i := range no {
|
||||
noStr += fmt.Sprintf("%d ", i.GetID())
|
||||
}
|
||||
fmt.Println(noStr)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
<span id="struct_Editor"></span>
|
||||
### Editor `STRUCT`
|
||||
提供了大量辅助函数的编辑器
|
||||
|
@ -169,6 +247,48 @@ type Editor[ID comparable, AreaInfo any] struct {
|
|||
retryCount int
|
||||
}
|
||||
```
|
||||
#### func (*Editor) GetPendingCount() int
|
||||
> 获取待编排的成员数量
|
||||
***
|
||||
#### func (*Editor) RemoveAreaItem(area *Area[ID, AreaInfo], item Item[ID])
|
||||
> 从编排区域中移除一个成员到待编排队列中,如果该成员不存在于编排区域中,则不进行任何操作
|
||||
***
|
||||
#### func (*Editor) AddAreaItem(area *Area[ID, AreaInfo], item Item[ID])
|
||||
> 将一个成员添加到编排区域中,如果该成员已经存在于编排区域中,则不进行任何操作
|
||||
***
|
||||
#### func (*Editor) GetAreas() []*Area[ID, AreaInfo]
|
||||
> 获取所有的编排区域
|
||||
***
|
||||
#### func (*Editor) GetAreasWithScoreAsc(extra ...Item[ID]) []*Area[ID, AreaInfo]
|
||||
> 获取所有的编排区域,并按照分数升序排序
|
||||
***
|
||||
#### func (*Editor) GetAreasWithScoreDesc(extra ...Item[ID]) []*Area[ID, AreaInfo]
|
||||
> 获取所有的编排区域,并按照分数降序排序
|
||||
***
|
||||
#### func (*Editor) GetRetryCount() int
|
||||
> 获取重试次数
|
||||
***
|
||||
#### func (*Editor) GetThresholdProgressRate() float64
|
||||
> 获取重试次数阈值进度
|
||||
***
|
||||
#### func (*Editor) GetAllowAreas(item Item[ID]) []*Area[ID, AreaInfo]
|
||||
> 获取允许的编排区域
|
||||
***
|
||||
#### func (*Editor) GetNoAllowAreas(item Item[ID]) []*Area[ID, AreaInfo]
|
||||
> 获取不允许的编排区域
|
||||
***
|
||||
#### func (*Editor) GetBestAllowArea(item Item[ID]) *Area[ID, AreaInfo]
|
||||
> 获取最佳的允许的编排区域,如果不存在,则返回 nil
|
||||
***
|
||||
#### func (*Editor) GetBestNoAllowArea(item Item[ID]) *Area[ID, AreaInfo]
|
||||
> 获取最佳的不允许的编排区域,如果不存在,则返回 nil
|
||||
***
|
||||
#### func (*Editor) GetWorstAllowArea(item Item[ID]) *Area[ID, AreaInfo]
|
||||
> 获取最差的允许的编排区域,如果不存在,则返回 nil
|
||||
***
|
||||
#### func (*Editor) GetWorstNoAllowArea(item Item[ID]) *Area[ID, AreaInfo]
|
||||
> 获取最差的不允许的编排区域,如果不存在,则返回 nil
|
||||
***
|
||||
<span id="struct_Item"></span>
|
||||
### Item `INTERFACE`
|
||||
编排成员
|
||||
|
|
|
@ -46,3 +46,55 @@ type SyncMap[K comparable, V any] struct {
|
|||
atom bool
|
||||
}
|
||||
```
|
||||
#### func (*SyncMap) Set(key K, value V)
|
||||
> 设置一个值
|
||||
***
|
||||
#### func (*SyncMap) Get(key K) V
|
||||
> 获取一个值
|
||||
***
|
||||
#### func (*SyncMap) Atom(handle func (m map[K]V))
|
||||
> 原子操作
|
||||
***
|
||||
#### func (*SyncMap) Exist(key K) bool
|
||||
> 判断是否存在
|
||||
***
|
||||
#### func (*SyncMap) GetExist(key K) ( V, bool)
|
||||
> 获取一个值并判断是否存在
|
||||
***
|
||||
#### func (*SyncMap) Delete(key K)
|
||||
> 删除一个值
|
||||
***
|
||||
#### func (*SyncMap) DeleteGet(key K) V
|
||||
> 删除一个值并返回
|
||||
***
|
||||
#### func (*SyncMap) DeleteGetExist(key K) ( V, bool)
|
||||
> 删除一个值并返回是否存在
|
||||
***
|
||||
#### func (*SyncMap) DeleteExist(key K) bool
|
||||
> 删除一个值并返回是否存在
|
||||
***
|
||||
#### func (*SyncMap) Clear()
|
||||
> 清空
|
||||
***
|
||||
#### func (*SyncMap) ClearHandle(handle func (key K, value V))
|
||||
> 清空并处理
|
||||
***
|
||||
#### func (*SyncMap) Range(handle func (key K, value V) bool)
|
||||
> 遍历所有值,如果 handle 返回 true 则停止遍历
|
||||
***
|
||||
#### func (*SyncMap) Keys() []K
|
||||
> 获取所有的键
|
||||
***
|
||||
#### func (*SyncMap) Slice() []V
|
||||
> 获取所有的值
|
||||
***
|
||||
#### func (*SyncMap) Map() map[K]V
|
||||
> 转换为普通 map
|
||||
***
|
||||
#### func (*SyncMap) Size() int
|
||||
> 获取数量
|
||||
***
|
||||
#### func (*SyncMap) MarshalJSON() ( []byte, error)
|
||||
***
|
||||
#### func (*SyncMap) UnmarshalJSON(bytes []byte) error
|
||||
***
|
||||
|
|
|
@ -85,6 +85,33 @@ type FSM[State comparable, Data any] struct {
|
|||
exitAfterEventHandles map[State][]func(state *FSM[State, Data])
|
||||
}
|
||||
```
|
||||
#### func (*FSM) Update()
|
||||
> 触发当前状态
|
||||
***
|
||||
#### func (*FSM) Register(state State, options ...Option[State, Data])
|
||||
> 注册状态
|
||||
***
|
||||
#### func (*FSM) Unregister(state State)
|
||||
> 反注册状态
|
||||
***
|
||||
#### func (*FSM) HasState(state State) bool
|
||||
> 检查状态机是否存在特定状态
|
||||
***
|
||||
#### func (*FSM) Change(state State)
|
||||
> 改变状态机状态到新的状态
|
||||
***
|
||||
#### func (*FSM) Current() (state State)
|
||||
> 获取当前状态
|
||||
***
|
||||
#### func (*FSM) GetData() Data
|
||||
> 获取状态机数据
|
||||
***
|
||||
#### func (*FSM) IsZero() bool
|
||||
> 检查状态机是否无状态
|
||||
***
|
||||
#### func (*FSM) PrevIsZero() bool
|
||||
> 检查状态机上一个状态是否无状态
|
||||
***
|
||||
<span id="struct_Option"></span>
|
||||
### Option `STRUCT`
|
||||
|
||||
|
|
|
@ -14,7 +14,8 @@ func newName(expr ast.Expr) string {
|
|||
//case *ast.FuncType:
|
||||
//case *ast.InterfaceType:
|
||||
//case *ast.MapType:
|
||||
//case *ast.ChanType:
|
||||
case *ast.ChanType:
|
||||
str.WriteString(newName(e.Value))
|
||||
case *ast.Ident:
|
||||
str.WriteString(e.Name)
|
||||
case *ast.Ellipsis:
|
||||
|
@ -28,13 +29,17 @@ func newName(expr ast.Expr) string {
|
|||
case *ast.IndexExpr:
|
||||
str.WriteString(newName(e.X))
|
||||
case *ast.IndexListExpr:
|
||||
str.WriteString(newName(e.X))
|
||||
case *ast.SliceExpr:
|
||||
case *ast.TypeAssertExpr:
|
||||
case *ast.CallExpr:
|
||||
str.WriteString(newName(e.X))
|
||||
//case *ast.TypeAssertExpr:
|
||||
//case *ast.CallExpr:
|
||||
case *ast.StarExpr:
|
||||
str.WriteString(newName(e.X))
|
||||
case *ast.UnaryExpr:
|
||||
str.WriteString(newName(e.X))
|
||||
case *ast.BinaryExpr:
|
||||
str.WriteString(newName(e.X))
|
||||
}
|
||||
return str.String()
|
||||
}
|
||||
|
|
|
@ -947,6 +947,8 @@ type LineSegmentCap[V generic.SignedNumber, Data any] struct {
|
|||
Data Data
|
||||
}
|
||||
```
|
||||
#### func (*LineSegmentCap) GetData() Data
|
||||
***
|
||||
<span id="struct_Point"></span>
|
||||
### Point `STRUCT`
|
||||
表示了一个由 x、y 坐标组成的点
|
||||
|
@ -1010,6 +1012,9 @@ type PointCap[V generic.SignedNumber, D any] struct {
|
|||
Data D
|
||||
}
|
||||
```
|
||||
#### func (PointCap) GetData() D
|
||||
> 获取数据
|
||||
***
|
||||
<span id="struct_Shape"></span>
|
||||
### Shape `STRUCT`
|
||||
通过多个点表示了一个形状
|
||||
|
|
|
@ -76,6 +76,107 @@ type BinarySearch[CompetitorID comparable, Score generic.Ordered] struct {
|
|||
rankClearBeforeEventHandles []BinarySearchRankClearBeforeEventHandle[CompetitorID, Score]
|
||||
}
|
||||
```
|
||||
#### func (*BinarySearch) Competitor(competitorId CompetitorID, score Score)
|
||||
> 声明排行榜竞争者
|
||||
> - 如果竞争者存在的情况下,会更新已有成绩,否则新增竞争者
|
||||
**示例代码:**
|
||||
|
||||
```go
|
||||
|
||||
func ExampleBinarySearch_Competitor() {
|
||||
bs := leaderboard2.NewBinarySearch[string, int](leaderboard2.WithBinarySearchCount[string, int](10))
|
||||
scores := []int{6131, 132, 5133, 134, 135, 136, 137, 138, 139, 140, 222, 333, 444, 555, 666}
|
||||
for i := 1; i <= 15; i++ {
|
||||
bs.Competitor(fmt.Sprintf("competitor_%2d", i), scores[i-1])
|
||||
}
|
||||
for rank, competitor := range bs.GetAllCompetitor() {
|
||||
fmt.Println(rank, competitor)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func (*BinarySearch) RemoveCompetitor(competitorId CompetitorID)
|
||||
> 删除特定竞争者
|
||||
**示例代码:**
|
||||
|
||||
```go
|
||||
|
||||
func ExampleBinarySearch_RemoveCompetitor() {
|
||||
bs := leaderboard2.NewBinarySearch[string, int](leaderboard2.WithBinarySearchCount[string, int](10))
|
||||
scores := []int{6131, 132, 5133, 134, 135, 136, 137, 138, 139, 140, 222, 333, 444, 555, 666}
|
||||
for i := 1; i <= 15; i++ {
|
||||
bs.Competitor(fmt.Sprintf("competitor_%2d", i), scores[i-1])
|
||||
}
|
||||
bs.RemoveCompetitor("competitor_ 1")
|
||||
for rank, competitor := range bs.GetAllCompetitor() {
|
||||
fmt.Println(rank, competitor)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func (*BinarySearch) Size() int
|
||||
> 获取竞争者数量
|
||||
***
|
||||
#### func (*BinarySearch) GetRankDefault(competitorId CompetitorID, defaultValue int) int
|
||||
> 获取竞争者排名,如果竞争者不存在则返回默认值
|
||||
> - 排名从 0 开始
|
||||
***
|
||||
#### func (*BinarySearch) GetRank(competitorId CompetitorID) ( int, error)
|
||||
> 获取竞争者排名
|
||||
> - 排名从 0 开始
|
||||
**示例代码:**
|
||||
|
||||
```go
|
||||
|
||||
func ExampleBinarySearch_GetRank() {
|
||||
bs := leaderboard2.NewBinarySearch[string, int](leaderboard2.WithBinarySearchCount[string, int](10))
|
||||
scores := []int{6131, 132, 5133, 134, 135, 136, 137, 138, 139, 140, 222, 333, 444, 555, 666}
|
||||
for i := 1; i <= 15; i++ {
|
||||
bs.Competitor(fmt.Sprintf("competitor_%2d", i), scores[i-1])
|
||||
}
|
||||
fmt.Println(bs.GetRank("competitor_ 1"))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func (*BinarySearch) GetCompetitor(rank int) (competitorId CompetitorID, err error)
|
||||
> 获取特定排名的竞争者
|
||||
***
|
||||
#### func (*BinarySearch) GetCompetitorWithRange(start int, end int) ( []CompetitorID, error)
|
||||
> 获取第start名到第end名竞争者
|
||||
***
|
||||
#### func (*BinarySearch) GetScore(competitorId CompetitorID) (score Score, err error)
|
||||
> 获取竞争者成绩
|
||||
***
|
||||
#### func (*BinarySearch) GetScoreDefault(competitorId CompetitorID, defaultValue Score) Score
|
||||
> 获取竞争者成绩,不存在时返回默认值
|
||||
***
|
||||
#### func (*BinarySearch) GetAllCompetitor() []CompetitorID
|
||||
> 获取所有竞争者ID
|
||||
> - 结果为名次有序的
|
||||
***
|
||||
#### func (*BinarySearch) Clear()
|
||||
> 清空排行榜
|
||||
***
|
||||
#### func (*BinarySearch) Cmp(s1 Score, s2 Score) int
|
||||
***
|
||||
#### func (*BinarySearch) UnmarshalJSON(bytes []byte) error
|
||||
***
|
||||
#### func (*BinarySearch) MarshalJSON() ( []byte, error)
|
||||
***
|
||||
#### func (*BinarySearch) RegRankChangeEvent(handle BinarySearchRankChangeEventHandle[CompetitorID, Score])
|
||||
***
|
||||
#### func (*BinarySearch) OnRankChangeEvent(competitorId CompetitorID, oldRank int, newRank int, oldScore Score, newScore Score)
|
||||
***
|
||||
#### func (*BinarySearch) RegRankClearBeforeEvent(handle BinarySearchRankClearBeforeEventHandle[CompetitorID, Score])
|
||||
***
|
||||
#### func (*BinarySearch) OnRankClearBeforeEvent()
|
||||
***
|
||||
<span id="struct_BinarySearchRankChangeEventHandle"></span>
|
||||
### BinarySearchRankChangeEventHandle `STRUCT`
|
||||
|
||||
|
|
|
@ -115,6 +115,124 @@ type TwoDimensional[EID generic.Basic, PosType generic.SignedNumber] struct {
|
|||
position2DStopMoveEventHandles []Position2DStopMoveEventHandle[EID, PosType]
|
||||
}
|
||||
```
|
||||
#### func (*TwoDimensional) MoveTo(entity TwoDimensionalEntity[EID, PosType], x PosType, y PosType)
|
||||
> 设置对象移动到特定位置
|
||||
**示例代码:**
|
||||
|
||||
```go
|
||||
|
||||
func ExampleTwoDimensional_MoveTo() {
|
||||
m := moving2.NewTwoDimensional(moving2.WithTwoDimensionalTimeUnit[int64, float64](time.Second))
|
||||
defer func() {
|
||||
m.Release()
|
||||
}()
|
||||
var wait sync.WaitGroup
|
||||
m.RegPosition2DDestinationEvent(func(moving *moving2.TwoDimensional[int64, float64], entity moving2.TwoDimensionalEntity[int64, float64]) {
|
||||
fmt.Println("done")
|
||||
wait.Done()
|
||||
})
|
||||
wait.Add(1)
|
||||
entity := NewEntity(1, 100)
|
||||
m.MoveTo(entity, 50, 30)
|
||||
wait.Wait()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func (*TwoDimensional) StopMove(id EID)
|
||||
> 停止特定对象的移动
|
||||
**示例代码:**
|
||||
|
||||
```go
|
||||
|
||||
func ExampleTwoDimensional_StopMove() {
|
||||
m := moving2.NewTwoDimensional(moving2.WithTwoDimensionalTimeUnit[int64, float64](time.Second))
|
||||
defer func() {
|
||||
m.Release()
|
||||
}()
|
||||
var wait sync.WaitGroup
|
||||
m.RegPosition2DChangeEvent(func(moving *moving2.TwoDimensional[int64, float64], entity moving2.TwoDimensionalEntity[int64, float64], oldX, oldY float64) {
|
||||
fmt.Println("move")
|
||||
})
|
||||
m.RegPosition2DStopMoveEvent(func(moving *moving2.TwoDimensional[int64, float64], entity moving2.TwoDimensionalEntity[int64, float64]) {
|
||||
fmt.Println("stop")
|
||||
wait.Done()
|
||||
})
|
||||
m.RegPosition2DDestinationEvent(func(moving *moving2.TwoDimensional[int64, float64], entity moving2.TwoDimensionalEntity[int64, float64]) {
|
||||
fmt.Println("done")
|
||||
wait.Done()
|
||||
})
|
||||
wait.Add(1)
|
||||
entity := NewEntity(1, 100)
|
||||
m.MoveTo(entity, 50, 300)
|
||||
m.StopMove(1)
|
||||
wait.Wait()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestTwoDimensional_StopMove(t *testing.T) {
|
||||
var wait sync.WaitGroup
|
||||
m := moving2.NewTwoDimensional(moving2.WithTwoDimensionalTimeUnit[int64, float64](time.Second))
|
||||
defer func() {
|
||||
m.Release()
|
||||
}()
|
||||
m.RegPosition2DChangeEvent(func(moving *moving2.TwoDimensional[int64, float64], entity moving2.TwoDimensionalEntity[int64, float64], oldX, oldY float64) {
|
||||
x, y := entity.GetPosition().GetXY()
|
||||
fmt.Println(fmt.Sprintf("%d : %d | %f, %f > %f, %f", entity.GetTwoDimensionalEntityID(), time.Now().UnixMilli(), oldX, oldY, x, y))
|
||||
})
|
||||
m.RegPosition2DDestinationEvent(func(moving *moving2.TwoDimensional[int64, float64], entity moving2.TwoDimensionalEntity[int64, float64]) {
|
||||
fmt.Println(fmt.Sprintf("%d : %d | destination", entity.GetTwoDimensionalEntityID(), time.Now().UnixMilli()))
|
||||
wait.Done()
|
||||
})
|
||||
m.RegPosition2DStopMoveEvent(func(moving *moving2.TwoDimensional[int64, float64], entity moving2.TwoDimensionalEntity[int64, float64]) {
|
||||
fmt.Println(fmt.Sprintf("%d : %d | stop", entity.GetTwoDimensionalEntityID(), time.Now().UnixMilli()))
|
||||
wait.Done()
|
||||
})
|
||||
for i := 0; i < 10; i++ {
|
||||
wait.Add(1)
|
||||
entity := NewEntity(int64(i)+1, float64(10+i))
|
||||
m.MoveTo(entity, 50, 30)
|
||||
}
|
||||
time.Sleep(time.Second * 1)
|
||||
for i := 0; i < 10; i++ {
|
||||
m.StopMove(int64(i) + 1)
|
||||
}
|
||||
wait.Wait()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*TwoDimensional) RegPosition2DChangeEvent(handle Position2DChangeEventHandle[EID, PosType])
|
||||
> 在对象位置改变时将执行注册的事件处理函数
|
||||
***
|
||||
#### func (*TwoDimensional) OnPosition2DChangeEvent(entity TwoDimensionalEntity[EID, PosType], oldX PosType, oldY PosType)
|
||||
***
|
||||
#### func (*TwoDimensional) RegPosition2DDestinationEvent(handle Position2DDestinationEventHandle[EID, PosType])
|
||||
> 在对象到达终点时将执行被注册的事件处理函数
|
||||
***
|
||||
#### func (*TwoDimensional) OnPosition2DDestinationEvent(entity TwoDimensionalEntity[EID, PosType])
|
||||
***
|
||||
#### func (*TwoDimensional) RegPosition2DStopMoveEvent(handle Position2DStopMoveEventHandle[EID, PosType])
|
||||
> 在对象停止移动时将执行被注册的事件处理函数
|
||||
***
|
||||
#### func (*TwoDimensional) OnPosition2DStopMoveEvent(entity TwoDimensionalEntity[EID, PosType])
|
||||
***
|
||||
#### func (*TwoDimensional) Release()
|
||||
> 释放对象移动对象所占用的资源
|
||||
***
|
||||
<span id="struct_TwoDimensionalEntity"></span>
|
||||
### TwoDimensionalEntity `INTERFACE`
|
||||
2D移动对象接口定义
|
||||
|
|
|
@ -940,6 +940,12 @@ type Matcher[Value any, Result any] struct {
|
|||
d bool
|
||||
}
|
||||
```
|
||||
#### func (*Matcher) Case(value Value, result Result) *Matcher[Value, Result]
|
||||
> 匹配
|
||||
***
|
||||
#### func (*Matcher) Default(value Result) Result
|
||||
> 默认
|
||||
***
|
||||
<span id="struct_Permission"></span>
|
||||
### Permission `STRUCT`
|
||||
|
||||
|
@ -949,6 +955,18 @@ type Permission[Code generic.Integer, EntityID comparable] struct {
|
|||
l sync.RWMutex
|
||||
}
|
||||
```
|
||||
#### func (*Permission) HasPermission(entityId EntityID, permission Code) bool
|
||||
> 是否有权限
|
||||
***
|
||||
#### func (*Permission) AddPermission(entityId EntityID, permission ...Code)
|
||||
> 添加权限
|
||||
***
|
||||
#### func (*Permission) RemovePermission(entityId EntityID, permission ...Code)
|
||||
> 移除权限
|
||||
***
|
||||
#### func (*Permission) SetPermission(entityId EntityID, permission ...Code)
|
||||
> 设置权限
|
||||
***
|
||||
<span id="struct_StackGo"></span>
|
||||
### StackGo `STRUCT`
|
||||
用于获取上一个协程调用的堆栈信息
|
||||
|
|
Loading…
Reference in New Issue