Merge branch 'develop'
This commit is contained in:
commit
293b24669e
|
@ -0,0 +1,40 @@
|
||||||
|
package modular
|
||||||
|
|
||||||
|
// Dimension 维度接口
|
||||||
|
// - 维度与服务的区别在于,维度是对非全局性的服务进行抽象,例如:依赖特定游戏房间的局内玩家管理服务
|
||||||
|
type Dimension[Owner any] interface {
|
||||||
|
// OnInit 服务初始化阶段,该阶段不应该依赖其他任何服务
|
||||||
|
OnInit(owner Owner) error
|
||||||
|
|
||||||
|
// OnPreload 预加载阶段,在进入该阶段时,所有服务已经初始化完成,可在该阶段注入其他服务的依赖
|
||||||
|
OnPreload() error
|
||||||
|
|
||||||
|
// OnMount 挂载阶段,该阶段所有服务本身及依赖的服务都已经初始化完成,可在该阶段进行服务功能的定义
|
||||||
|
OnMount() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunDimensions 运行维度
|
||||||
|
func RunDimensions[Owner any](owner Owner, dimensions ...Dimension[Owner]) error {
|
||||||
|
// OnInit
|
||||||
|
for _, dimension := range dimensions {
|
||||||
|
if err := dimension.OnInit(owner); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnPreload
|
||||||
|
for _, dimension := range dimensions {
|
||||||
|
if err := dimension.OnPreload(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnMount
|
||||||
|
for _, dimension := range dimensions {
|
||||||
|
if err := dimension.OnMount(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
type Events struct {
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import "github.com/kercylan98/minotaur/modular/example/internal/dimension/dimensions/exposes"
|
||||||
|
|
||||||
|
type Room struct {
|
||||||
|
RoomId int64
|
||||||
|
*Events
|
||||||
|
exposes.VisitorsExpose
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package dimension
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kercylan98/minotaur/modular"
|
||||||
|
"github.com/kercylan98/minotaur/modular/example/internal/dimension/core"
|
||||||
|
"github.com/kercylan98/minotaur/modular/example/internal/dimension/dimensions/dimensions/visitors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(roomId int64) error {
|
||||||
|
visitorsDimension := new(visitors.Dimension)
|
||||||
|
|
||||||
|
return modular.RunDimensions(&core.Room{
|
||||||
|
RoomId: roomId,
|
||||||
|
Events: &core.Events{},
|
||||||
|
|
||||||
|
VisitorsExpose: visitorsDimension,
|
||||||
|
},
|
||||||
|
visitorsDimension,
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package visitors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/kercylan98/minotaur/modular/example/internal/dimension/core"
|
||||||
|
"github.com/kercylan98/minotaur/modular/example/internal/dimension/dimensions/exposes"
|
||||||
|
"github.com/kercylan98/minotaur/modular/example/internal/dimension/dimensions/models"
|
||||||
|
"github.com/kercylan98/minotaur/utils/collection"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Dimension struct {
|
||||||
|
*core.Room // 房间 Id
|
||||||
|
visitors map[string]*models.VisitorsMember // 所有访客
|
||||||
|
visitorIds []string // 所有访客 OpenId
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dimension) OnInit(owner *core.Room) error {
|
||||||
|
exposes.Visitors = d
|
||||||
|
d.Room = owner
|
||||||
|
d.visitors = make(map[string]*models.VisitorsMember)
|
||||||
|
fmt.Println("visitors dimension initialized")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dimension) OnPreload() error {
|
||||||
|
fmt.Println("visitors dimension preloaded")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dimension) OnMount() error {
|
||||||
|
fmt.Println("visitors dimension mounted")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dimension) Count() int {
|
||||||
|
return len(d.visitors)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dimension) OpenIds() []string {
|
||||||
|
return d.visitorIds
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dimension) Has(openId string) bool {
|
||||||
|
return collection.KeyInMap(d.visitors, openId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dimension) Del(openId string) {
|
||||||
|
member := d.Get(openId)
|
||||||
|
if member == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(d.visitors, openId)
|
||||||
|
collection.DropSliceByIndices(&d.visitorIds, member.OpenIdIdx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dimension) Get(openId string) *models.VisitorsMember {
|
||||||
|
return d.visitors[openId]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dimension) Add(member *models.VisitorsMember) {
|
||||||
|
member.OpenIdIdx = len(d.visitorIds)
|
||||||
|
d.visitorIds = append(d.visitorIds, member.OpenId)
|
||||||
|
d.visitors[member.OpenId] = member
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package exposes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kercylan98/minotaur/modular/example/internal/dimension/dimensions/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Visitors VisitorsExpose
|
||||||
|
|
||||||
|
type VisitorsExpose interface {
|
||||||
|
// Count 访客数量
|
||||||
|
Count() int
|
||||||
|
|
||||||
|
// OpenIds 访客 OpenId 列表
|
||||||
|
OpenIds() []string
|
||||||
|
|
||||||
|
// Has 是否存在指定 OpenId 的访客
|
||||||
|
Has(openId string) bool
|
||||||
|
|
||||||
|
// Del 删除指定 OpenId 的访客
|
||||||
|
Del(openId string)
|
||||||
|
|
||||||
|
// Get 获取指定 OpenId 的访客
|
||||||
|
Get(openId string) *models.VisitorsMember
|
||||||
|
|
||||||
|
// Add 添加访客
|
||||||
|
Add(member *models.VisitorsMember)
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
// VisitorsMember 访客成员
|
||||||
|
type VisitorsMember struct {
|
||||||
|
OpenId string // 访客成员 OpenId
|
||||||
|
OpenIdIdx int // 访客成员 OpenId 索引
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/modular"
|
"github.com/kercylan98/minotaur/modular"
|
||||||
|
"github.com/kercylan98/minotaur/modular/example/internal/dimension"
|
||||||
"github.com/kercylan98/minotaur/modular/example/internal/service/services/attack"
|
"github.com/kercylan98/minotaur/modular/example/internal/service/services/attack"
|
||||||
"github.com/kercylan98/minotaur/modular/example/internal/service/services/login"
|
"github.com/kercylan98/minotaur/modular/example/internal/service/services/login"
|
||||||
"github.com/kercylan98/minotaur/modular/example/internal/service/services/server"
|
"github.com/kercylan98/minotaur/modular/example/internal/service/services/server"
|
||||||
|
@ -13,5 +14,11 @@ func main() {
|
||||||
new(server.Service),
|
new(server.Service),
|
||||||
new(login.Service),
|
new(login.Service),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
err := dimension.New(1) // generate a room
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
modular.Run()
|
modular.Run()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package modular
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/kercylan98/minotaur/utils/log"
|
"github.com/kercylan98/minotaur/utils/log"
|
||||||
"reflect"
|
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,14 +26,12 @@ func (m *modular) RegisterServices(s ...Service) {
|
||||||
func Run() {
|
func Run() {
|
||||||
m := application
|
m := application
|
||||||
var names = make(map[string]bool)
|
var names = make(map[string]bool)
|
||||||
var tvm = make(map[reflect.Type]reflect.Value)
|
|
||||||
for i := 0; i < len(m.registerServices); i++ {
|
for i := 0; i < len(m.registerServices); i++ {
|
||||||
s := newService(m.registerServices[i])
|
s := newService(m.registerServices[i])
|
||||||
if names[s.name] {
|
if names[s.name] {
|
||||||
panic(fmt.Errorf("service %s is already registered", s.name))
|
panic(fmt.Errorf("service %s is already registered", s.name))
|
||||||
}
|
}
|
||||||
names[s.name] = true
|
names[s.name] = true
|
||||||
tvm[s.vof.Type()] = s.vof
|
|
||||||
m.services = append(m.services, s)
|
m.services = append(m.services, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewPrioritySlice 创建一个优先级切片
|
// NewPrioritySlice 创建一个优先级切片,优先级越低越靠前
|
||||||
func NewPrioritySlice[V any](lengthAndCap ...int) *PrioritySlice[V] {
|
func NewPrioritySlice[V any](lengthAndCap ...int) *PrioritySlice[V] {
|
||||||
p := &PrioritySlice[V]{}
|
p := &PrioritySlice[V]{}
|
||||||
if len(lengthAndCap) > 0 {
|
if len(lengthAndCap) > 0 {
|
||||||
|
@ -19,7 +19,7 @@ func NewPrioritySlice[V any](lengthAndCap ...int) *PrioritySlice[V] {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrioritySlice 是一个优先级切片
|
// PrioritySlice 是一个优先级切片,优先级越低越靠前
|
||||||
type PrioritySlice[V any] struct {
|
type PrioritySlice[V any] struct {
|
||||||
items []*priorityItem[V]
|
items []*priorityItem[V]
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,19 @@ func (slf Point[V]) Max(point Point[V]) Point[V] {
|
||||||
return NewPoint(x, y)
|
return NewPoint(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move 返回向特定角度移动特定距离后的新的位置,其中 angle 期待的角度范围是 -180~180
|
||||||
|
func (slf Point[V]) Move(angle, direction V) Point[V] {
|
||||||
|
df := float64(direction)
|
||||||
|
// 将角度转换为弧度
|
||||||
|
radian := float64(angle) * (math.Pi / 180.0)
|
||||||
|
|
||||||
|
// 计算新的坐标
|
||||||
|
newX := float64(slf.GetX()) + df*math.Cos(radian)
|
||||||
|
newY := float64(slf.GetY()) + df*math.Sin(radian)
|
||||||
|
|
||||||
|
return NewPoint(V(newX), V(newY))
|
||||||
|
}
|
||||||
|
|
||||||
// Min 返回两个位置中每个维度的最小值组成的新的位置
|
// Min 返回两个位置中每个维度的最小值组成的新的位置
|
||||||
func (slf Point[V]) Min(point Point[V]) Point[V] {
|
func (slf Point[V]) Min(point Point[V]) Point[V] {
|
||||||
x, y := slf.GetXY()
|
x, y := slf.GetXY()
|
||||||
|
|
|
@ -29,6 +29,11 @@ func (sc SimpleCircle[V]) String() string {
|
||||||
return fmt.Sprintf("SimpleCircle{centroid: %v, %v, radius: %v}", sc.centroid.GetX(), sc.centroid.GetY(), sc.radius)
|
return fmt.Sprintf("SimpleCircle{centroid: %v, %v, radius: %v}", sc.centroid.GetX(), sc.centroid.GetY(), sc.radius)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsZero 反映该圆形是否为零值的无效圆形
|
||||||
|
func (sc SimpleCircle[V]) IsZero() bool {
|
||||||
|
return sc.radius == V(0)
|
||||||
|
}
|
||||||
|
|
||||||
// Centroid 获取圆形质心位置
|
// Centroid 获取圆形质心位置
|
||||||
func (sc SimpleCircle[V]) Centroid() Point[V] {
|
func (sc SimpleCircle[V]) Centroid() Point[V] {
|
||||||
return sc.centroid
|
return sc.centroid
|
||||||
|
@ -74,15 +79,18 @@ func (sc SimpleCircle[V]) Area() V {
|
||||||
return sc.radius * sc.radius
|
return sc.radius * sc.radius
|
||||||
}
|
}
|
||||||
|
|
||||||
// Projection 获取圆形投影到另一个圆形的特定比例下的位置和半径
|
// Projection 获取圆形投影到另一个圆形的特定比例下的位置和半径(同心合并)
|
||||||
func (sc SimpleCircle[V]) Projection(circle SimpleCircle[V], ratio float64) SimpleCircle[V] {
|
func (sc SimpleCircle[V]) Projection(circle SimpleCircle[V], ratio float64) SimpleCircle[V] {
|
||||||
// 计算圆心朝目标按比例移动后的位置
|
// 计算圆心朝目标按比例移动后的位置
|
||||||
distance := float64(sc.Centroid().Distance(circle.centroid))
|
distance := sc.Centroid().Distance(circle.Centroid())
|
||||||
moveDistance := distance * ratio
|
moveDistance := distance * ratio
|
||||||
newX := float64(sc.CentroidX()) + moveDistance*(float64(circle.CentroidX())-float64(sc.CentroidX()))/distance
|
newX := float64(circle.CentroidX()) + moveDistance*(float64(sc.CentroidX())-float64(circle.CentroidX()))/distance
|
||||||
newY := float64(sc.CentroidY()) + moveDistance*(float64(circle.CentroidY())-float64(sc.CentroidY()))/distance
|
newY := float64(circle.CentroidY()) + moveDistance*(float64(sc.CentroidY())-float64(circle.CentroidY()))/distance
|
||||||
|
|
||||||
return NewSimpleCircle(V(float64(sc.radius)*ratio), NewPoint(V(newX), V(newY)))
|
// 计算新的半径
|
||||||
|
newRadius := float64(sc.radius) + (float64(circle.radius)-float64(sc.radius))*(1-ratio)
|
||||||
|
|
||||||
|
return NewSimpleCircle(V(newRadius), NewPoint(V(newX), V(newY)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Length 获取圆的周长
|
// Length 获取圆的周长
|
||||||
|
|
|
@ -13,6 +13,30 @@ func Int64(min int64, max int64) int64 {
|
||||||
return min + rand.Int63n(max+1-min)
|
return min + rand.Int63n(max+1-min)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Int32 返回一个介于min和max之间的的int32类型的随机数。
|
||||||
|
func Int32(min int32, max int32) int32 {
|
||||||
|
if min == max {
|
||||||
|
return min
|
||||||
|
}
|
||||||
|
return int32(Int64(int64(min), int64(max)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32Range 返回一个介于min和max之间的的float32类型的随机数。
|
||||||
|
func Float32Range(min float32, max float32) float32 {
|
||||||
|
if min == max {
|
||||||
|
return min
|
||||||
|
}
|
||||||
|
return min + rand.Float32()*(max-min)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Range 返回一个介于min和max之间的的float64类型的随机数。
|
||||||
|
func Float64Range(min float64, max float64) float64 {
|
||||||
|
if min == max {
|
||||||
|
return min
|
||||||
|
}
|
||||||
|
return min + rand.Float64()*(max-min)
|
||||||
|
}
|
||||||
|
|
||||||
// Int 返回一个介于min和max之间的的int类型的随机数。
|
// Int 返回一个介于min和max之间的的int类型的随机数。
|
||||||
func Int(min int, max int) int {
|
func Int(min int, max int) int {
|
||||||
if min == max {
|
if min == max {
|
||||||
|
|
|
@ -2,10 +2,12 @@ package timer
|
||||||
|
|
||||||
type Option func(ticker *Ticker)
|
type Option func(ticker *Ticker)
|
||||||
|
|
||||||
// WithCaller 通过其他的 handle 执行 Caller
|
// WithCaller 通过其他的 handler 执行 Caller
|
||||||
func WithCaller(handle func(name string, caller func())) Option {
|
func WithCaller(handler func(name string, caller func())) Option {
|
||||||
return func(ticker *Ticker) {
|
return func(ticker *Ticker) {
|
||||||
ticker.handle = handle
|
ticker.lock.Lock()
|
||||||
|
ticker.handler = handler
|
||||||
|
ticker.lock.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@ type Ticker struct {
|
||||||
timers map[string]*Scheduler
|
timers map[string]*Scheduler
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
|
|
||||||
handle func(name string, caller func())
|
handler func(name string, caller func())
|
||||||
mark string
|
mark string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark 获取定时器的标记
|
// Mark 获取定时器的标记
|
||||||
|
@ -33,6 +33,7 @@ func (slf *Ticker) Release() {
|
||||||
|
|
||||||
slf.lock.Lock()
|
slf.lock.Lock()
|
||||||
slf.mark = ""
|
slf.mark = ""
|
||||||
|
slf.handler = nil
|
||||||
for name, scheduler := range slf.timers {
|
for name, scheduler := range slf.timers {
|
||||||
scheduler.close()
|
scheduler.close()
|
||||||
delete(slf.timers, name)
|
delete(slf.timers, name)
|
||||||
|
@ -94,8 +95,8 @@ func (slf *Ticker) CronByInstantly(name, expression string, handleFunc interface
|
||||||
f := reflect.ValueOf(handleFunc)
|
f := reflect.ValueOf(handleFunc)
|
||||||
slf.lock.RLock()
|
slf.lock.RLock()
|
||||||
defer slf.lock.RUnlock()
|
defer slf.lock.RUnlock()
|
||||||
if slf.handle != nil {
|
if slf.handler != nil {
|
||||||
slf.handle(name, func() {
|
slf.handler(name, func() {
|
||||||
f.Call(values)
|
f.Call(values)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -147,9 +148,13 @@ func (slf *Ticker) loop(name string, after, interval time.Duration, expr *cronex
|
||||||
|
|
||||||
slf.lock.Lock()
|
slf.lock.Lock()
|
||||||
slf.timers[name] = scheduler
|
slf.timers[name] = scheduler
|
||||||
if slf.handle != nil {
|
if slf.handler != nil {
|
||||||
scheduler.timer = slf.wheel.ScheduleFunc(scheduler, func() {
|
scheduler.timer = slf.wheel.ScheduleFunc(scheduler, func() {
|
||||||
slf.handle(scheduler.Name(), scheduler.Caller)
|
slf.lock.RLock()
|
||||||
|
defer slf.lock.RUnlock()
|
||||||
|
if slf.handler != nil {
|
||||||
|
slf.handler(scheduler.Name(), scheduler.Caller)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
scheduler.timer = slf.wheel.ScheduleFunc(scheduler, scheduler.Caller)
|
scheduler.timer = slf.wheel.ScheduleFunc(scheduler, scheduler.Caller)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package times
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/kercylan98/minotaur/utils/generic"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
@ -60,3 +61,8 @@ func IntervalFormat(time1, time2 time.Time) string {
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToSecDuration 转换为秒级 time.Duration
|
||||||
|
func ToSecDuration[V generic.Number](v V) time.Duration {
|
||||||
|
return Second * time.Duration(int64(v))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue