minotaur

module
v0.3.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 11, 2023 License: MIT

README

Minotaur

Go doc

Minotaur 是一个基于Golang 1.20 编写的服务端开发支持库,其中采用了大量泛型设计,用于游戏服务器开发。

目录结构概况

mindmap
  root((Minotaur))
    /configuration 配置管理功能
    /game 游戏通用功能
      /builtin 游戏通用功能内置实现
    /notify 通知功能接口定义
    /planner 策划相关工具目录
      /pce 配置导表功能实现
    /server 网络服务器支持
      /client 长连接客户端
      /lockstep 帧同步组件
      /router 消息路由器
    /utils 工具结构函数目录
    /examples 示例代码目录

Server 架构预览

server-gdi.jpg

安装

注意:依赖于 Go 1.20 +

运行以下 Go 命令来安装软件包:minotaur

$ go get -u github.com/kercylan98/minotaur

用法

本地文档

可使用 godoc 搭建本地文档服务器

安装 godoc
git clone golang.org/x/tools
cd tools/cmd
go install ...
使用 godoc 启动本地文档服务器
godoc -http=:9998 -play
Windows
.\local-doc.bat
Linux or MacOS
chmod 777 ./local-doc.sh
./local-doc.sh
文档地址
简单回响服务器

创建一个基于Websocket创建的单线程回响服务器。

package main

import (
	"github.com/kercylan98/minotaur/server"
)

func main() {
	srv := server.New(server.NetworkWebsocket)
	srv.RegConnectionReceivePacketEvent(func(srv *server.Server, conn *server.Conn, packet []byte) {
		conn.Write(packet)
	})
	if err := srv.Run(":9999"); err != nil {
		panic(err)
	}
}

访问 WebSocket 在线测试 进行验证。

Websocket地址: ws://127.0.0.1:9999

分流服务器

分流服务器可以将消息分流到不同的分组上,每个分组中为串行处理,不同分组之间并行处理。

关于分流服务器的思考:

  • 当游戏需要以房间的形式进行时,应该确保相同房间的玩家处于同一分流中,不同房间的玩家处于不同分流中,这样可以避免不同房间的玩家之间的消息互相阻塞;
    • 这时候网络 IO 应该根据不同的游戏类型而进行不同的处理,例如回合制可以同步执行,而实时游戏应该采用异步执行;
  • 当游戏大部分时候以单人游戏进行时,应该每个玩家处于自身唯一的分流中,此时非互动的消息造成的网络 IO 采用同步执行即可,也不会阻塞到其他玩家的消息处理;
package main

import "github.com/kercylan98/minotaur/server"

func main() {
	srv := server.New(server.NetworkWebsocket)
	srv.RegConnectionOpenedEvent(func(srv *server.Server, conn *server.Conn) {
		// 通过 user_id 进行分流,不同用户的消息将不会互相阻塞
		srv.UseShunt(conn, conn.Gata("user_id").(string))
	})
	srv.RegConnectionReceivePacketEvent(func(srv *server.Server, conn *server.Conn, packet []byte) {
		var roomId = "default"
		switch string(packet) {
		case "JoinRoom":
            // 将用户所处的分流渠道切换到 roomId 渠道,此刻同一分流渠道的消息将会按队列顺序处理
            srv.UseShunt(conn, roomId)
		case "LeaveRoom":
            // 将用户所处分流切换为用户自身的分流渠道
            srv.UseShunt(conn, conn.Gata("user_id").(string))
		}
	})
	if err := srv.Run(":9999"); err != nil {
		panic(err)
	}
}

该示例中模拟了用户分流渠道在自身渠道和房间渠道切换的过程,通过UseShunt对连接分流渠道进行设置,提高并发处理能力。

服务器死锁检测

Minotaur内置了服务器消息死锁检测功能,可通过server.WithDeadlockDetect进行开启。

package main

import (
	"github.com/kercylan98/minotaur/server"
	"time"
)

func main() {
	srv := server.New(server.NetworkWebsocket,
		server.WithDeadlockDetect(time.Second*5),
	)
	srv.RegConnectionReceivePacketEvent(func(srv *server.Server, conn *server.Conn, packet []byte) {
		time.Sleep(10 * time.Second)
		conn.Write(packet)
	})
	if err := srv.Run(":9999"); err != nil {
		panic(err)
	}
}

在开启死锁检测的时候需要设置一个合理的死锁怀疑时间,该时间内消息没有处理完毕则会触发死锁检测,并打印WARN级别的日志输出。

计时器

在默认的server.Server不会包含计时器功能,可通过server.WithTicker进行开启,例如:

package main

import "github.com/kercylan98/minotaur/server"

func main() {
	srv := server.New(server.NetworkWebsocket, server.WithTicker(50, 10, false))
	if err := srv.Run(":9999"); err != nil {
		panic(err)
	}
}

也可以通过timer.GetTicker获取计时器进行使用,例如:

package main

import (
	"fmt"
	"github.com/kercylan98/minotaur/utils/timer"
	"github.com/kercylan98/minotaur/utils/times"
	"sync"
)

func main() {
	var ticker = timer.GetTicker(10)
	var wait sync.WaitGroup
	wait.Add(3)
	ticker.Loop("LOOP", timer.Instantly, times.Second, timer.Forever, func() {
		fmt.Println("LOOP")
		wait.Done()
	})
	wait.Wait()
}

在分布式环境中,如果存在类似于多服务器需要同时间刷新配置时,可使用Cron表达式设置定时任务。

流操作

可以通过 stream 包快速开启对切片map的流式操作,例如:

package main

import (
	"fmt"
	"github.com/kercylan98/minotaur/utils/stream"
	"github.com/kercylan98/minotaur/utils/streams"
)

func main() {
	s := stream.WithSlice([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}).
		Copy().
		Shuffle().
		Filter(true, func(index int, item int) bool {
			return item%2 == 0
		}).
		Zoom(20).
		Each(true, func(index int, item int) bool {
			t.Log(index, item)
			return false
		}).
		Chunk(3).
		EachT(func(index int, item stream.Slice[int]) bool {
			t.Log(item)
			return false
		}).
		Merge().
		FillBy(func(index int, value int) int {
			if value == 0 {
				return 999
			}
			return value
		})
	
	fmt.Println(s)
}
基于xlsx文件的配置导出工具

该导出器的xlsx文件配置使用JSON语法进行复杂类型配置,具体可参考图例

导出 JSON 文件(可供客户端直接使用,包含索引的配置导出后为键值模式,可直接读取)
Flags:
  -e, --exclude string   excluded configuration names or display names (comma separated) | 排除的配置名或显示名(英文逗号分隔)
  -h, --help             help for json
  -o, --output string    directory path of the output json file | 输出的 json 文件所在目录路径
  -p, --prefix string    export configuration file name prefix | 导出配置文件名前缀
  -t, --type string      export server configuration[s] or client configuration[c] | 导出服务端配置[s]还是客户端配置[c]
  -f, --xlsx string      xlsx file path or directory path | xlsx 文件路径或所在目录路径

expoter.exe json -t s -f xlsx_template.xlsx -o ./output

导出结果示例

{
  "1": {
    "b": {
      "Id": 1,
      "Count": "b",
      "Info": {
        "id": 1,
        "name": "小明",
        "info": {
          "lv": 1,
          "exp": {
            "mux": 10,
            "count": 100
          }
        }
      },
      "Other": [
        {
          "id": 1,
          "name": "张飞"
        },
        {
          "id": 2,
          "name": "刘备"
        }
      ]
    }
  }
}

导出 Golang 文件
Flags:
  -e, --exclude string   excluded configuration names or display names (comma separated) | 排除的配置名或显示名(英文逗号分隔)
  -h, --help             help for go
  -o, --output string    output path | 输出的 go 文件路径
  -f, --xlsx string      xlsx file path or directory path | xlsx 文件路径或所在目录路径
expoter.exe go -f xlsx_template.xlsx -o ./output

使用示例

package main

import (
	"fmt"
	"config"
)

func main() {
	fmt.Println(config.EasyConfig.Id)
}
持续更新的示例项目
贡献者列表
参与贡献请参考 CONTRIBUTING.md 贡献指南。
联系方式

JetBrains OS licenses

Minotaur had been being developed with GoLand IDE under the free JetBrains Open Source license(s) granted by JetBrains s.r.o., hence I would like to express my thanks here.

Directories

Path Synopsis
ax module
Package configuration 基于配置导表功能实现的配置加载及刷新功能
Package configuration 基于配置导表功能实现的配置加载及刷新功能
examples
Package game 目录下包含了各类通用的游戏玩法性内容,其中该目录主要为基础性内容,具体目录将对应不同的游戏功能性内容。
Package game 目录下包含了各类通用的游戏玩法性内容,其中该目录主要为基础性内容,具体目录将对应不同的游戏功能性内容。
aoi
builtin
Package builtin 包含了通用游戏相关的接口的内置实现
Package builtin 包含了通用游戏相关的接口的内置实现
fsm
poker
Package poker 提供了一组用于处理扑克牌游戏的函数和数据结构。
Package poker 提供了一组用于处理扑克牌游戏的函数和数据结构。
Package notify 包含了对外部第三方通知的实现,如机器人消息等
Package notify 包含了对外部第三方通知的实现,如机器人消息等
notifies
Package notifies 包含了内置通知内容的实现
Package notifies 包含了内置通知内容的实现
senders
Package senders Package 包含了内置通知发送器的实现
Package senders Package 包含了内置通知发送器的实现
Package planner 包含了策划工具相关的内容
Package planner 包含了策划工具相关的内容
pce
Package server 提供了包含多种网络类型的服务器实现
Package server 提供了包含多种网络类型的服务器实现
gateway
Package gateway 是用于处理服务器消息的网关模块,适用于对客户端消息进行处理、转发的情况。
Package gateway 是用于处理服务器消息的网关模块,适用于对客户端消息进行处理、转发的情况。
Package utils 旨在提供一组用于处理通用功能的函数和数据结构。
Package utils 旨在提供一组用于处理通用功能的函数和数据结构。
deck
Package deck 包中的内容用于针对一堆内容的管理,适用但不限于牌堆、麻将牌堆等情况。
Package deck 包中的内容用于针对一堆内容的管理,适用但不限于牌堆、麻将牌堆等情况。
generic
Package generic 目的在于提供一组基于泛型的用于处理通用功能的函数和数据结构。
Package generic 目的在于提供一组基于泛型的用于处理通用功能的函数和数据结构。
geometry
Package geometry 旨在提供一组用于处理几何形状和计算几何属性的函数和数据结构。
Package geometry 旨在提供一组用于处理几何形状和计算几何属性的函数和数据结构。
geometry/astar
Package astar 提供用于实现 A* 算法的函数和数据结构。
Package astar 提供用于实现 A* 算法的函数和数据结构。
geometry/dp
Package dp (DistributionPattern) 提供用于在二维数组中根据不同的特征标记为数组成员建立分布链接的函数和数据结构。
Package dp (DistributionPattern) 提供用于在二维数组中根据不同的特征标记为数组成员建立分布链接的函数和数据结构。
geometry/matrix
Package matrix 提供了一个简单的二维数组的实现
Package matrix 提供了一个简单的二维数组的实现
geometry/navmesh
Package navmesh 提供了用于导航网格处理的函数和数据结构。
Package navmesh 提供了用于导航网格处理的函数和数据结构。
log
str

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL