├── log
└── .gitkeep
├── bin
├── release
│ └── .gitkeep
└── debug
│ ├── 4-web.bat
│ ├── 8-gps.bat
│ ├── 1-gate.bat
│ ├── 2-login.bat
│ ├── 3-database.bat
│ ├── 5-world.bat
│ ├── 6-world.bat
│ ├── 7-world.bat
│ ├── 9-balcony.bat
│ ├── 0-center.bat
│ ├── 1-gate.command
│ ├── 4-web.command
│ ├── 8-gps.command
│ ├── 2-login.command
│ ├── 3-database.command
│ ├── 5-world.command
│ ├── 6-world.command
│ ├── 7-world.command
│ ├── 9-balcony.command
│ ├── 0-center.command
│ ├── fstopall.sh
│ ├── stopall.sh
│ ├── runall.bat
│ ├── runall.command
│ └── runall.sh
├── etc
├── basic.yaml
├── database.yaml
├── zones.yaml
└── servers.yaml
├── src
├── services
│ ├── world
│ │ ├── util.go
│ │ ├── messageHandler.go
│ │ └── zoneworld.go
│ ├── ai
│ │ └── ai.go
│ ├── robot
│ │ └── robot.go
│ ├── chat
│ │ └── chat.go
│ ├── innet
│ │ ├── util.go
│ │ ├── retry.go
│ │ ├── sender.go
│ │ ├── address.go
│ │ └── receiver.go
│ ├── gate
│ │ ├── services.go
│ │ └── session.go
│ ├── cluster
│ │ ├── cluster.go
│ │ └── running.go
│ ├── balcony
│ │ └── balcony.go
│ ├── node
│ │ └── node.go
│ ├── web
│ │ └── web.go
│ ├── gps
│ │ └── gps.go
│ └── center
│ │ └── center.go
├── common
│ ├── global
│ │ ├── interfaces.go
│ │ ├── global.go
│ │ └── const.go
│ ├── protect
│ │ └── protect.go
│ ├── dbobj
│ │ └── dbobj.go
│ ├── profiler
│ │ └── profiler.go
│ ├── util
│ │ └── util.go
│ ├── logger
│ │ └── logger.go
│ └── uuid
│ │ └── uuid.go
├── README.md
├── unittest
│ ├── golang_test.go
│ ├── uuid_test.go
│ └── udp_test.go
├── gameplay
│ ├── ecs
│ │ ├── system
│ │ │ ├── system.go
│ │ │ ├── physics.go
│ │ │ ├── reborn.go
│ │ │ └── move.go
│ │ ├── controller.go
│ │ └── entity.go
│ ├── matrix
│ │ └── matrix.go
│ └── gamemap
│ │ ├── scene.go
│ │ └── gamemap.go
├── engine
│ ├── extensions
│ │ ├── rect
│ │ │ └── rect.go
│ │ └── vector3
│ │ │ └── vector3.go
│ └── grid
│ │ └── grid.go
├── proto
│ ├── config
│ │ ├── map.pb.json.go
│ │ └── scene.pb.json.go
│ ├── data
│ │ ├── data.map.pb.json.go
│ │ ├── data.player.pb.json.go
│ │ ├── data.entity.pb.json.go
│ │ ├── data.gate.pb.json.go
│ │ ├── data.role.pb.json.go
│ │ └── data.component.pb.json.go
│ ├── etc
│ │ ├── etc.basic.pb.json.go
│ │ ├── etc.database.pb.json.go
│ │ ├── etc.zones.pb.json.go
│ │ └── etc.servers.pb.json.go
│ └── engine
│ │ └── math.pb.json.go
├── cli
│ └── cli.go
├── lifetime
│ ├── finalize
│ │ └── finalize.go
│ └── startup
│ │ └── startup.go
└── dao
│ ├── dao.player.go
│ ├── dao.role.go
│ └── dao.map.go
├── tools
├── build.sh
├── kibana.bat
├── filebeat.setup.bat
├── metricbeat.setup.bat
├── elasticsearch.bat
├── filebeat.bat
├── metricbeat.bat
├── genclient.sh
└── genproto.sh
├── doc
├── 场景类消息流.jpg
├── 主要服务器关服流程.jpg
├── 主要服务器启动流程.jpg
├── 玩家注册登录流程.jpg
└── README.md
├── .gitmodules
├── .vscode
├── settings.json
└── launch.json
├── proto
├── etc
│ ├── etc.basic.proto
│ ├── etc.zones.proto
│ ├── etc.database.proto
│ └── etc.servers.proto
├── msg
│ ├── login-gate.proto
│ ├── world.proto
│ ├── gate-world.proto
│ ├── gate.proto
│ ├── world-database.proto
│ ├── balcony.proto
│ ├── client-chat.proto
│ ├── message.proto
│ ├── database.proto
│ ├── client-gate.proto
│ ├── client-world.proto
│ ├── center.proto
│ ├── gps.proto
│ ├── gate-database.proto
│ ├── client-login.proto
│ └── command.proto
├── config
│ ├── map.proto
│ └── scene.proto
├── data
│ ├── data.player.proto
│ ├── data.map.proto
│ ├── data.gate.proto
│ ├── data.entity.proto
│ ├── data.role.proto
│ └── data.component.proto
├── db
│ ├── db.role.proto
│ ├── db.player.proto
│ └── db.map.proto
├── engine
│ └── math.proto
├── gogoproto
│ ├── gogo.pb.golden
│ ├── Makefile
│ └── gogo.proto
└── protobuf
│ ├── source_context.proto
│ ├── empty.proto
│ ├── struct.proto
│ ├── wrappers.proto
│ ├── duration.proto
│ ├── any.proto
│ ├── timestamp.proto
│ └── type.proto
├── .travis.yml
├── go.mod
├── web
└── web.html
├── .gitignore
├── sql
├── dynamicmaps.sql
├── players.sql
├── roles.sql
├── staticmaps.sql
└── accounts.sql
├── MIND.md
├── main.go
├── LICENSE
├── README.md
└── go.sum
/log/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bin/release/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/etc/basic.yaml:
--------------------------------------------------------------------------------
1 | gamename: 突突突
2 |
--------------------------------------------------------------------------------
/src/services/world/util.go:
--------------------------------------------------------------------------------
1 | package world
2 |
--------------------------------------------------------------------------------
/bin/debug/4-web.bat:
--------------------------------------------------------------------------------
1 | cd ../../
2 | go run main.go -id 4
--------------------------------------------------------------------------------
/bin/debug/8-gps.bat:
--------------------------------------------------------------------------------
1 | cd ../../
2 | go run main.go -id 8
--------------------------------------------------------------------------------
/bin/debug/1-gate.bat:
--------------------------------------------------------------------------------
1 | cd ../../
2 | go run main.go -id 1
--------------------------------------------------------------------------------
/bin/debug/2-login.bat:
--------------------------------------------------------------------------------
1 | cd ../../
2 | go run main.go -id 2
--------------------------------------------------------------------------------
/bin/debug/3-database.bat:
--------------------------------------------------------------------------------
1 | cd ../../
2 | go run main.go -id 3
--------------------------------------------------------------------------------
/bin/debug/5-world.bat:
--------------------------------------------------------------------------------
1 | cd ../../
2 | go run main.go -id 5
--------------------------------------------------------------------------------
/bin/debug/6-world.bat:
--------------------------------------------------------------------------------
1 | cd ../../
2 | go run main.go -id 6
--------------------------------------------------------------------------------
/bin/debug/7-world.bat:
--------------------------------------------------------------------------------
1 | cd ../../
2 | go run main.go -id 7
--------------------------------------------------------------------------------
/bin/debug/9-balcony.bat:
--------------------------------------------------------------------------------
1 | cd ../../
2 | go run main.go -id 9
--------------------------------------------------------------------------------
/bin/debug/0-center.bat:
--------------------------------------------------------------------------------
1 | cd ../../
2 | go run main.go -id 0
3 |
--------------------------------------------------------------------------------
/bin/debug/1-gate.command:
--------------------------------------------------------------------------------
1 | cd `dirname $0`
2 | cd ../../
3 | go run main.go -id 1
--------------------------------------------------------------------------------
/bin/debug/4-web.command:
--------------------------------------------------------------------------------
1 | cd `dirname $0`
2 | cd ../../
3 | go run main.go -id 4
--------------------------------------------------------------------------------
/bin/debug/8-gps.command:
--------------------------------------------------------------------------------
1 | cd `dirname $0`
2 | cd ../../
3 | go run main.go -id 8
--------------------------------------------------------------------------------
/bin/debug/2-login.command:
--------------------------------------------------------------------------------
1 | cd `dirname $0`
2 | cd ../../
3 | go run main.go -id 2
--------------------------------------------------------------------------------
/bin/debug/3-database.command:
--------------------------------------------------------------------------------
1 | cd `dirname $0`
2 | cd ../../
3 | go run main.go -id 3
--------------------------------------------------------------------------------
/bin/debug/5-world.command:
--------------------------------------------------------------------------------
1 | cd `dirname $0`
2 | cd ../../
3 | go run main.go -id 5
--------------------------------------------------------------------------------
/bin/debug/6-world.command:
--------------------------------------------------------------------------------
1 | cd `dirname $0`
2 | cd ../../
3 | go run main.go -id 6
--------------------------------------------------------------------------------
/bin/debug/7-world.command:
--------------------------------------------------------------------------------
1 | cd `dirname $0`
2 | cd ../../
3 | go run main.go -id 7
--------------------------------------------------------------------------------
/bin/debug/9-balcony.command:
--------------------------------------------------------------------------------
1 | cd `dirname $0`
2 | cd ../../
3 | go run main.go -id 9
--------------------------------------------------------------------------------
/tools/build.sh:
--------------------------------------------------------------------------------
1 | cd ..
2 | go build -o bin/release/server.exe
3 | echo "finish"
4 |
--------------------------------------------------------------------------------
/bin/debug/0-center.command:
--------------------------------------------------------------------------------
1 | cd `dirname $0`
2 | cd ../../
3 | go run main.go -id 0
4 |
--------------------------------------------------------------------------------
/doc/场景类消息流.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iNeverSleeeeep/INServer/HEAD/doc/场景类消息流.jpg
--------------------------------------------------------------------------------
/bin/debug/fstopall.sh:
--------------------------------------------------------------------------------
1 | ps ef|grep "@in-"|grep -v "grep"|awk '{print $1}'|xargs kill -9
2 |
--------------------------------------------------------------------------------
/bin/debug/stopall.sh:
--------------------------------------------------------------------------------
1 | ps aux|grep "@in-"|grep -v "grep"|awk '{print $2}'|xargs kill -2
2 |
--------------------------------------------------------------------------------
/doc/主要服务器关服流程.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iNeverSleeeeep/INServer/HEAD/doc/主要服务器关服流程.jpg
--------------------------------------------------------------------------------
/doc/主要服务器启动流程.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iNeverSleeeeep/INServer/HEAD/doc/主要服务器启动流程.jpg
--------------------------------------------------------------------------------
/doc/玩家注册登录流程.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iNeverSleeeeep/INServer/HEAD/doc/玩家注册登录流程.jpg
--------------------------------------------------------------------------------
/etc/database.yaml:
--------------------------------------------------------------------------------
1 | ip: 127.0.0.1
2 | username: root
3 | password: 123456
4 | connmaxlifetime: 5
--------------------------------------------------------------------------------
/tools/kibana.bat:
--------------------------------------------------------------------------------
1 | title kibana
2 | ../ELK/kibana-7.5.1-windows-x86_64/bin/kibana.bat
3 | pause
--------------------------------------------------------------------------------
/tools/filebeat.setup.bat:
--------------------------------------------------------------------------------
1 | cd ../ELK/filebeat-7.5.1-windows-x86_64/
2 | filebeat.exe setup -e
3 | pause
--------------------------------------------------------------------------------
/tools/metricbeat.setup.bat:
--------------------------------------------------------------------------------
1 | cd ../ELK/metricbeat-7.5.1-windows-x86_64/
2 | metricbeat setup -e
3 | pause
--------------------------------------------------------------------------------
/tools/elasticsearch.bat:
--------------------------------------------------------------------------------
1 | title elasticsearch
2 | ../ELK/elasticsearch-7.5.1/bin/elasticsearch.bat
3 | pause
--------------------------------------------------------------------------------
/tools/filebeat.bat:
--------------------------------------------------------------------------------
1 | title filebeat
2 | cd ../ELK/filebeat-7.5.1-windows-x86_64/
3 | filebeat -c filebeat.yml -e
4 | pause
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "ELK"]
2 | path = ELK
3 | url = https://gitee.com/iNeverSleeeeep/ELK.git
4 | ignore = dirty
5 |
--------------------------------------------------------------------------------
/tools/metricbeat.bat:
--------------------------------------------------------------------------------
1 | title metricbeat
2 | cd ../ELK/metricbeat-7.5.1-windows-x86_64/
3 | metricbeat -c metricbeat.yml -e
4 | pause
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "git.ignoreLimitWarning": true,
3 | "go.lintFlags": [
4 | "-min_confidence=.8"
5 | ],
6 | }
--------------------------------------------------------------------------------
/bin/debug/runall.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | for /f "tokens=1 delims=." %%i in ('dir /a-d /b ^| findstr \-') do (
3 | START "%%i" %~dp0%%i.bat
4 | )
--------------------------------------------------------------------------------
/bin/debug/runall.command:
--------------------------------------------------------------------------------
1 | cd "$(dirname "$0")"
2 | for file in `ls|grep command`
3 | do
4 | if [[ $file != "runall.command" ]]
5 | then
6 | open "$file"
7 | fi
8 | done
--------------------------------------------------------------------------------
/proto/etc/etc.basic.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/etc";
4 |
5 | // 一些基本配置
6 |
7 | message BasicConfig {
8 | string GameName = 1; // 游戏名称
9 | }
--------------------------------------------------------------------------------
/src/services/world/messageHandler.go:
--------------------------------------------------------------------------------
1 | package world
2 |
3 | var messageHandler = new(handler)
4 |
5 | type (
6 | handler struct {
7 | }
8 | )
9 |
10 | func Init() {
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/etc/zones.yaml:
--------------------------------------------------------------------------------
1 | zones:
2 | - {zoneid: 0, name: 沙漠之鹰, state: open}
3 | - {zoneid: 1, name: 加特林, state: open}
4 | - {zoneid: 2, name: AK47, state: open}
5 | - {zoneid: 3, name: M4A1, state: open}
--------------------------------------------------------------------------------
/proto/msg/login-gate.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | import "client-gate.proto";
6 |
7 | message LoginToGate {
8 | SessionCert Cert = 1;
9 | }
--------------------------------------------------------------------------------
/proto/config/map.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/config";
4 |
5 | message Map {
6 | int32 MapID = 1;
7 | repeated int32 Scenes = 2;
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/src/common/global/interfaces.go:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | // 这里类里面是避免一些循环引用问题,所以使用接口来调用方法
4 |
5 | // IRoleGateGetter 取得角色所在的门服务器
6 | type IRoleGateGetter interface {
7 | GetRoleGate(uuid string) int32
8 | }
9 |
--------------------------------------------------------------------------------
/proto/config/scene.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/config";
4 |
5 | import "math.proto";
6 |
7 | message Scene {
8 | int32 SceneID = 1;
9 | Rect Rect = 2;
10 | }
11 |
--------------------------------------------------------------------------------
/proto/msg/world.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | import "data.role.proto";
6 |
7 | message RoleEnterNTF {
8 | int32 Gate = 1;
9 | Role Role = 2;
10 | }
--------------------------------------------------------------------------------
/proto/msg/gate-world.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | message GetMapIDReq {
6 | string MapUUID = 1;
7 | }
8 |
9 | message GetMapIDResp {
10 | int32 MapID = 1;
11 | }
--------------------------------------------------------------------------------
/src/README.md:
--------------------------------------------------------------------------------
1 | # 路径说明
2 |
3 | - cli 交互式命令行
4 | - common 通用函数
5 | - dao 数据库操作
6 | - engine 游戏引擎模块
7 | - gameplay 游戏内容
8 | - lifetime 服务器生命周期控制
9 | - proto proto生成文件
10 | - services 服务 目前一个服务器进程只启动一个服务
11 | - unittest 单元测试
12 |
--------------------------------------------------------------------------------
/proto/data/data.player.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/data";
4 |
5 | import "data.role.proto";
6 |
7 | message Player {
8 | repeated RoleSummaryData RoleList = 1;
9 | string UUID = 2;
10 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 | go:
3 | - 1.13
4 | script:
5 | - go build main.go
6 | notifications:
7 | email:
8 | recipients:
9 | - 362761534@qq.com
10 | on_success: change
11 | on_failure: always
12 | git:
13 | submodules: false
14 | env:
15 | - GO111MODULE=on
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module INServer
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/go-sql-driver/mysql v1.5.0
7 | github.com/gogo/protobuf v1.3.1
8 | github.com/golang/protobuf v1.3.2
9 | github.com/gorilla/websocket v1.4.1
10 | gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71
11 | )
12 |
--------------------------------------------------------------------------------
/src/common/protect/protect.go:
--------------------------------------------------------------------------------
1 | package protect
2 |
3 | import (
4 | "INServer/src/common/logger"
5 | )
6 |
7 | // CatchPanic 捕获异常
8 | func CatchPanic() {
9 | if logger.IsDebug {
10 | return
11 | }
12 | if err := recover(); err != nil {
13 | logger.Fatal(err)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/proto/data/data.map.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/data";
4 |
5 | import "data.entity.proto";
6 |
7 | message MapData {
8 | int32 MapID = 1;
9 | string MapUUID = 2;
10 | int64 LastTickTime = 3;
11 | repeated EntityData Entities = 4;
12 | }
--------------------------------------------------------------------------------
/proto/etc/etc.zones.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/etc";
4 |
5 | // 游戏区的各种配置
6 |
7 | message Zone {
8 | int32 ZoneID = 1;
9 | string Name = 2;
10 | string State = 3;
11 | }
12 |
13 | message ZoneList {
14 | repeated Zone Zones = 1;
15 | }
--------------------------------------------------------------------------------
/src/services/ai/ai.go:
--------------------------------------------------------------------------------
1 | package ai
2 |
3 | // Instance AI单例
4 | var Instance *AI
5 |
6 | // AI 负责游戏内怪物/NPC等的行为
7 | type AI struct {
8 | }
9 |
10 | // New 构造AI服务
11 | func New() *AI {
12 | a := new(AI)
13 | return a
14 | }
15 |
16 | // Start 启动AI服务
17 | func (a *AI) Start() {
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/proto/msg/gate.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | message ForwardPlayerMessage {
6 | string UUID = 1;
7 | bytes Buffer = 2;
8 | }
9 |
10 | message RoleLeaveReq {
11 | repeated string Roles = 1;
12 | }
13 |
14 | message RoleLeaveResp {
15 | }
--------------------------------------------------------------------------------
/proto/msg/world-database.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | import "data.map.proto";
6 |
7 | message LoadStaticMapReq {
8 | int32 ZoneID = 1;
9 | int32 StaticMapID = 2;
10 | }
11 |
12 | message LoadStaticMapResp {
13 | MapData Map = 1;
14 | }
--------------------------------------------------------------------------------
/src/services/robot/robot.go:
--------------------------------------------------------------------------------
1 | package robot
2 |
3 | // Instance 机器人服务单例
4 | var Instance *Robot
5 |
6 | // Robot 机器人 用于压测
7 | type Robot struct {
8 | }
9 |
10 | // New 构造Robot服务
11 | func New() *Robot {
12 | r := new(Robot)
13 | return r
14 | }
15 |
16 | // Start 启动Robot服务
17 | func (r *Robot) Start() {
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/services/world/zoneworld.go:
--------------------------------------------------------------------------------
1 | package world
2 |
3 | import "INServer/src/gameplay/gamemap"
4 |
5 | type (
6 | ZoneWorld struct {
7 | gameMaps map[int32]*gamemap.Map
8 | }
9 | )
10 |
11 | func NewZoneWorld() *ZoneWorld {
12 | zw := new(ZoneWorld)
13 | zw.gameMaps = make(map[int32]*gamemap.Map)
14 | return zw
15 | }
--------------------------------------------------------------------------------
/web/web.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 | Hello Web
11 |
12 |
--------------------------------------------------------------------------------
/proto/msg/balcony.proto:
--------------------------------------------------------------------------------
1 |
2 | syntax = "proto3";
3 |
4 | option go_package = "INServer/src/proto/msg";
5 |
6 | import "data.role.proto";
7 |
8 | message RoleEnterReq {
9 | string RoleUUID = 1;
10 | }
11 |
12 | message RoleEnterResp {
13 | bool Success = 1;
14 | int32 MapID = 2;
15 | Role Role = 3;
16 | int32 WorldID = 4;
17 | }
--------------------------------------------------------------------------------
/src/unittest/golang_test.go:
--------------------------------------------------------------------------------
1 | package unittest
2 |
3 | import (
4 | "INServer/src/common/logger"
5 | "strconv"
6 | "testing"
7 | "time"
8 | )
9 |
10 | func TestTime(t *testing.T) {
11 | t1 := strconv.FormatInt(time.Now().UnixNano(), 10)
12 | t2 := strconv.FormatInt(time.Now().UnixNano(), 10)
13 | logger.Debug(t1)
14 | logger.Debug(t2)
15 | }
16 |
--------------------------------------------------------------------------------
/proto/db/db.role.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/db";
4 |
5 | import "gogo.proto";
6 |
7 | message DBRole {
8 | string UUID = 1 [(gogoproto.moretags) = "db:\"UUID\""];
9 | bytes SummaryData = 2 [(gogoproto.moretags) = "db:\"SummaryData\""];
10 | bytes OnlineData = 3 [(gogoproto.moretags) = "db:\"OnlineData\""];
11 | }
--------------------------------------------------------------------------------
/doc/README.md:
--------------------------------------------------------------------------------
1 | ## 目录
2 | - [主要服务器启动流程图](#主要服务器启动流程图)
3 | - [主要服务器关服流程图](#主要服务器关服流程图)
4 | - [玩家注册登录流程图](#玩家注册登录流程图)
5 | - [场景类消息流](#场景类消息流)
6 |
7 | ### 主要服务器启动流程图
8 | 
9 |
10 | ### 主要服务器关服流程图
11 | 
12 |
13 | ### 玩家注册登录流程图
14 | 
15 |
16 | ### 场景类消息流
17 | 
18 |
--------------------------------------------------------------------------------
/proto/etc/etc.database.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/etc";
4 |
5 | message Database {
6 | string IP = 1; // 数据库IP地址
7 | string UserName = 2; // 用户名
8 | string Password = 3; // 密码
9 | int64 ConnMaxLifetime = 4; // 最大连接周期,超过时间的连接就close 单位秒
10 | int32 MaxOpenConns = 5; // 最大连接数
11 | int32 MaxIdleConns = 6; // 闲置连接数
12 | }
--------------------------------------------------------------------------------
/src/unittest/uuid_test.go:
--------------------------------------------------------------------------------
1 | package unittest
2 |
3 | import (
4 | "INServer/src/common/uuid"
5 | "testing"
6 | )
7 |
8 | func TestUUID(t *testing.T) {
9 | uuids := make(map[string]bool)
10 | // 测试一千万次循环uuid是否会重复
11 | for i := 0; i < 10000000; i++ {
12 | uid := uuid.New()
13 | if _, ok := uuids[uid]; ok {
14 | t.Fail()
15 | return
16 | } else {
17 | uuids[uid] = true
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/gameplay/ecs/system/system.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import "INServer/src/gameplay/ecs"
4 |
5 | var (
6 | MoveSystem = &move{}
7 | PhysicsSystem = &physics{}
8 | )
9 |
10 | type ISystem interface {
11 | Tick(dt float64, entities map[string]*ecs.Entity)
12 | }
13 |
14 | func Tick(dt float64, entities map[string]*ecs.Entity) {
15 | MoveSystem.Tick(dt, entities)
16 | PhysicsSystem.Tick(dt, entities)
17 | }
18 |
--------------------------------------------------------------------------------
/bin/debug/runall.sh:
--------------------------------------------------------------------------------
1 | cd "$(dirname "$0")"
2 | go build -o ../../inserver-temp.exe ../../main.go
3 | cd ../..
4 | ./inserver-temp.exe -id 0 &
5 | ./inserver-temp.exe -id 1 &
6 | ./inserver-temp.exe -id 2 &
7 | ./inserver-temp.exe -id 3 &
8 | ./inserver-temp.exe -id 4 &
9 | ./inserver-temp.exe -id 5 &
10 | ./inserver-temp.exe -id 6 &
11 | ./inserver-temp.exe -id 7 &
12 | ./inserver-temp.exe -id 8 &
13 | ./inserver-temp.exe -id 9 &
14 |
--------------------------------------------------------------------------------
/src/services/chat/chat.go:
--------------------------------------------------------------------------------
1 | package chat
2 |
3 | import (
4 | "INServer/src/proto/msg"
5 | "INServer/src/services/node"
6 | )
7 |
8 | type (
9 | Chat struct {
10 | }
11 | )
12 |
13 | func New() *Chat {
14 | c := new(Chat)
15 |
16 | return c
17 | }
18 |
19 | func (c *Chat) Start() {
20 | node.Net.Listen(msg.CMD_CCHAT_CHAT, c.onClientChatMessage)
21 | }
22 |
23 | func (c *Chat) onClientChatMessage(eader *msg.MessageHeader, buffer []byte) {
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/proto/msg/client-chat.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | enum ChatType {
6 | LOCAL = 0;
7 | WORLD = 1;
8 | PRIVATE = 3;
9 | }
10 |
11 | message ClientToChat {
12 | ChatType ChatType = 1;
13 | string Message = 2;
14 | string ReceiverUUID = 3; // 私聊的时候需要发接受者ID
15 | }
16 |
17 | message ChatToClient {
18 | ChatType ChatType = 1;
19 | string Message = 2;
20 | string SenderUUID = 3;
21 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 | __debug_bin
8 |
9 | # Test binary, built with `go test -c`
10 | *.test
11 |
12 | # Output of the go coverage tool, specifically when used with LiteIDE
13 | *.out
14 |
15 | *.log
16 |
17 | # Mac
18 | *.DS_Store
19 |
20 | clientproto
21 |
22 | # 本地配置
23 | etc/local*
24 |
25 | # go build 产生的文件
26 | INServer
27 | main
28 |
29 | # https
30 | *.crt
31 | *.key
32 |
33 | *.zip
--------------------------------------------------------------------------------
/proto/engine/math.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/engine";
4 |
5 | message Vector2 {
6 | double X = 1;
7 | double Z = 2;
8 | }
9 |
10 | message Vector3 {
11 | double X = 1;
12 | double Y = 2;
13 | double Z = 3;
14 | }
15 |
16 | message Rect {
17 | double X = 1;
18 | double Z = 2;
19 | double Width = 3;
20 | double Height = 4;
21 | }
22 |
23 | message Quaternion {
24 | double X = 1;
25 | double Y = 2;
26 | double Z = 3;
27 | double W = 4;
28 | }
--------------------------------------------------------------------------------
/proto/db/db.player.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/db";
4 |
5 | import "gogo.proto";
6 |
7 | message DBAccount {
8 | string Name = 1 [(gogoproto.moretags) = "db:\"Name\""];
9 | string PasswordHash = 2 [(gogoproto.moretags) = "db:\"PasswordHash\""];
10 | string PlayerUUID = 3 [(gogoproto.moretags) = "db:\"PlayerUUID\""];
11 | }
12 |
13 | message DBPlayer {
14 | string UUID = 1 [(gogoproto.moretags) = "db:\"UUID\""];
15 | bytes SerializedData = 2 [(gogoproto.moretags) = "db:\"SerializedData\""];
16 | }
--------------------------------------------------------------------------------
/sql/dynamicmaps.sql:
--------------------------------------------------------------------------------
1 | SET NAMES utf8mb4;
2 | SET FOREIGN_KEY_CHECKS = 0;
3 |
4 | -- ----------------------------
5 | -- Table structure for dynamicmaps
6 | -- ----------------------------
7 | DROP TABLE IF EXISTS `dynamicmaps`;
8 | CREATE TABLE `dynamicmaps` (
9 | `UUID` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
10 | `SerializedData` longblob NULL,
11 | PRIMARY KEY (`UUID`) USING BTREE
12 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
13 |
14 | SET FOREIGN_KEY_CHECKS = 1;
15 |
--------------------------------------------------------------------------------
/proto/data/data.gate.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/data";
4 |
5 | import "data.role.proto";
6 |
7 | enum SessionState {
8 | Offline = 0; // 无连接 默认状态 可以认为无连接的用户应该被Gate删除
9 | Connected = 1; // 连接状态,但是没有经过验证
10 | Online = 2; // 验证通过状态
11 | OutOfContact = 3; // 短暂失联状态,可以断线重连
12 | }
13 |
14 | message RoleSessionInfo {
15 | string RoleUUID = 1;
16 | RoleAddress Address = 2;
17 | SessionState State = 3;
18 | }
19 |
20 | message SessionCertData {
21 | string Key = 1;
22 | int64 OutOfDateTime = 2;
23 | }
--------------------------------------------------------------------------------
/proto/msg/message.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | import "command.proto";
6 |
7 | message MessageHeader {
8 | CMD Command = 1;
9 | uint64 Sequence = 2;
10 | int32 From = 3;
11 | string RoleUUID = 4;
12 | }
13 |
14 | message Message {
15 | MessageHeader Header = 1;
16 | bytes Buffer = 2;
17 | }
18 |
19 | message Package {
20 | uint64 UniqueID = 1;
21 | int32 From = 2;
22 | int32 Index = 3;
23 | int32 Total = 4;
24 | bytes Buffer = 5;
25 | }
26 |
27 | message KeepAlive {
28 | int32 ServerID = 1;
29 | }
30 |
--------------------------------------------------------------------------------
/sql/players.sql:
--------------------------------------------------------------------------------
1 | SET NAMES utf8mb4;
2 | SET FOREIGN_KEY_CHECKS = 0;
3 |
4 | -- ----------------------------
5 | -- Table structure for players
6 | -- ----------------------------
7 | DROP TABLE IF EXISTS `players`;
8 | CREATE TABLE `players` (
9 | `UUID` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
10 | `SerializedData` blob NULL,
11 | PRIMARY KEY (`UUID`) USING BTREE,
12 | UNIQUE INDEX `UUID_UNIQUE`(`UUID`) USING BTREE
13 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
14 |
15 | SET FOREIGN_KEY_CHECKS = 1;
16 |
--------------------------------------------------------------------------------
/src/common/global/global.go:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | import (
4 | "INServer/src/proto/etc"
5 | )
6 |
7 | var (
8 | // CurrentServerID 当前服务器ID
9 | CurrentServerID int32 = 0
10 | // CurrentServerType 当前服务器类型
11 | CurrentServerType string = InvalidServer
12 | // CurrentServerConfig 当前服务器配置
13 | CurrentServerConfig *etc.ServerConfig = nil
14 |
15 | // CenterIP 中心服默认IP
16 | CenterIP string = "127.0.0.1"
17 |
18 | // PendingExit 等待进程终止状态
19 | PendingExit bool
20 | // Exit 由命令行或消息引起的进程退出使用这个chan
21 | Exit chan bool
22 |
23 | // RoleGateGetter 根据角色UUID取得所在门服务器
24 | RoleGateGetter IRoleGateGetter
25 | )
26 |
--------------------------------------------------------------------------------
/proto/db/db.map.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/db";
4 |
5 | import "gogo.proto";
6 |
7 | message DBDynamicMap {
8 | string UUID = 1 [(gogoproto.moretags) = "db:\"UUID\""];
9 | bytes SerializedData = 2 [(gogoproto.moretags) = "db:\"SerializedData\""];
10 | }
11 |
12 | message DBStaticMap {
13 | int32 ZoneID = 1 [(gogoproto.moretags) = "db:\"ZoneID\""];
14 | int32 MapID = 2 [(gogoproto.moretags) = "db:\"MapID\""];
15 | string UUID = 3 [(gogoproto.moretags) = "db:\"UUID\""];
16 | bytes SerializedData = 4 [(gogoproto.moretags) = "db:\"SerializedData\""];
17 | }
--------------------------------------------------------------------------------
/proto/data/data.entity.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/data";
4 |
5 | import "data.component.proto";
6 |
7 | enum EntityType {
8 | OAAEntity = 0; // one above all
9 | RoleEntity = 1;
10 | MonsterEntity = 2;
11 | BulletEntity = 3;
12 | NPCEntity = 4;
13 | TriggerEntity = 5;
14 | }
15 |
16 | message EntityRealtimeData {
17 | string LastStaticMapUUID = 1;
18 | string CurrentMapUUID = 2;
19 | }
20 |
21 | message EntityData {
22 | string EntityUUID = 1;
23 | EntityRealtimeData RealTimeData = 2;
24 | repeated Component Components = 3;
25 | }
--------------------------------------------------------------------------------
/proto/msg/database.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | import "data.map.proto";
6 | import "data.role.proto";
7 |
8 | message SaveStaticMapReq {
9 | repeated MapData StaticMaps = 1;
10 | }
11 |
12 | message SaveStaticMapResp {
13 | bool Success = 1;
14 | }
15 |
16 | message SaveRoleReq {
17 | repeated Role Roles = 1;
18 | }
19 |
20 | message SaveRoleResp {
21 | bool Success = 1;
22 | }
23 |
24 | message SaveDynamicMapReq {
25 | repeated MapData DynamicMaps = 1;
26 | }
27 |
28 | message SaveDynamicMapResp {
29 | bool Success = 1;
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/sql/roles.sql:
--------------------------------------------------------------------------------
1 | SET NAMES utf8mb4;
2 | SET FOREIGN_KEY_CHECKS = 0;
3 |
4 | -- ----------------------------
5 | -- Table structure for roles
6 | -- ----------------------------
7 | DROP TABLE IF EXISTS `roles`;
8 | CREATE TABLE `roles` (
9 | `UUID` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
10 | `SummaryData` longblob NULL,
11 | `OnlineData` longblob NULL,
12 | PRIMARY KEY (`UUID`) USING BTREE,
13 | UNIQUE INDEX `UUID_UNIQUE`(`UUID`) USING BTREE
14 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
15 |
16 | SET FOREIGN_KEY_CHECKS = 1;
17 |
--------------------------------------------------------------------------------
/src/engine/extensions/rect/rect.go:
--------------------------------------------------------------------------------
1 | package rect
2 |
3 | import "INServer/src/proto/engine"
4 |
5 | func Quadrants(r *engine.Rect) (ul, ur, ll, lr *engine.Rect) {
6 | w := r.Width / 2.0
7 | h := r.Height / 2.0
8 | ll = &engine.Rect{X: r.X, Z: r.Z, Width: w, Height: h}
9 | ul = &engine.Rect{X: r.X, Z: r.Z + h, Width: w, Height: h}
10 | ur = &engine.Rect{X: r.X + w, Z: r.Z + h, Width: w, Height: h}
11 | lr = &engine.Rect{X: r.X + w, Z: r.Z, Width: w, Height: h}
12 | return ul, ur, ll, lr
13 | }
14 |
15 | func Contains(r *engine.Rect, p *engine.Vector2) bool {
16 | return p.X >= r.X && p.Z >= r.Z && p.X < r.X+r.Width && p.Z < r.Z+r.Height
17 | }
18 |
--------------------------------------------------------------------------------
/src/proto/config/map.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: map.proto
3 |
4 | package config
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *Map) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *Map) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
--------------------------------------------------------------------------------
/sql/staticmaps.sql:
--------------------------------------------------------------------------------
1 | SET NAMES utf8mb4;
2 | SET FOREIGN_KEY_CHECKS = 0;
3 |
4 | -- ----------------------------
5 | -- Table structure for staticmaps
6 | -- ----------------------------
7 | DROP TABLE IF EXISTS `staticmaps`;
8 | CREATE TABLE `staticmaps` (
9 | `UUID` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
10 | `SerializedData` longblob NULL,
11 | `ZoneID` int(11) NULL DEFAULT NULL,
12 | `MapID` int(11) NULL DEFAULT NULL,
13 | PRIMARY KEY (`UUID`) USING BTREE,
14 | UNIQUE INDEX `UUID_UNIQUE`(`UUID`) USING BTREE
15 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
16 |
17 | SET FOREIGN_KEY_CHECKS = 1;
18 |
--------------------------------------------------------------------------------
/src/proto/config/scene.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: scene.proto
3 |
4 | package config
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *Scene) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *Scene) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
--------------------------------------------------------------------------------
/src/proto/data/data.map.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: data.map.proto
3 |
4 | package data
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *MapData) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *MapData) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
--------------------------------------------------------------------------------
/proto/msg/client-gate.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | import "command.proto";
6 | import "data.role.proto";
7 |
8 | message SessionCert {
9 | string UUID = 1;
10 | string Key = 2;
11 | }
12 |
13 | message ConnectGateReq {
14 | SessionCert SessionCert = 1;
15 | }
16 |
17 | message ConnectGateResp {
18 | bool Success = 1;
19 | int32 MapID = 2;
20 | Role Role = 3;
21 | }
22 |
23 | message ClientToGate {
24 | CMD Command = 1;
25 | uint64 Sequence = 2;
26 | bytes Request = 3;
27 | bytes Notify = 4;
28 | }
29 |
30 | message GateToClient {
31 | CMD Command = 1;
32 | uint64 Sequence = 2;
33 | bytes Buffer = 3;
34 | }
--------------------------------------------------------------------------------
/src/proto/data/data.player.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: data.player.proto
3 |
4 | package data
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *Player) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *Player) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
--------------------------------------------------------------------------------
/src/proto/etc/etc.basic.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: etc.basic.proto
3 |
4 | package etc
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *BasicConfig) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *BasicConfig) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
--------------------------------------------------------------------------------
/src/proto/etc/etc.database.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: etc.database.proto
3 |
4 | package etc
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *Database) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *Database) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
--------------------------------------------------------------------------------
/proto/msg/client-world.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | import "math.proto";
6 | import "data.entity.proto";
7 |
8 | message MoveINF {
9 | Vector3 Position = 1;
10 | Vector3 To = 2;
11 | }
12 |
13 | message StopMoveINF {
14 | Vector3 Position = 1;
15 | }
16 |
17 | message MoveNTF {
18 | string EntityUUID = 1;
19 | Vector3 To = 2;
20 | }
21 |
22 | message NearEntity {
23 | string EntityUUID = 1;
24 | Vector3 Position = 2;
25 | }
26 |
27 | message NearEntitiesNTF {
28 | repeated NearEntity Entities = 1;
29 | }
30 |
31 | message EntityDataReq {
32 | repeated string EntityUUIDs = 1;
33 | }
34 |
35 | message EntityDataRes {
36 | repeated EntityData Entities = 1;
37 | }
--------------------------------------------------------------------------------
/sql/accounts.sql:
--------------------------------------------------------------------------------
1 | SET NAMES utf8mb4;
2 | SET FOREIGN_KEY_CHECKS = 0;
3 |
4 | -- ----------------------------
5 | -- Table structure for accounts
6 | -- ----------------------------
7 | DROP TABLE IF EXISTS `accounts`;
8 | CREATE TABLE `accounts` (
9 | `Name` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
10 | `PasswordHash` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
11 | `PlayerUUID` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
12 | PRIMARY KEY (`Name`) USING BTREE,
13 | UNIQUE INDEX `Name_UNIQUE`(`Name`) USING BTREE
14 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
15 |
16 | SET FOREIGN_KEY_CHECKS = 1;
17 |
--------------------------------------------------------------------------------
/proto/data/data.role.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/data";
4 |
5 | import "data.entity.proto";
6 |
7 | // 离线数据
8 | message RoleSummaryData {
9 | string Name = 1; // 角色名
10 | int32 Zone = 2; // 游戏区
11 | string RoleUUID = 3; // RoleUUID
12 | string PlayerUUID = 4; // PlayerUUID
13 | string MapUUID = 5; // 所在地图
14 | string MailUUID = 6; // 邮件地址
15 | }
16 |
17 | message RoleAddress {
18 | int32 Gate = 1;
19 | int32 World = 2;
20 | }
21 |
22 | // 在线数据
23 | message RoleOnlineData {
24 | EntityData EntityData = 1;
25 | }
26 |
27 | // 实时数据 与场景相关的数据
28 | message RoleRealtimeData {
29 | string LastStaticMapUUID = 1;
30 | }
31 |
32 | message Role {
33 | RoleSummaryData SummaryData = 1;
34 | RoleOnlineData OnlineData = 2;
35 | }
--------------------------------------------------------------------------------
/proto/msg/center.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | import "etc.servers.proto";
4 | import "etc.zones.proto";
5 | import "etc.basic.proto";
6 | import "etc.database.proto";
7 |
8 | option go_package = "INServer/src/proto/msg";
9 |
10 | enum NodeState {
11 | Unset = 0;
12 | Ready = 1;
13 | Running = 2;
14 | Offline = 3;
15 | }
16 |
17 | message ETCSyncNTF {
18 | BasicConfig BasicConfig = 1;
19 | Database Database = 2;
20 | ServerList ServerList = 3;
21 | ZoneList ZoneList = 4;
22 | }
23 |
24 | message NodeStartNTF {
25 | bytes Address = 1;
26 | }
27 |
28 | message Node {
29 | NodeState NodeState = 1;
30 | bytes NodeAddress = 2;
31 | }
32 |
33 | message NodesInfoNTF {
34 | repeated Node Nodes = 1;
35 | }
36 |
37 | message ResetConnectionNTF {
38 | int32 ServerID = 1;
39 | }
--------------------------------------------------------------------------------
/tools/genclient.sh:
--------------------------------------------------------------------------------
1 | cd ../proto
2 |
3 | # data
4 | echo "--------- data ---------"
5 | for file in `ls data`
6 | do
7 | echo $file
8 | protoc --csharp_out=../clientproto --proto_path=./data --proto_path=./engine $file
9 | done
10 |
11 | # msg
12 | echo "--------- msg ---------"
13 | for file in `ls msg`
14 | do
15 | echo $file
16 | protoc --csharp_out=../clientproto --proto_path=./msg --proto_path=./data --proto_path=./etc --proto_path=./engine $file
17 | done
18 |
19 | # msg
20 | echo "--------- engine ---------"
21 | for file in `ls engine`
22 | do
23 | echo $file
24 | protoc --csharp_out=../clientproto --proto_path=./engine $file
25 | done
26 |
27 | # msg
28 | echo "--------- etc ---------"
29 | for file in `ls etc`
30 | do
31 | echo $file
32 | protoc --csharp_out=../clientproto --proto_path=./etc $file
33 | done
34 |
--------------------------------------------------------------------------------
/src/gameplay/ecs/system/physics.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "INServer/src/gameplay/ecs"
5 | "INServer/src/proto/data"
6 | )
7 |
8 | type physics struct {
9 | }
10 |
11 | func (m *physics) Tick(dt float64, entities map[string]*ecs.Entity) {
12 | for _, entity := range entities {
13 | physics := entity.GetComponent(data.ComponentType_Physics).Physics
14 | if physics != nil {
15 | slowdown(dt, physics)
16 | }
17 | }
18 | }
19 |
20 | func max(a, b float64) float64 {
21 | if a > b {
22 | return a
23 | }
24 | return b
25 | }
26 |
27 | func slowdown(dt float64, physics *data.PhysicsComponent) {
28 | a := 1 / physics.Mass
29 | physics.PassiveSpeed.X -= max(a*dt, physics.PassiveSpeed.X)
30 | physics.PassiveSpeed.Y -= max(a*dt, physics.PassiveSpeed.Y)
31 | physics.PassiveSpeed.Z -= max(a*dt, physics.PassiveSpeed.Z)
32 | }
33 |
--------------------------------------------------------------------------------
/src/services/innet/util.go:
--------------------------------------------------------------------------------
1 | package innet
2 |
3 | import (
4 | "INServer/src/common/logger"
5 | "errors"
6 | "net"
7 | )
8 |
9 | const (
10 | timeout int64 = 10 * 1E6 // 纳秒
11 | sliceSize int = 1000 // MTU 1472
12 |
13 | sendport = 11000
14 | recvport = 12000
15 | expvarport = 13000
16 | )
17 |
18 | func getIP() []byte {
19 | netInterfaces, err := net.Interfaces()
20 | if err != nil {
21 | logger.Fatal(err)
22 | }
23 |
24 | for i := 0; i < len(netInterfaces); i++ {
25 | if (netInterfaces[i].Flags & net.FlagUp) != 0 {
26 | addrs, _ := netInterfaces[i].Addrs()
27 |
28 | for _, address := range addrs {
29 | if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
30 | if ipnet.IP.To4() != nil {
31 | return ipnet.IP.To4()
32 | }
33 | }
34 | }
35 | }
36 | }
37 |
38 | logger.Fatal(errors.New("No Valid IPV4!"))
39 | return nil
40 | }
41 |
--------------------------------------------------------------------------------
/MIND.md:
--------------------------------------------------------------------------------
1 | ### 一些想法
2 | * 所有的数据都定义在proto/data里面,数据和逻辑完全分离,玩家的数据存储在一个proto中,这样既方便序列化,又方便使用json进行快速验证,又方便客户端做热加载(客户端逻辑与数据分离)
3 | * 所有服务器通过与中心服务器通信来确定自己的类型,所有配置档(包括服务器配置和游戏配置)都由中心服发出
4 | * 最终实现的目标是所有玩家只在逻辑上分区,实际不分区服的在服务器集群中
5 | * 使用ECS结构编写逻辑
6 | * 只有有限的数据作为存储单元 这个得想一下 比如角色、地图、帮会等。 而怪物应该是跟随地图走,Buff跟随角色走
7 | * 是否使用机器服务器来启动当前机器上的各个服务器
8 | * 后台功能
9 | - (done) ELK 收集日志
10 | - 现在服务器都是单线程的 如果后期有必要的话 可以把一些压力大的服务器改为多线程
11 |
12 | ### 服务器类型包括如下:
13 | * 中心服务器 (广播服务器状态,发送服务器配置,游戏配置)
14 | * 登录服务器
15 | * 门服务器 (只做消息转发,不做逻辑处理)
16 | * 世界服务器 (静态场景,分线)
17 | * 副本服务器 (动态场景,可以随时创建销毁,不保存副本配置,这样可以由客户端直接发来运行时配置用于快速调试)
18 | * 聊天服务器 (世界,当前,帮派,组队,好友)
19 | * 邮件服务器
20 | * AI服务器
21 | * 玩家消息中转服务器 (用于向不确定Gate的玩家发送消息)
22 | * 数据库服务器
23 | * 日志服务器
24 | * 负载服务器 (负责统计当前机器的负载情况)
25 | * 匹配、帧同步、排行榜、帮派等专项功能服务器
26 | * SDK服务器 (登录、支付等)
27 |
28 | ### 接下来要做的
29 | - 消息分类与消息流整理
30 | - 服务器存储数据类型整理
31 | - 角色加载与释放流程整理
32 |
33 | ### 可以用到的包
34 | * gopsutil 搜集机器负载,CPU使用率等
35 |
--------------------------------------------------------------------------------
/src/unittest/udp_test.go:
--------------------------------------------------------------------------------
1 | package unittest
2 |
3 | import (
4 | "INServer/src/common/logger"
5 | "net"
6 | "testing"
7 | )
8 |
9 | func newConn() *net.UDPConn {
10 | raddr, err := net.ResolveUDPAddr("udp4", ":10000")
11 | if err != nil {
12 | logger.Debug(err)
13 | return nil
14 | }
15 | //laddr, err := net.ResolveUDPAddr("udp4", ":10001")
16 | //if err != nil {
17 | // logger.Debug(err)
18 | // return nil
19 | //}
20 | conn, err := net.DialUDP("udp4", nil, raddr)
21 | if err != nil {
22 | logger.Debug(err)
23 | return nil
24 | }
25 | return conn
26 | }
27 |
28 | func TestDialUDP(t *testing.T) {
29 | conn := newConn()
30 | if conn == nil {
31 | t.FailNow()
32 | }
33 | conn = newConn()
34 | if conn == nil {
35 | t.FailNow()
36 | }
37 | conn = newConn()
38 | if conn == nil {
39 | t.FailNow()
40 | }
41 | conn = newConn()
42 | if conn == nil {
43 | t.FailNow()
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/proto/msg/gps.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | import "data.role.proto";
6 |
7 | message UpdateRoleAddressNTF {
8 | string RoleUUID = 1;
9 | RoleAddress Address = 2;
10 | }
11 |
12 | message RemoveRoleAddressNTF {
13 | string RoleUUID = 1;
14 | }
15 |
16 | message UpdateMapAddressNTF {
17 | string MapUUID = 1;
18 | int32 ServerID = 2;
19 | }
20 |
21 | message RemoveMapAddressNTF {
22 | string MapUUID = 1;
23 | }
24 |
25 | message GetMapAddressReq {
26 | string MapUUID = 1;
27 | }
28 |
29 | message GetMapAddressResp {
30 | int32 ServerID = 1;
31 | }
32 |
33 | message UpdateStaticMapUUIDNTF {
34 | int32 ZoneID = 1;
35 | int32 StaticMapID = 2;
36 | string StaticMapUUID = 3;
37 | }
38 |
39 | message GetStaticMapUUIDReq {
40 | int32 ZoneID = 1;
41 | int32 StaticMapID = 2;
42 | }
43 |
44 | message GetStaticMapUUIDResp {
45 | string StaticMapUUID = 1;
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/src/gameplay/ecs/system/reborn.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "INServer/src/gameplay/ecs"
5 | "INServer/src/proto/data"
6 | "time"
7 | )
8 |
9 | type reborn struct {
10 | }
11 |
12 | func (r *reborn) Tick(dt float64, entities map[string]*ecs.Entity) {
13 | now := time.Now().UnixNano()
14 | for _, entity := range entities {
15 | reborn := entity.GetComponent(data.ComponentType_Reborn).Reborn
16 | if reborn != nil && reborn.RebornType == data.RebornType_Auto && reborn.RebornTime > 0 {
17 | if reborn.RebornTime < now {
18 | reset(entity, reborn)
19 | }
20 | }
21 | }
22 | }
23 |
24 | func reset(entity *ecs.Entity, reborn *data.RebornComponent) {
25 | attribute := entity.GetComponent(data.ComponentType_Attribute).Attribute
26 | if attribute != nil {
27 | attribute.HP = attribute.MaxHP
28 | }
29 | transform := entity.GetComponent(data.ComponentType_Transofrm).Transform
30 | if transform != nil {
31 | transform.Position = reborn.Position
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/services/gate/services.go:
--------------------------------------------------------------------------------
1 | package gate
2 |
3 | import (
4 | "INServer/src/proto/data"
5 | "INServer/src/proto/msg"
6 | "INServer/src/services/node"
7 |
8 | "github.com/golang/protobuf/proto"
9 | )
10 |
11 | type (
12 | services struct {
13 | }
14 | )
15 |
16 | func newServices() *services {
17 | s := new(services)
18 | return s
19 | }
20 |
21 | func (s *services) start() {
22 | node.Net.Listen(msg.CMD_SESSION_CERT_NTF, s.onSessionCert)
23 | }
24 |
25 | func (s *services) onSessionCert(header *msg.MessageHeader, buffer []byte) {
26 | message := &msg.LoginToGate{}
27 | err := proto.Unmarshal(buffer, message)
28 | if err != nil {
29 | return
30 | }
31 | UUID := message.Cert.UUID
32 | role, ok := Instance.roles[UUID]
33 | if ok == false {
34 | role = newSession(nil, UUID)
35 | role.info.State = data.SessionState_Offline
36 | Instance.roles[UUID] = role
37 | }
38 | role.cert.Key = message.Cert.Key
39 | role.cert.OutOfDateTime = generateCertOutOfDateTime()
40 | }
41 |
--------------------------------------------------------------------------------
/proto/msg/gate-database.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | import "data.player.proto";
6 | import "data.role.proto";
7 |
8 | message CreatePlayerReq {
9 | string PlayerUUID = 1;
10 | }
11 |
12 | message CreatePlayerResp {
13 | bool Success = 1;
14 | }
15 |
16 | message LoadPlayerReq {
17 | string PlayerUUID = 1;
18 | }
19 |
20 | message LoadPlayerResp {
21 | bool Success = 1;
22 | Player Player = 2;
23 | }
24 |
25 | message ReleasePlayerNtf {
26 | string PlayerUUID = 1;
27 | }
28 |
29 | message LoadRoleReq {
30 | string RoleUUID = 1;
31 | }
32 |
33 | message LoadRoleResp {
34 | bool Success = 1;
35 | int32 WorldID = 2;
36 | string MapUUID = 3;
37 | Role Role = 4;
38 | }
39 |
40 | message CreateRoleReq {
41 | string PlayerUUID = 1;
42 | string RoleName = 2;
43 | int32 Zone = 3;
44 | }
45 |
46 | message CreateRoleResp {
47 | bool Success = 1;
48 | RoleSummaryData Role = 2;
49 | }
50 |
--------------------------------------------------------------------------------
/proto/msg/client-login.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | import "client-gate.proto";
6 | import "data.player.proto";
7 |
8 | message CLLogon {
9 | string Name = 1;
10 | string PasswordHash = 2;
11 | }
12 |
13 | message CLLogin {
14 | string Name = 1;
15 | string PasswordHash = 2;
16 | }
17 |
18 | message CLChangePassword {
19 | string Name = 1;
20 | string OldPasswordHash = 2;
21 | string NewPasswordHash = 3;
22 | }
23 |
24 | message CLRoleEnterGame {
25 | string RoleUUID = 1;
26 | }
27 |
28 | message CLCreateRole {
29 | string RoleName = 1;
30 | int32 Zone = 2;
31 | }
32 |
33 | message ClientToLogin {
34 | CLLogon Logon = 1;
35 | CLLogin Login = 2;
36 | CLChangePassword ChangePassword = 3;
37 | CLCreateRole CreateRole = 4;
38 | CLRoleEnterGame EnterGame = 5;
39 | }
40 |
41 | message LoginToClient {
42 | bool Success = 1;
43 | SessionCert SessionCert = 2;
44 | string GateIP = 3;
45 | int32 GatePort = 4;
46 | int32 GateWebPort = 5;
47 | Player Player = 6;
48 | }
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "INServer/src/cli"
5 | "INServer/src/common/global"
6 | "INServer/src/common/logger"
7 | "INServer/src/common/profiler"
8 | "INServer/src/lifetime/finalize"
9 | "INServer/src/lifetime/startup"
10 | _ "expvar"
11 | "flag"
12 | "fmt"
13 | "log"
14 | "runtime"
15 | )
16 |
17 | var serverID = flag.Int("id", -1, "本服务器ID(范围0~65535)")
18 | var centerIP = flag.String("center", "127.0.0.1", "中心服务器IP")
19 | var interactive = flag.Bool("i", false, "开启交互命令行")
20 |
21 | func main() {
22 | runtime.GOMAXPROCS(1)
23 | flag.Parse()
24 | global.CurrentServerID = int32(*serverID)
25 | global.CenterIP = *centerIP
26 |
27 | if global.CurrentServerID == -1 {
28 | log.Fatalln("必须使用参数(-id ?)指定本服务器ID")
29 | } else if global.CurrentServerID > global.SERVER_ID_MAX || global.CurrentServerID < 0 {
30 | log.Fatalln("服务器ID范围0~999")
31 | }
32 |
33 | logger.Setup()
34 |
35 | profiler.Start()
36 |
37 | startup.Run()
38 |
39 | if *interactive {
40 | go cli.Run()
41 | }
42 |
43 | finalize.Wait()
44 |
45 | logger.Info(fmt.Sprintf("%d-%s Shut Down!", global.CurrentServerID, global.CurrentServerType))
46 | }
47 |
--------------------------------------------------------------------------------
/src/common/dbobj/dbobj.go:
--------------------------------------------------------------------------------
1 | package dbobj
2 |
3 | import (
4 | "INServer/src/common/logger"
5 | "INServer/src/proto/etc"
6 | "database/sql"
7 | "fmt"
8 | "time"
9 |
10 | _ "github.com/go-sql-driver/mysql"
11 | )
12 |
13 | type (
14 | DBObject struct {
15 | config *etc.Database
16 | database *sql.DB
17 | }
18 | )
19 |
20 | func New() *DBObject {
21 | d := new(DBObject)
22 | return d
23 | }
24 |
25 | func (d *DBObject) Open(config *etc.Database, dbname string) {
26 | dsn := fmt.Sprintf("%s:%s@%s(%s:%d)/%s", config.UserName, config.Password, "tcp", config.IP, 3306, dbname)
27 | database, err := sql.Open("mysql", dsn)
28 | if err != nil {
29 | logger.Fatal(err)
30 | }
31 | database.SetConnMaxLifetime(time.Duration(config.ConnMaxLifetime) * time.Second)
32 | database.SetMaxOpenConns(int(config.MaxOpenConns))
33 | database.SetMaxIdleConns(int(config.MaxIdleConns))
34 | d.config = config
35 | d.database = database
36 | }
37 |
38 | func (d *DBObject) Close() {
39 | err := d.database.Close()
40 | if err != nil {
41 | logger.Debug(err)
42 | }
43 | }
44 |
45 | func (d *DBObject) DB() *sql.DB {
46 | return d.database
47 | }
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 iNeverSleeeeep
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/proto/etc/etc.zones.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: etc.zones.proto
3 |
4 | package etc
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *Zone) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *Zone) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
28 | // MarshalJSON implements json.Marshaler
29 | func (msg *ZoneList) MarshalJSON() ([]byte, error) {
30 | var buf bytes.Buffer
31 | err := (&jsonpb.Marshaler{
32 | EnumsAsInts: false,
33 | EmitDefaults: false,
34 | OrigName: false,
35 | }).Marshal(&buf, msg)
36 | return buf.Bytes(), err
37 | }
38 |
39 | // UnmarshalJSON implements json.Unmarshaler
40 | func (msg *ZoneList) UnmarshalJSON(b []byte) error {
41 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
42 | }
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/iNeverSleeeeep/INServer)
2 |
3 | # INServer
4 |
5 | #### 介绍
6 | 基于Golang的分布式MMO游戏服务器,目标是只在逻辑上区分游戏区,单游戏区没有承载上限。
7 |
8 | ### 初始化
9 | protobuf环境初始化
10 | ```
11 | go get github.com/gogo/protobuf/protoc-gen-gofast
12 | go get github.com/gogo/protobuf/proto
13 | go get github.com/gogo/protobuf/jsonpb
14 | go get github.com/gogo/protobuf/protoc-gen-gogo
15 | go get github.com/gogo/protobuf/gogoproto
16 | go get github.com/mitchellh/protoc-gen-go-json
17 | go get github.com/divan/expvarmon
18 | ```
19 |
20 | [一些原始想法](/MIND.md)
21 | [一些流程图](/doc/README.md)
22 |
23 | 目前版本存在几个核心问题没有解决,这些问题直接影响了服务器的可用性和易用性。
24 | 1. 服务器如何支持乱序启动,如何支持服务器宕机重开后恢复各个服务器的状态,服务器的关机流程。
25 | 2. **服务器中有几种大的类型的消息,他们的流向应该是如何,消息如何从一个起点到达终点。这个问题不解决,目前实现玩家移动的时候,整体的逻辑是混乱的,就算做出来了,以后也会越来越乱。**
26 | 3. 每个服务器应该保存玩家/角色的哪些数据,数据发生变化时的同步如何进行。
27 |
28 | 根据以上的问题,接下来顺序完成的功能
29 | 1. 完成整个服务器群的生命周期整理,清晰的开服关服流程,服务器重启流程。(done)
30 | 2. 玩家数据分布整理,玩家的哪些数据需要存储在哪些服务器。
31 | 3. 增加月台服务器 承接玩家进入游戏但是没有分到逻辑服务器的状态。(done)
32 | 4. 整理清楚玩家和角色的概念,登录流程走完之后,一切都是角色,不应该有玩家了。完成一个玩家的生命周期整理,进入,退出游戏流程与关服时保存流程。
33 | 5. 消息类别整理,不同类别的消息的在服务器之间如何流动的流程整理。
34 | 6. 完成玩家的移动和切地图逻辑。
35 |
--------------------------------------------------------------------------------
/src/cli/cli.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "bufio"
6 | "fmt"
7 | "net/http"
8 | "os"
9 | "strings"
10 | )
11 |
12 | // Run 启动交互命令行
13 | func Run() {
14 | reader := bufio.NewReader(os.Stdin)
15 |
16 | http.HandleFunc("/cli", handleHTTPCli)
17 | go http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", 8000+global.CurrentServerID), nil)
18 | for {
19 | fmt.Print("$ ")
20 | cmdString, err := reader.ReadString('\n')
21 | if err != nil {
22 | fmt.Fprintln(os.Stderr, err)
23 | }
24 | err = runCommand(cmdString)
25 | if err != nil {
26 | fmt.Fprintln(os.Stderr, err)
27 | }
28 | }
29 | }
30 |
31 | func handleHTTPCli(w http.ResponseWriter, r *http.Request) {
32 | err := runCommand(r.FormValue("cmd"))
33 | if err != nil {
34 | w.Write([]byte(fmt.Sprintf("%s", err)))
35 | } else {
36 | w.Write([]byte("Success"))
37 | }
38 | }
39 |
40 | func runCommand(commandStr string) error {
41 | commandStr = strings.TrimSuffix(commandStr, "\n")
42 | arrCommandStr := strings.Fields(commandStr)
43 | switch arrCommandStr[0] {
44 | case "exit":
45 | global.Exit <- true
46 | break
47 | case "ping":
48 | fmt.Println("pong")
49 | break
50 | }
51 | return nil
52 | }
53 |
--------------------------------------------------------------------------------
/src/proto/data/data.entity.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: data.entity.proto
3 |
4 | package data
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *EntityRealtimeData) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *EntityRealtimeData) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
28 | // MarshalJSON implements json.Marshaler
29 | func (msg *EntityData) MarshalJSON() ([]byte, error) {
30 | var buf bytes.Buffer
31 | err := (&jsonpb.Marshaler{
32 | EnumsAsInts: false,
33 | EmitDefaults: false,
34 | OrigName: false,
35 | }).Marshal(&buf, msg)
36 | return buf.Bytes(), err
37 | }
38 |
39 | // UnmarshalJSON implements json.Unmarshaler
40 | func (msg *EntityData) UnmarshalJSON(b []byte) error {
41 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
42 | }
43 |
--------------------------------------------------------------------------------
/src/proto/data/data.gate.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: data.gate.proto
3 |
4 | package data
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *RoleSessionInfo) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *RoleSessionInfo) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
28 | // MarshalJSON implements json.Marshaler
29 | func (msg *SessionCertData) MarshalJSON() ([]byte, error) {
30 | var buf bytes.Buffer
31 | err := (&jsonpb.Marshaler{
32 | EnumsAsInts: false,
33 | EmitDefaults: false,
34 | OrigName: false,
35 | }).Marshal(&buf, msg)
36 | return buf.Bytes(), err
37 | }
38 |
39 | // UnmarshalJSON implements json.Unmarshaler
40 | func (msg *SessionCertData) UnmarshalJSON(b []byte) error {
41 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
42 | }
43 |
--------------------------------------------------------------------------------
/src/engine/extensions/vector3/vector3.go:
--------------------------------------------------------------------------------
1 | package vector3
2 |
3 | import (
4 | "INServer/src/proto/engine"
5 | "math"
6 | )
7 |
8 | // Equal 判断相等
9 | func Equal(a *engine.Vector3, b *engine.Vector3) bool {
10 | return a.X == b.X && a.Z == b.Z
11 | }
12 |
13 | // Normalize 归一化
14 | func Normalize(a *engine.Vector3) *engine.Vector3 {
15 | length := math.Sqrt(a.X*a.X + a.Y*a.Y + a.Z*a.Z)
16 | return &engine.Vector3{
17 | X: a.X / length,
18 | Y: a.Y / length,
19 | Z: a.Z / length,
20 | }
21 | }
22 |
23 | // Multiply 乘法
24 | func Multiply(a *engine.Vector3, scale float64) *engine.Vector3 {
25 | return &engine.Vector3{
26 | X: a.X * scale,
27 | Y: a.Y * scale,
28 | Z: a.Z * scale,
29 | }
30 | }
31 |
32 | // Minus 减法
33 | func Minus(a *engine.Vector3, b *engine.Vector3) *engine.Vector3 {
34 | return &engine.Vector3{
35 | X: a.X - b.X,
36 | Y: a.Y - b.Y,
37 | Z: a.Z - b.Z,
38 | }
39 | }
40 |
41 | // Add 加法
42 | func Add(a *engine.Vector3, b *engine.Vector3) *engine.Vector3 {
43 | return &engine.Vector3{
44 | X: a.X + b.X,
45 | Y: a.Y + b.Y,
46 | Z: a.Z + b.Z,
47 | }
48 | }
49 |
50 | // Dot 点积
51 | func Dot(a *engine.Vector3, b *engine.Vector3) float64 {
52 | return a.X*b.X + a.Y*b.Y + a.Z*b.Z
53 | }
54 |
--------------------------------------------------------------------------------
/src/common/profiler/profiler.go:
--------------------------------------------------------------------------------
1 | package profiler
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "expvar"
6 | "net/http"
7 | "strconv"
8 | "time"
9 | )
10 |
11 | var (
12 | messages map[uint64]int64
13 | expvarport = 13000
14 | enabled bool = false
15 | messageRT int64 = 0
16 | )
17 |
18 | func BeginSampleMessage(id uint64) {
19 | if enabled {
20 | messages[id] = time.Now().UnixNano()
21 | }
22 | }
23 |
24 | func EndSampleMessage(id uint64) {
25 | if enabled {
26 | messageRT += time.Now().UnixNano() - messages[id]
27 | delete(messages, id)
28 | }
29 | }
30 |
31 | func getRT() interface{} {
32 | rt := messageRT
33 | messageRT = 0
34 | return rt
35 | }
36 |
37 | func getServerID() interface{} {
38 | return global.CurrentServerID
39 | }
40 |
41 | func getServerType() interface{} {
42 | return global.CurrentServerType
43 | }
44 |
45 | func Start() {
46 | expvar.Publish("Message RT", expvar.Func(getRT))
47 | expvar.Publish("ServerID", expvar.Func(getServerID))
48 | expvar.Publish("ServerType", expvar.Func(getServerType))
49 | go http.ListenAndServe(":"+strconv.Itoa(expvarport+int(global.CurrentServerID)), nil)
50 | enabled = true
51 | }
52 |
53 | func init() {
54 | messages = make(map[uint64]int64)
55 | }
56 |
--------------------------------------------------------------------------------
/src/common/util/util.go:
--------------------------------------------------------------------------------
1 | package util
2 |
3 | import (
4 | "INServer/src/common/logger"
5 | "math/rand"
6 | "os"
7 | "reflect"
8 | "time"
9 | "unsafe"
10 | )
11 |
12 | // GetRandomString 取得随机字符串
13 | func GetRandomString(l int) string {
14 | str := "0123456789abcdefghijklmnopqrstuvwxyz"
15 | bytes := []byte(str)
16 | result := []byte{}
17 | r := rand.New(rand.NewSource(time.Now().UnixNano()))
18 | for i := 0; i < l; i++ {
19 | result = append(result, bytes[r.Intn(len(bytes))])
20 | }
21 | return string(result)
22 | }
23 |
24 | // SetProcessName 设置linux下进程名称
25 | func SetProcessName(name string) error {
26 | argv0str := (*reflect.StringHeader)(unsafe.Pointer(&os.Args[0]))
27 | argv0 := (*[1 << 30]byte)(unsafe.Pointer(argv0str.Data))[:argv0str.Len]
28 |
29 | n := copy(argv0, name)
30 | if n < len(argv0) {
31 | argv0[n] = 0
32 | }
33 |
34 | return nil
35 | }
36 |
37 | // Wait 等待函数返回true
38 | func Wait(f func() bool, message string, d time.Duration) {
39 | for {
40 | if f() {
41 | break
42 | }
43 | logger.Info(message)
44 | time.Sleep(d)
45 | }
46 | }
47 |
48 | // PathExists 文件或目录是否存在
49 | func PathExists(path string) bool {
50 | _, err := os.Stat(path)
51 | if err == nil {
52 | return true
53 | }
54 | return false
55 | }
56 |
--------------------------------------------------------------------------------
/src/common/global/const.go:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | const (
4 | // CenterID 中心服务器ID
5 | CenterID int32 = 0
6 |
7 | // InvalidServerID 无效服务器ID
8 | InvalidServerID int32 = -1
9 | // InvalidServer 无效服务器类型
10 | InvalidServer string = "InvalidServer"
11 |
12 | // CenterServer 中心服务器
13 | CenterServer string = "Center"
14 | // GateServer 门服务器
15 | GateServer string = "Gate"
16 | // LoginServer 登录服务器
17 | LoginServer string = "Login"
18 | // ChatServer 聊天服务器
19 | ChatServer string = "Chat"
20 | // GPSServer 定位服务器
21 | GPSServer string = "GPS"
22 | // WorldServer 世界服务器
23 | WorldServer string = "World"
24 | // DatabaseServer 数据库服务器
25 | DatabaseServer string = "Database"
26 | // WebServer Web服务器
27 | WebServer string = "Web"
28 | // BalconyServer 月台服务器
29 | BalconyServer string = "Balcony"
30 | // AIServer AI服务器
31 | AIServer string = "AI"
32 | // RobotServer 机器人服务器(压测)
33 | RobotServer string = "Robot"
34 |
35 | // ZoneStateOpen 游戏区开启
36 | ZoneStateOpen string = "Open"
37 | // ZoneStateClosed 游戏区关闭
38 | ZoneStateClosed string = "Closed"
39 |
40 | // DatabaseSchema 数据库名
41 | DatabaseSchema string = "indb"
42 |
43 | // SERVER_ID_MAX 服务器ID最大值
44 | SERVER_ID_MAX int32 = 999
45 | // CERT_KEY_LEN 客户端登录秘钥长度
46 | CERT_KEY_LEN int = 10
47 |
48 | NANO_PER_SECONE int64 = 1E9
49 | )
50 |
--------------------------------------------------------------------------------
/src/services/gate/session.go:
--------------------------------------------------------------------------------
1 | package gate
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/common/util"
6 | "INServer/src/proto/data"
7 | "net"
8 | "time"
9 |
10 | "github.com/gorilla/websocket"
11 | )
12 |
13 | const INT_MAX int = int(^uint(0) >> 1)
14 |
15 | type (
16 | session struct {
17 | conn *net.TCPConn
18 | webconn *websocket.Conn
19 | info *data.RoleSessionInfo
20 | cert *data.SessionCertData
21 | }
22 | )
23 |
24 | func newSession(conn *net.TCPConn, uuid string) *session {
25 | s := &session{
26 | conn: conn,
27 | info: &data.RoleSessionInfo{
28 | RoleUUID: uuid,
29 | Address: &data.RoleAddress{
30 | Gate: global.CurrentServerID,
31 | World: global.InvalidServerID,
32 | },
33 | State: data.SessionState_Connected,
34 | },
35 | cert: &data.SessionCertData{
36 | Key: util.GetRandomString(global.CERT_KEY_LEN),
37 | OutOfDateTime: generateCertOutOfDateTime(),
38 | },
39 | }
40 | return s
41 | }
42 |
43 | func (s *session) generateNewCertKey() {
44 | s.cert = &data.SessionCertData{
45 | Key: util.GetRandomString(global.CERT_KEY_LEN),
46 | OutOfDateTime: generateCertOutOfDateTime(),
47 | }
48 | // TODO 发送到客户端
49 | }
50 |
51 | func generateCertOutOfDateTime() int64 {
52 | return time.Now().Unix() + global.CurrentServerConfig.GateConfig.OutOfDateTimeout
53 | }
54 |
--------------------------------------------------------------------------------
/tools/genproto.sh:
--------------------------------------------------------------------------------
1 | cd ../proto
2 |
3 | # engine
4 | echo "--------- engine ---------"
5 | for file in `ls engine`
6 | do
7 | echo $file
8 | protoc --gofast_out=../../ --go-json_out=../src/proto/engine --proto_path=./engine $file
9 | done
10 |
11 | # config
12 | echo "--------- config ---------"
13 | for file in `ls config`
14 | do
15 | echo $file
16 | protoc --gofast_out=../../ --go-json_out=../src/proto/config --proto_path=./config --proto_path=./engine $file
17 | done
18 |
19 | # data
20 | echo "--------- data ---------"
21 | for file in `ls data`
22 | do
23 | echo $file
24 | protoc --gofast_out=../../ --go-json_out=../src/proto/data --proto_path=./data --proto_path=./engine $file
25 | done
26 |
27 | # msg
28 | echo "--------- msg ---------"
29 | for file in `ls msg`
30 | do
31 | echo $file
32 | protoc --gofast_out=../../ --proto_path=./msg --proto_path=./data --proto_path=./etc --proto_path=./engine --proto_path=./gogoproto --proto_path=./protobuf $file
33 | done
34 |
35 | # etc
36 | echo "--------- etc ---------"
37 | for file in `ls etc`
38 | do
39 | echo $file
40 | protoc --gofast_out=../../ --go-json_out=../src/proto/etc --proto_path=./etc --proto_path=./gogoproto --proto_path=./protobuf $file
41 | done
42 |
43 | # db
44 | echo "--------- db ---------"
45 | for file in `ls db`
46 | do
47 | echo $file
48 | protoc --gofast_out=../../ --proto_path=./db --proto_path=./gogoproto --proto_path=./protobuf $file
49 | done
50 |
--------------------------------------------------------------------------------
/proto/gogoproto/gogo.pb.golden:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go.
2 | // source: gogo.proto
3 | // DO NOT EDIT!
4 |
5 | package gogoproto
6 |
7 | import proto "github.com/gogo/protobuf/proto"
8 | import json "encoding/json"
9 | import math "math"
10 | import google_protobuf "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
11 |
12 | // Reference proto, json, and math imports to suppress error if they are not otherwise used.
13 | var _ = proto.Marshal
14 | var _ = &json.SyntaxError{}
15 | var _ = math.Inf
16 |
17 | var E_Nullable = &proto.ExtensionDesc{
18 | ExtendedType: (*google_protobuf.FieldOptions)(nil),
19 | ExtensionType: (*bool)(nil),
20 | Field: 51235,
21 | Name: "gogoproto.nullable",
22 | Tag: "varint,51235,opt,name=nullable",
23 | }
24 |
25 | var E_Embed = &proto.ExtensionDesc{
26 | ExtendedType: (*google_protobuf.FieldOptions)(nil),
27 | ExtensionType: (*bool)(nil),
28 | Field: 51236,
29 | Name: "gogoproto.embed",
30 | Tag: "varint,51236,opt,name=embed",
31 | }
32 |
33 | var E_Customtype = &proto.ExtensionDesc{
34 | ExtendedType: (*google_protobuf.FieldOptions)(nil),
35 | ExtensionType: (*string)(nil),
36 | Field: 51237,
37 | Name: "gogoproto.customtype",
38 | Tag: "bytes,51237,opt,name=customtype",
39 | }
40 |
41 | func init() {
42 | proto.RegisterExtension(E_Nullable)
43 | proto.RegisterExtension(E_Embed)
44 | proto.RegisterExtension(E_Customtype)
45 | }
46 |
--------------------------------------------------------------------------------
/proto/data/data.component.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/data";
4 |
5 | import "math.proto";
6 |
7 | enum ComponentType {
8 | Invalid = 0;
9 | Transofrm = 1;
10 | Physics = 2;
11 | Attribute = 3;
12 | Move = 4;
13 | Controller = 5;
14 | Reborn = 6;
15 | }
16 |
17 | enum ControllerType {
18 | PlayerController = 0;
19 | AIController = 1;
20 | }
21 |
22 | enum RebornType {
23 | None = 0;
24 | Auto = 1;
25 | Manual = 2;
26 | }
27 |
28 | message TransformComponent {
29 | Vector3 Position = 1;
30 | Quaternion rotation = 2;
31 | }
32 |
33 | message PhysicsComponent {
34 | double Mass = 1;
35 | Vector3 RawSpeed = 2; // 玩家操作的移动速度
36 | Vector3 PassiveSpeed = 3; // 其他外力影响的速度
37 | }
38 |
39 | message AttributeComponent {
40 | float Speed = 1;
41 | float HP = 2;
42 | float MaxHP = 3;
43 | }
44 |
45 | message MoveComponent {
46 | Vector3 Destination = 1;
47 | }
48 |
49 | message ControllerComponent {
50 | ControllerType ControllerType = 1;
51 | }
52 |
53 | message RebornComponent {
54 | int64 RebornTime = 1;
55 | RebornType RebornType = 2;
56 | Vector3 Position = 3;
57 | }
58 |
59 | message Component {
60 | ComponentType Type = 1;
61 | TransformComponent Transform = 2;
62 | PhysicsComponent Physics = 3;
63 | AttributeComponent Attribute = 4;
64 | MoveComponent Move = 5;
65 | ControllerComponent Controller = 6;
66 | RebornComponent Reborn = 7;
67 | }
--------------------------------------------------------------------------------
/src/gameplay/ecs/system/move.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "INServer/src/engine/extensions/vector3"
5 | "INServer/src/gameplay/ecs"
6 | "INServer/src/proto/data"
7 | "INServer/src/proto/engine"
8 | )
9 |
10 | type move struct {
11 | }
12 |
13 | func (m *move) Tick(dt float64, entities map[string]*ecs.Entity) {
14 | for _, entity := range entities {
15 | physics := entity.GetComponent(data.ComponentType_Physics).Physics
16 | if physics != nil {
17 | transform := entity.GetComponent(data.ComponentType_Transofrm).Transform
18 | if transform != nil {
19 | stop(dt, entity, physics, transform)
20 | step(dt, transform.Position, vector3.Add(physics.RawSpeed, physics.PassiveSpeed))
21 | }
22 | }
23 | }
24 | }
25 |
26 | func stop(dt float64, entity *ecs.Entity, physics *data.PhysicsComponent, transform *data.TransformComponent) {
27 | move := entity.GetComponent(data.ComponentType_Move).Move
28 | if move != nil {
29 | dir := vector3.Minus(move.Destination, transform.Position)
30 | // 如果前进方向和目标方向相反 则停止移动
31 | if vector3.Dot(physics.RawSpeed, dir) < 0 {
32 | physics.RawSpeed = &engine.Vector3{}
33 | transform.Position = move.Destination
34 | }
35 | } else {
36 | physics.RawSpeed = &engine.Vector3{}
37 | }
38 | }
39 |
40 | func step(dt float64, pos *engine.Vector3, speed *engine.Vector3) bool {
41 | X, Y, Z := pos.X, pos.Y, pos.Z
42 | pos.X += dt * speed.X
43 | pos.Y += dt * speed.Y
44 | pos.Z += dt * speed.Z
45 | return X != pos.X || Y != pos.Y || Z != pos.Z
46 | }
47 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
2 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
3 | github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
4 | github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
5 | github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
6 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
7 | github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
8 | github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
9 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
10 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
11 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563 h1:NIou6eNFigscvKJmsbyez16S2cIS6idossORlFtSt2E=
12 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
13 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
14 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
15 | gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo=
16 | gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
17 |
--------------------------------------------------------------------------------
/etc/servers.yaml:
--------------------------------------------------------------------------------
1 | servers:
2 | -
3 | serverid: 0
4 | servertype: Center
5 | serverconfig:
6 | -
7 | serverid: 1
8 | servertype: Gate
9 | serverconfig:
10 | gateconfig:
11 | address: 127.0.0.1
12 | port: 10999
13 | outofdatatimeout: 10
14 | webport: 10998
15 | -
16 | serverid: 2
17 | servertype: Login
18 | serverconfig:
19 | loginconfig:
20 | port: 10800
21 | webport: 10801
22 | -
23 | serverid: 3
24 | servertype: Database
25 | serverconfig:
26 | databaseconfig:
27 | database:
28 | -
29 | serverid: 4
30 | servertype: Web
31 | serverconfig:
32 | webconfig:
33 | port: 10700
34 | account: ins
35 | password: 123456
36 | -
37 | serverid: 5
38 | servertype: World
39 | serverconfig:
40 | worldconfig:
41 | fps: 100
42 | zones:
43 | - {zoneid: 0, staticmaps: [1]}
44 | - {zoneid: 1, staticmaps: [1]}
45 | -
46 | serverid: 6
47 | servertype: World
48 | serverconfig:
49 | worldconfig:
50 | fps: 100
51 | zones:
52 | - {zoneid: 1, staticmaps: [2]}
53 | - {zoneid: 2, staticmaps: [1,2]}
54 | -
55 | serverid: 7
56 | servertype: World
57 | serverconfig:
58 | worldconfig:
59 | fps: 100
60 | zones:
61 | - {zoneid: 3, staticmaps: [1,2]}
62 | - {zoneid: 4, staticmaps: [1,2]}
63 | -
64 | serverid: 8
65 | servertype: GPS
66 | serverconfig:
67 | -
68 | serverid: 9
69 | servertype: Balcony
70 | serverconfig:
--------------------------------------------------------------------------------
/src/lifetime/finalize/finalize.go:
--------------------------------------------------------------------------------
1 | package finalize
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/common/util"
6 | "INServer/src/services/cluster"
7 | "INServer/src/services/world"
8 | "os"
9 | "os/signal"
10 | "syscall"
11 | "time"
12 | )
13 |
14 | // Wait 等待结束
15 | func Wait() {
16 | global.Exit = make(chan bool)
17 | sigs := make(chan os.Signal, 1)
18 | signal.Notify(sigs, syscall.SIGINT)
19 |
20 | for {
21 | stopped := false
22 | select {
23 | case sig := <-sigs:
24 | if sig.String() == "interrupt" && stopped == false {
25 | stopped = true
26 | stopNode()
27 | }
28 | break
29 | case exit := <-global.Exit:
30 | if exit == true && stopped == false {
31 | stopped = true
32 | stopNode()
33 | }
34 | }
35 | if stopped {
36 | break
37 | }
38 | time.Sleep(time.Millisecond * 10)
39 | }
40 | }
41 |
42 | func stopNode() {
43 | global.PendingExit = true
44 | stopServer()
45 | }
46 |
47 | // 关服流程
48 | // step1 登录服务器 门服务器 等
49 | // step2 世界服务器
50 | // step3 数据库服务器
51 | // step4 中心服务器
52 | func stopServer() {
53 | switch global.CurrentServerType {
54 | case global.WorldServer:
55 | util.Wait(func() bool {
56 | return len(cluster.RunningGates()) == 0
57 | }, "等待门服务器关服完成...", time.Second)
58 | world.Instance.Stop()
59 | break
60 | case global.DatabaseServer:
61 | util.Wait(func() bool {
62 | return cluster.RunningCount() == 2
63 | }, "等待其他服务器关服完成...", time.Second)
64 | break
65 | case global.CenterServer:
66 | util.Wait(func() bool {
67 | return cluster.RunningCount() == 1
68 | }, "等待其他服务器关服完成...", time.Second)
69 | break
70 | }
71 | }
72 |
73 | func init() {
74 | global.PendingExit = false
75 | }
76 |
--------------------------------------------------------------------------------
/proto/etc/etc.servers.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/etc";
4 |
5 | import "etc.database.proto";
6 |
7 | // 服务器的各种配置
8 |
9 | message GateConfig {
10 | int32 Port = 1; // 监听客户端连接的端口
11 | int64 OutOfDateTimeout = 2; // 断开连接后Session删除的Timeout
12 | string Address = 3; // IP地址 因为阿里云没有办法取得公网IP所以只能配置
13 | int32 WebPort = 4; // 客户端websocket端口
14 | }
15 |
16 | message LoginConfig {
17 | int32 Port = 1; // 监听客户端连接的端口
18 | Database Database = 2; // 账号数据库
19 | int32 WebPort = 3; // 客户端websocket端口
20 | }
21 |
22 | message ChatConfig {
23 |
24 | }
25 |
26 | message DatabaseConfig {
27 | Database Database = 1;
28 | }
29 |
30 | message WebConfig {
31 | int32 Port = 1; // 监听Http请求的端口
32 | string Account = 2; // 账号
33 | string Password = 3; // 密码
34 | }
35 |
36 | message ZoneWorld {
37 | int32 ZoneID = 1; // 游戏区ID
38 | repeated int32 StaticMaps = 2; // 世界地图列表
39 | }
40 |
41 | message WorldConfig {
42 | repeated ZoneWorld Zones = 1; // 游戏区配置
43 | int32 FPS = 2; // 帧率
44 | }
45 |
46 | message AIConfig {
47 |
48 | }
49 |
50 | message RobotConfig {
51 |
52 | }
53 |
54 | message ServerConfig {
55 | GateConfig GateConfig = 1; // 门服务器配置
56 | LoginConfig LoginConfig = 2; // 登录服务器
57 | ChatConfig ChatConfig = 3; // 聊天服务器
58 | DatabaseConfig DatabaseConfig = 4; // 数据库服务器
59 | WebConfig WebConfig = 5; // Http服务器
60 | WorldConfig WorldConfig = 6; // 世界服务器
61 | AIConfig AIConfig = 7; // AI服务器
62 | RobotConfig RobotConfig = 8; // 机器人服务器
63 | }
64 |
65 | message Server {
66 | int32 ServerID = 1;
67 | string ServerType = 2;
68 | ServerConfig ServerConfig = 3;
69 | string Describe = 4;
70 | }
71 |
72 | message ServerList {
73 | repeated Server Servers = 1;
74 | }
--------------------------------------------------------------------------------
/proto/gogoproto/Makefile:
--------------------------------------------------------------------------------
1 | # Protocol Buffers for Go with Gadgets
2 | #
3 | # Copyright (c) 2013, The GoGo Authors. All rights reserved.
4 | # http://github.com/gogo/protobuf
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions are
8 | # met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following disclaimer
14 | # in the documentation and/or other materials provided with the
15 | # distribution.
16 | #
17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | regenerate:
30 | go install github.com/gogo/protobuf/protoc-gen-gogo
31 | protoc --gogo_out=Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor:../../../../ --proto_path=../../../../:../protobuf/:. *.proto
32 |
33 | restore:
34 | cp gogo.pb.golden gogo.pb.go
35 |
36 | preserve:
37 | cp gogo.pb.go gogo.pb.golden
38 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // 使用 IntelliSense 了解相关属性。
3 | // 悬停以查看现有属性的描述。
4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 |
8 | {
9 | "name": "Launch Center",
10 | "type": "go",
11 | "request": "launch",
12 | "mode": "debug",
13 | "program": "${workspaceFolder}",
14 | "env": {},
15 | "args": ["-id", "0"]
16 | },
17 | {
18 | "name": "Launch Gate",
19 | "type": "go",
20 | "request": "launch",
21 | "mode": "debug",
22 | "program": "${workspaceFolder}",
23 | "env": {},
24 | "args": ["-id", "1"]
25 | },
26 | {
27 | "name": "Launch Login",
28 | "type": "go",
29 | "request": "launch",
30 | "mode": "debug",
31 | "program": "${workspaceFolder}",
32 | "env": {},
33 | "args": ["-id", "2"]
34 | },
35 | {
36 | "name": "Launch Database",
37 | "type": "go",
38 | "request": "launch",
39 | "mode": "debug",
40 | "program": "${workspaceFolder}",
41 | "env": {},
42 | "args": ["-id", "3"]
43 | },
44 | {
45 | "name": "Launch Web",
46 | "type": "go",
47 | "request": "launch",
48 | "mode": "debug",
49 | "program": "${workspaceFolder}",
50 | "env": {},
51 | "args": ["-id", "4"]
52 | },
53 | {
54 | "name": "Launch World5",
55 | "type": "go",
56 | "request": "launch",
57 | "mode": "debug",
58 | "program": "${workspaceFolder}",
59 | "env": {},
60 | "args": ["-id", "5", "-i", "true"]
61 | },
62 | ]
63 | }
--------------------------------------------------------------------------------
/src/gameplay/matrix/matrix.go:
--------------------------------------------------------------------------------
1 | package matrix
2 |
3 | import (
4 | "INServer/src/common/uuid"
5 | "INServer/src/gameplay/ecs"
6 | "INServer/src/gameplay/gamemap"
7 | "INServer/src/proto/data"
8 | "INServer/src/proto/engine"
9 | )
10 |
11 | // Matrix 控制地图内实体的产生消亡
12 | type Matrix struct {
13 | }
14 |
15 | // New 构造Matrix
16 | func New() *Matrix {
17 | m := new(Matrix)
18 | return m
19 | }
20 |
21 | // OnGamemapCreate 地图创建时的初始化
22 | func (m *Matrix) OnGamemapCreate(gameMap *gamemap.Map) {
23 | if len(gameMap.MapData().Entities) == 0 {
24 | for _, scene := range gameMap.Scenes() {
25 | for x := scene.Width / -2; x < scene.Width/2; x = x + 10 {
26 | for z := scene.Height / -2; z < scene.Height/2; z = z + 10 {
27 | entityUUID := uuid.New()
28 | components := ecs.InitComponents(data.EntityType_MonsterEntity)
29 | components[data.ComponentType_Transofrm].Transform.Position = &engine.Vector3{
30 | X: float64(x),
31 | Y: 0,
32 | Z: float64(z),
33 | }
34 | entityData := &data.EntityData{
35 | EntityUUID: entityUUID,
36 | Components: components,
37 | RealTimeData: &data.EntityRealtimeData{
38 | LastStaticMapUUID: gameMap.MapData().MapUUID,
39 | CurrentMapUUID: gameMap.MapData().MapUUID,
40 | },
41 | }
42 | entity := ecs.NewEntity(entityData, data.EntityType_MonsterEntity)
43 | if entity != nil {
44 | gameMap.EntityEnter(entity.UUID(), entity)
45 | }
46 | }
47 | }
48 | }
49 | } else {
50 | for _, entityData := range gameMap.MapData().Entities {
51 | entity := ecs.NewEntity(entityData, data.EntityType_MonsterEntity)
52 | if entity != nil {
53 | gameMap.EntityEnter(entity.UUID(), entity)
54 | }
55 | }
56 | }
57 | }
58 |
59 | // OnGamemapDestroy 地图销毁时的回收
60 | func (m *Matrix) OnGamemapDestroy(gameMap *gamemap.Map) {
61 |
62 | }
63 |
64 | // TickGamemap Tick
65 | func (m *Matrix) TickGamemap(gameMap *gamemap.Map) {
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/proto/msg/command.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "INServer/src/proto/msg";
4 |
5 | enum CMD {
6 | KEEP_ALIVE = 0; // any -> center
7 | RESP = 1;
8 | GATE = 2; // client -> gate -> any
9 | CONNECT_GATE_REQ = 6; // client -> gate
10 | SESSION_CERT_NTF = 7; // gate -> client
11 | CCHAT_CHAT = 8; // client -> chat
12 | DISPATCH = 9; // any -> dispatcher
13 | LD_CREATE_PLAYER_REQ = 10; // login -> database
14 | GD_LOAD_PLAYER_REQ = 11; // gate -> database
15 | GD_RELEASE_PLAYER_NTF = 12; // gate -> database
16 | GD_CREATE_ROLE_REQ = 13; // gate -> database
17 | GD_LOAD_ROLE_REQ = 14; // gate -> database
18 | RELOAD_ETC_REQ = 15; // web -> center
19 | MOVE_NTF = 17; // world -> client
20 | NEAR_ENTITIES_NTF = 18; // world -> client
21 | ENTITY_DATA_REQ = 19; // client -> world
22 | ROLE_ENTER = 20; // client -> gate; any -> world
23 | UPDATE_ROLE_ADDRESS_NTF = 21; // any -> gps
24 | REMOVE_ROLE_ADDRESS_NTF = 22; // gate -> gps
25 | UPDATE_MAP_ADDRESS_NTF = 23; // world -> gps
26 | REMOVE_MAP_ADDRESS_NTF = 24; // world -> gps
27 | GET_MAP_ADDRESS_REQ = 25; // database -> gps
28 | LOAD_STATIC_MAP_REQ = 26; // world -> database
29 | LOAD_DYNAMIC_MAP_REQ = 27; // world -> database
30 | UPDATE_STATIC_MAP_UUID_NTF = 28; // world -> gps
31 | GET_STATIC_MAP_UUID_REQ = 29; // any -> gps
32 | SAVE_STATIC_MAP_REQ = 30; // any -> database
33 | SAVE_DYNAMIC_MAP_REQ = 31; // any -> database
34 | SAVE_ROLE_REQ = 32; // any -> database
35 | GET_MAP_ID = 33; // gate -> world
36 | MOVE_INF = 34; // client -> world
37 | FORWARD_CLIENT_MESSAGE = 35; // any -> gate -> client
38 | STOP_MOVE_INF = 36; // client -> world
39 |
40 | NODE_START_NTF = 1000; // any -> center
41 | ETC_SYNC_NTF = 1001; // center -> any
42 | NODES_INFO_NTF = 1002; // any <-> center
43 | RESET_CONNECTION_NTF = 1003; // center -> any
44 | ROLE_LEAVE_REQ = 1004; // gate -> any
45 | }
--------------------------------------------------------------------------------
/src/services/innet/retry.go:
--------------------------------------------------------------------------------
1 | package innet
2 |
3 | import (
4 | "INServer/src/proto/msg"
5 | "net"
6 | "time"
7 | )
8 |
9 | type (
10 | packageCache struct {
11 | addr *net.UDPAddr
12 | packages []*msg.Package
13 | retryTime int64
14 | toServerID int32
15 | }
16 |
17 | retry struct {
18 | innet *INNet
19 | cachedPackages map[uint64]*packageCache
20 | stoped bool
21 | }
22 | )
23 |
24 | func newRetry(innet *INNet) *retry {
25 | r := new(retry)
26 | r.innet = innet
27 | r.cachedPackages = make(map[uint64]*packageCache)
28 | r.startTickRetry()
29 | return r
30 | }
31 |
32 | func (r *retry) addPackagesCache(packageID uint64, cache *packageCache) {
33 | r.cachedPackages[packageID] = cache
34 | }
35 |
36 | func (r *retry) resetServer(serverID int32) {
37 | packageIDList := make([]uint64, 0)
38 | for packageID, cache := range r.cachedPackages {
39 | if cache.toServerID == serverID {
40 | packageIDList = append(packageIDList, packageID)
41 | }
42 | }
43 | for _, packageID := range packageIDList {
44 | delete(r.cachedPackages, packageID)
45 | }
46 | }
47 |
48 | func (r *retry) handlePackageReceive(receivedPkg *msg.Package) {
49 | if cache, ok := r.cachedPackages[receivedPkg.UniqueID]; ok {
50 | for index, pkg := range cache.packages {
51 | if pkg.UniqueID == receivedPkg.UniqueID {
52 | cache.packages = append(cache.packages[:index], cache.packages[index+1:]...)
53 | if len(cache.packages) == 0 {
54 | delete(r.cachedPackages, receivedPkg.UniqueID)
55 | }
56 | break
57 | }
58 | }
59 | }
60 | }
61 |
62 | func (r *retry) startTickRetry() {
63 | r.stoped = false
64 | go func() {
65 | for r.stoped == false {
66 | time.Sleep(time.Millisecond * 30)
67 | current := time.Now().UnixNano()
68 | for _, cache := range r.cachedPackages {
69 | retryTime := cache.retryTime
70 | if retryTime < current {
71 | r.innet.sender.sendPackages(cache.addr, cache.packages)
72 | cache.retryTime = current + timeout
73 | }
74 | }
75 | }
76 | }()
77 | }
78 |
--------------------------------------------------------------------------------
/src/services/cluster/cluster.go:
--------------------------------------------------------------------------------
1 | package cluster
2 |
3 | import (
4 | "INServer/src/proto/msg"
5 | "INServer/src/services/etcmgr"
6 | )
7 |
8 | var (
9 | nodes []*msg.Node
10 | )
11 |
12 | // SetNodes 设置集群信息
13 | func SetNodes(nodesArray []*msg.Node) {
14 | for serverID, node := range nodesArray {
15 | SetNode(int32(serverID), node)
16 | }
17 | RefreshRunning()
18 | RefreshRunningZones()
19 | }
20 |
21 | // SetNode 设置单个节点信息
22 | func SetNode(serverID int32, node *msg.Node) {
23 | for len(nodes) < int(serverID+1) {
24 | nodes = append(nodes, &msg.Node{})
25 | }
26 | if len(node.NodeAddress) > 0 {
27 | nodes[serverID].NodeAddress = node.NodeAddress
28 | }
29 | if node.NodeState == msg.NodeState_Unset {
30 | return
31 | }
32 | if node.NodeState == msg.NodeState_Ready && nodes[serverID].NodeState == msg.NodeState_Running {
33 | // 因为消息乱序处理的问题,有可能先处理runining后处理ready 这个时候状态不要切换错了
34 | return
35 | }
36 | nodes[serverID].NodeState = node.NodeState
37 | }
38 |
39 | // GetNode 取得单个节点信息
40 | func GetNode(serverID int32) *msg.Node {
41 | if len(nodes) < int(serverID+1) {
42 | return &msg.Node{}
43 | }
44 | if nodes[serverID] != nil {
45 | return nodes[serverID]
46 | }
47 | return &msg.Node{}
48 | }
49 |
50 | // GetNodeState 取得节点状态
51 | func GetNodeState(serverID int32) msg.NodeState {
52 | if len(nodes) < int(serverID+1) {
53 | return msg.NodeState_Unset
54 | }
55 | if nodes[serverID] == nil {
56 | return msg.NodeState_Unset
57 | }
58 | return nodes[serverID].NodeState
59 | }
60 |
61 | // GetNodes 取得集群信息
62 | func GetNodes() []*msg.Node {
63 | return nodes
64 | }
65 |
66 | // GetGatePublicAddress 网关公网地址
67 | func GetGatePublicAddress(serverID int32) (string, int, int) {
68 | servers := etcmgr.Instance.Servers()
69 | ip := servers[int(serverID)].ServerConfig.GateConfig.Address
70 | port := int(servers[int(serverID)].ServerConfig.GateConfig.Port)
71 | webport := int(servers[int(serverID)].ServerConfig.GateConfig.WebPort)
72 | return ip, port, webport
73 | }
74 |
75 | func init() {
76 | nodes = make([]*msg.Node, 0)
77 | }
78 |
--------------------------------------------------------------------------------
/src/dao/dao.player.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "INServer/src/common/dbobj"
5 | "INServer/src/common/logger"
6 | "INServer/src/proto/db"
7 | )
8 |
9 | func AccountQuery(DB *dbobj.DBObject, username string) (*db.DBAccount, error) {
10 | account := new(db.DBAccount)
11 | row := DB.DB().QueryRow("select * from accounts where Name=?", username)
12 | if err := row.Scan(&account.Name, &account.PasswordHash, &account.PlayerUUID); err != nil {
13 | logger.Debug(err)
14 | return nil, err
15 | }
16 | return account, nil
17 | }
18 |
19 | func AccountInsert(DB *dbobj.DBObject, account *db.DBAccount) error {
20 | _, err := DB.DB().Exec("insert INTO accounts(Name,PasswordHash,PlayerUUID) values(?,?,?)", account.Name, account.PasswordHash, account.PlayerUUID)
21 | if err != nil {
22 | logger.Debug(err)
23 | return err
24 | }
25 | return nil
26 | }
27 |
28 | func AccountUpdate(DB *dbobj.DBObject, account *db.DBAccount) error {
29 | _, err := DB.DB().Exec("UPDATE accounts set PasswordHash=? PlayerUUID=? where Name=?", account.PasswordHash, account.PlayerUUID, account.Name)
30 | if err != nil {
31 | logger.Debug(err)
32 | return err
33 | }
34 | return nil
35 | }
36 |
37 | func PlayerQuery(DB *dbobj.DBObject, uuid string) (*db.DBPlayer, error) {
38 | player := new(db.DBPlayer)
39 | row := DB.DB().QueryRow("select * from players where UUID=?", uuid)
40 | if err := row.Scan(&player.UUID, &player.SerializedData); err != nil {
41 | logger.Debug(err)
42 | return nil, err
43 | }
44 | return player, nil
45 | }
46 |
47 | func PlayerInsert(DB *dbobj.DBObject, player *db.DBPlayer) error {
48 | _, err := DB.DB().Exec("insert INTO players(UUID,SerializedData) values(?,?)", player.UUID, player.SerializedData)
49 | if err != nil {
50 | logger.Debug(err)
51 | return err
52 | }
53 | return nil
54 | }
55 |
56 | func PlayerUpdate(DB *dbobj.DBObject, player *db.DBPlayer) error {
57 | _, err := DB.DB().Exec("UPDATE players set SerializedData=? where UUID=?", player.SerializedData, player.UUID)
58 | if err != nil {
59 | logger.Debug(err)
60 | return err
61 | }
62 | return nil
63 | }
64 |
--------------------------------------------------------------------------------
/src/proto/engine/math.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: math.proto
3 |
4 | package engine
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *Vector2) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *Vector2) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
28 | // MarshalJSON implements json.Marshaler
29 | func (msg *Vector3) MarshalJSON() ([]byte, error) {
30 | var buf bytes.Buffer
31 | err := (&jsonpb.Marshaler{
32 | EnumsAsInts: false,
33 | EmitDefaults: false,
34 | OrigName: false,
35 | }).Marshal(&buf, msg)
36 | return buf.Bytes(), err
37 | }
38 |
39 | // UnmarshalJSON implements json.Unmarshaler
40 | func (msg *Vector3) UnmarshalJSON(b []byte) error {
41 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
42 | }
43 |
44 | // MarshalJSON implements json.Marshaler
45 | func (msg *Rect) MarshalJSON() ([]byte, error) {
46 | var buf bytes.Buffer
47 | err := (&jsonpb.Marshaler{
48 | EnumsAsInts: false,
49 | EmitDefaults: false,
50 | OrigName: false,
51 | }).Marshal(&buf, msg)
52 | return buf.Bytes(), err
53 | }
54 |
55 | // UnmarshalJSON implements json.Unmarshaler
56 | func (msg *Rect) UnmarshalJSON(b []byte) error {
57 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
58 | }
59 |
60 | // MarshalJSON implements json.Marshaler
61 | func (msg *Quaternion) MarshalJSON() ([]byte, error) {
62 | var buf bytes.Buffer
63 | err := (&jsonpb.Marshaler{
64 | EnumsAsInts: false,
65 | EmitDefaults: false,
66 | OrigName: false,
67 | }).Marshal(&buf, msg)
68 | return buf.Bytes(), err
69 | }
70 |
71 | // UnmarshalJSON implements json.Unmarshaler
72 | func (msg *Quaternion) UnmarshalJSON(b []byte) error {
73 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
74 | }
75 |
--------------------------------------------------------------------------------
/src/gameplay/ecs/controller.go:
--------------------------------------------------------------------------------
1 | package ecs
2 |
3 | import (
4 | "INServer/src/proto/data"
5 | "INServer/src/proto/msg"
6 | "INServer/src/services/node"
7 |
8 | "github.com/gogo/protobuf/proto"
9 | )
10 |
11 | type (
12 | // Controller 全部Controller的接口
13 | Controller interface {
14 | OnOtherMove(entity *Entity, ntf *msg.MoveNTF)
15 | OnNearEntities([]*msg.NearEntity)
16 | }
17 |
18 | // DummyController 占位 什么事情也不做
19 | DummyController struct {
20 | entity *Entity
21 | }
22 | // AIController 服务器控制
23 | AIController struct {
24 | entity *Entity
25 | }
26 | // PlayerController 玩家控制
27 | PlayerController struct {
28 | entity *Entity
29 | }
30 | )
31 |
32 | func initController(entity *Entity) {
33 | switch entity.entityType {
34 | case data.EntityType_MonsterEntity, data.EntityType_NPCEntity:
35 | entity.controller = &AIController{entity}
36 | case data.EntityType_RoleEntity:
37 | entity.controller = &PlayerController{entity}
38 | }
39 | if entity.controller == nil {
40 | entity.controller = &DummyController{entity}
41 | }
42 | }
43 |
44 | func (c *DummyController) OnOtherMove(entity *Entity, ntf *msg.MoveNTF) {
45 |
46 | }
47 | func (c *DummyController) OnNearEntities([]*msg.NearEntity) {
48 |
49 | }
50 | func (c *AIController) OnOtherMove(entity *Entity, ntf *msg.MoveNTF) {
51 |
52 | }
53 | func (c *AIController) OnNearEntities([]*msg.NearEntity) {
54 |
55 | }
56 | func (c *PlayerController) OnOtherMove(entity *Entity, ntf *msg.MoveNTF) {
57 | c.sendMessage(msg.CMD_MOVE_NTF, ntf)
58 | }
59 | func (c *PlayerController) OnNearEntities(items []*msg.NearEntity) {
60 | if len(items) > 1 {
61 | nearEntitiesNTF := &msg.NearEntitiesNTF{
62 | Entities: items,
63 | }
64 | node.Net.NotifyClient(msg.CMD_NEAR_ENTITIES_NTF, nearEntitiesNTF, c.entity.UUID())
65 | }
66 | }
67 |
68 | func (c *PlayerController) sendMessage(command msg.CMD, message proto.Message) {
69 | //gate := world.Instance.RoleGate(c.entity.UUID())
70 | //if gate != global.InvalidServerID {
71 | // if buffer, err := proto.Marshal(message); err == nil {
72 | // forward := &msg.ForwardPlayerMessage{}
73 | // }
74 | // node.Net.NotifyServer(msg.CMD_MOVE_NTF, message, gate)
75 | //}
76 | }
77 |
--------------------------------------------------------------------------------
/src/dao/dao.role.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "INServer/src/common/dbobj"
5 | "INServer/src/common/logger"
6 | "INServer/src/proto/db"
7 | )
8 |
9 | func AllRoleSummaryDataQuery(DB *dbobj.DBObject) []*db.DBRole {
10 | rows, err := DB.DB().Query("select UUID, SummaryData from roles")
11 | if err != nil {
12 | logger.Fatal(err)
13 | }
14 | roles := []*db.DBRole{}
15 | for rows.Next() {
16 | role := &db.DBRole{}
17 | rows.Scan(&role.UUID, &role.SummaryData)
18 | roles = append(roles, role)
19 | }
20 | return roles
21 | }
22 |
23 | func RoleOnlineDataQuery(DB *dbobj.DBObject, uuid string) ([]byte, error) {
24 | onlineData := make([]byte, 0)
25 | row := DB.DB().QueryRow("select OnlineData from roles where UUID=?", uuid)
26 | if err := row.Scan(&onlineData); err != nil {
27 | logger.Debug(err)
28 | return nil, err
29 | }
30 | return onlineData, nil
31 | }
32 |
33 | func RoleInsert(DB *dbobj.DBObject, role *db.DBRole) error {
34 | _, err := DB.DB().Exec("insert INTO roles(UUID,SummaryData,OnlineData) values(?,?,?)", role.UUID, role.SummaryData, role.OnlineData)
35 | if err != nil {
36 | logger.Debug(err)
37 | return err
38 | }
39 | return nil
40 | }
41 |
42 | func RoleUpdate(DB *dbobj.DBObject, role *db.DBRole) error {
43 | _, err := DB.DB().Exec("UPDATE roles set SummaryData=? OnlineData=? where UUID=?", role.SummaryData, role.OnlineData, role.UUID)
44 | if err != nil {
45 | logger.Debug(err)
46 | return err
47 | }
48 | return nil
49 | }
50 |
51 | func BulkRoleUpdate(DB *dbobj.DBObject, roles []*db.DBRole) error {
52 | tx, err := DB.DB().Begin()
53 | if err != nil {
54 | logger.Error(err)
55 | return err
56 | }
57 | //stmt, err := tx.Prepare(`UPDATE roles set SummaryData=? OnlineData=? where UUID=?`)
58 | stmt, err := tx.Prepare(`REPLACE into roles (UUID, SummaryData, OnlineData) values(?,?,?)`)
59 | if err != nil {
60 | logger.Error(err)
61 | return err
62 | }
63 | for _, role := range roles {
64 | _, err := stmt.Exec(role.UUID, role.SummaryData, role.OnlineData)
65 | if err != nil {
66 | logger.Error(err)
67 | return err
68 | }
69 | }
70 | err = tx.Commit()
71 | if err != nil {
72 | logger.Error(err)
73 | }
74 | return err
75 | }
76 |
--------------------------------------------------------------------------------
/src/common/logger/logger.go:
--------------------------------------------------------------------------------
1 | package logger
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "fmt"
6 | "log"
7 | "os"
8 | "runtime/debug"
9 | "strings"
10 | "time"
11 | )
12 |
13 | const (
14 | timeFormat string = "2006-01-02T15:04:05.999999+08:00"
15 | )
16 |
17 | var (
18 | day = time.Now().Day()
19 | logHandler *log.Logger
20 | id string
21 |
22 | skipstrings = []string{"/stack.go", "debug.Stack", "/protect", "panic", "logger"}
23 |
24 | // IsDebug 是否是调试模式运行的
25 | IsDebug = strings.Contains(os.Args[0], "__debug_bin")
26 | )
27 |
28 | // Setup 日志初始化
29 | func Setup() {
30 | wd, err := os.Getwd()
31 | if err != nil {
32 | log.Fatalln(err)
33 | }
34 | now := time.Now()
35 | file := wd + "/log/" + fmt.Sprintf("%d-%d%02d%02d.log", int(global.CurrentServerID), now.Year(), now.Month(), now.Day())
36 |
37 | logFile, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)
38 | if err != nil {
39 | log.Fatalln(err)
40 | }
41 | logHandler = log.New(logFile, "", 0)
42 | }
43 |
44 | func format(level string, v ...interface{}) string {
45 | now := time.Now().Format(timeFormat)
46 | return fmt.Sprintf("{\"level\":\"%s\", \"@timestamp\":\"%s\", \"message\":\"%s\", \"server\": {\"type\":\"%s\", \"id\":\"%d\"}}", level, now, fmt.Sprint(v...), global.CurrentServerType, global.CurrentServerID)
47 | }
48 |
49 | // Debug 调试日志
50 | func Debug(v ...interface{}) {
51 | log.Println(v...)
52 | logHandler.Println(format("debug", v...))
53 | PrintStack()
54 | }
55 |
56 | // Info 普通信息日志
57 | func Info(v ...interface{}) {
58 | log.Println(v...)
59 | logHandler.Println(format("info", v...))
60 | }
61 |
62 | // Error 错误信息日志
63 | func Error(v ...interface{}) {
64 | log.Println(v...)
65 | logHandler.Println(format("error", v...))
66 | PrintStack()
67 | }
68 |
69 | // Fatal 严重错误日志
70 | func Fatal(v ...interface{}) {
71 | log.Println(v...)
72 | logHandler.Println(format("fatal", v...))
73 | PrintStack()
74 | }
75 |
76 | // PrintStack 输出调用栈
77 | func PrintStack() {
78 | stack := strings.Split(string(debug.Stack()), "\n")
79 | logstr := ""
80 | for _, str := range stack {
81 | skip := false
82 | for _, skipstr := range skipstrings {
83 | if strings.Contains(str, skipstr) {
84 | skip = true
85 | break
86 | }
87 | }
88 | if skip == false {
89 | logstr = logstr + str
90 | }
91 | }
92 | log.Println(logstr)
93 | logHandler.Println(format("stack", logstr))
94 | }
95 |
--------------------------------------------------------------------------------
/proto/protobuf/source_context.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option java_package = "com.google.protobuf";
37 | option java_outer_classname = "SourceContextProto";
38 | option java_multiple_files = true;
39 | option objc_class_prefix = "GPB";
40 | option go_package = "types";
41 |
42 | // `SourceContext` represents information about the source of a
43 | // protobuf element, like the file in which it is defined.
44 | message SourceContext {
45 | // The path-qualified name of the .proto file that contained the associated
46 | // protobuf element. For example: `"google/protobuf/source_context.proto"`.
47 | string file_name = 1;
48 | }
49 |
--------------------------------------------------------------------------------
/src/services/balcony/balcony.go:
--------------------------------------------------------------------------------
1 | package balcony
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/common/logger"
6 | "INServer/src/proto/data"
7 | "INServer/src/proto/msg"
8 | "INServer/src/services/node"
9 | "fmt"
10 |
11 | "github.com/gogo/protobuf/proto"
12 | )
13 |
14 | // Instance 月台单例
15 | var Instance *Balcony
16 |
17 | // Balcony 月台 负责角色进入游戏世界之前的一些逻辑
18 | type Balcony struct {
19 | }
20 |
21 | // New 构造月台实例
22 | func New() *Balcony {
23 | b := new(Balcony)
24 | b.initMessageHandler()
25 | return b
26 | }
27 |
28 | // Start 服务启动
29 | func (b *Balcony) Start() {
30 |
31 | }
32 |
33 | // Stop 服务停止
34 | func (b *Balcony) Stop() {
35 |
36 | }
37 |
38 | func (b *Balcony) initMessageHandler() {
39 | node.Net.Listen(msg.CMD_ROLE_ENTER, b.HANDLE_ROLE_ENTER)
40 | }
41 |
42 | func (b *Balcony) HANDLE_ROLE_ENTER(header *msg.MessageHeader, buffer []byte) {
43 | roleEnterResp := &msg.RoleEnterResp{}
44 | defer node.Net.Responce(header, roleEnterResp)
45 | roleEnterReq := &msg.RoleEnterReq{}
46 | err := proto.Unmarshal(buffer, roleEnterReq)
47 | if err != nil {
48 | logger.Info(err)
49 | return
50 | }
51 |
52 | loadRoleReq := &msg.LoadRoleReq{
53 | RoleUUID: roleEnterReq.RoleUUID,
54 | }
55 | loadRoleResp := &msg.LoadRoleResp{}
56 | if err := node.Net.Request(msg.CMD_GD_LOAD_ROLE_REQ, loadRoleReq, loadRoleResp); err != nil {
57 | logger.Info(err)
58 | return
59 | }
60 | logger.Info(fmt.Sprintf("加载角色 %s", roleEnterReq.RoleUUID))
61 | roleEnterResp.Success = loadRoleResp.Success
62 | roleEnterResp.Role = loadRoleResp.Role
63 | if loadRoleResp.Success {
64 | getMapIDReq := &msg.GetMapIDReq{
65 | MapUUID: loadRoleResp.MapUUID,
66 | }
67 | getMapIDResp := &msg.GetMapIDResp{}
68 | err := node.Net.RequestServer(msg.CMD_GET_MAP_ID, getMapIDReq, getMapIDResp, loadRoleResp.WorldID)
69 | if err != nil {
70 | logger.Info(err)
71 | return
72 | }
73 | roleEnterResp.MapID = getMapIDResp.MapID
74 | roleEnterResp.WorldID = loadRoleResp.WorldID
75 |
76 | updateRoleAddressNTF := &msg.UpdateRoleAddressNTF{
77 | RoleUUID: roleEnterReq.RoleUUID,
78 | Address: &data.RoleAddress{
79 | Gate: global.InvalidServerID,
80 | World: loadRoleResp.WorldID,
81 | },
82 | }
83 | node.Net.Notify(msg.CMD_UPDATE_ROLE_ADDRESS_NTF, updateRoleAddressNTF)
84 |
85 | roleEnterNTF := &msg.RoleEnterNTF{
86 | Gate: header.From,
87 | Role: loadRoleResp.Role,
88 | }
89 | node.Net.NotifyServer(msg.CMD_ROLE_ENTER, roleEnterNTF, loadRoleResp.WorldID)
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/services/cluster/running.go:
--------------------------------------------------------------------------------
1 | package cluster
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/proto/etc"
6 | "INServer/src/proto/msg"
7 | "INServer/src/services/etcmgr"
8 | )
9 |
10 | var (
11 | running []int32
12 | gates []int32
13 | database int32
14 | gps int32
15 | balcony int32
16 | zones []*etc.Zone
17 | )
18 |
19 | // RunningGates 处于Running状态下的门服务器
20 | func RunningGates() []int32 {
21 | return gates
22 | }
23 |
24 | // RunningDatabase 处于Running状态下的数据库服务器
25 | func RunningDatabase() int32 {
26 | return database
27 | }
28 |
29 | // RunningGPS 处于Running状态下的定位服务器
30 | func RunningGPS() int32 {
31 | return gps
32 | }
33 |
34 | // RunningBalcony 处于Runing状态下的月台服务器
35 | func RunningBalcony() int32 {
36 | return balcony
37 | }
38 |
39 | // RefreshRunning 刷新活跃中的服务器
40 | func RefreshRunning() {
41 | running = make([]int32, 0)
42 | gates = make([]int32, 0)
43 | database = global.InvalidServerID
44 | gps = global.InvalidServerID
45 | balcony = global.InvalidServerID
46 | for serverID, info := range nodes {
47 | serverType := etcmgr.Instance.GetServerType(int32(serverID))
48 | if info.NodeState == msg.NodeState_Running {
49 | running = append(running, int32(serverID))
50 | if serverType == global.GateServer {
51 | gates = append(gates, int32(serverID))
52 | } else if serverType == global.DatabaseServer {
53 | database = int32(serverID)
54 | } else if serverType == global.GPSServer {
55 | gps = int32(serverID)
56 | } else if serverType == global.BalconyServer {
57 | balcony = int32(serverID)
58 | }
59 | }
60 | }
61 | }
62 |
63 | // RefreshRunningZones 刷新游戏区状态
64 | func RefreshRunningZones() {
65 | zones = make([]*etc.Zone, 0)
66 | for _, zone := range etcmgr.Instance.Zones() {
67 | realZone := &etc.Zone{}
68 | realZone.ZoneID = zone.ZoneID
69 | realZone.Name = zone.Name
70 | realZone.State = zone.State
71 | if zone.State != global.ZoneStateClosed {
72 | servers := etcmgr.Instance.GetZoneLocation(zone.ZoneID)
73 | for _, serverID := range servers {
74 | if GetNodeState(serverID) != msg.NodeState_Running {
75 | realZone.State = global.ZoneStateClosed
76 | break
77 | }
78 | }
79 | }
80 | zones = append(zones, realZone)
81 | }
82 | }
83 |
84 | // RunningCount 运行中服务器数量
85 | func RunningCount() int {
86 | return len(running)
87 | }
88 |
89 | func init() {
90 | running = make([]int32, 0)
91 | gates = make([]int32, 0)
92 | database = global.InvalidServerID
93 | gps = global.InvalidServerID
94 | balcony = global.InvalidServerID
95 | zones = make([]*etc.Zone, 0)
96 | }
97 |
--------------------------------------------------------------------------------
/proto/protobuf/empty.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option go_package = "types";
37 | option java_package = "com.google.protobuf";
38 | option java_outer_classname = "EmptyProto";
39 | option java_multiple_files = true;
40 | option objc_class_prefix = "GPB";
41 | option cc_enable_arenas = true;
42 |
43 | // A generic empty message that you can re-use to avoid defining duplicated
44 | // empty messages in your APIs. A typical example is to use it as the request
45 | // or the response type of an API method. For instance:
46 | //
47 | // service Foo {
48 | // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
49 | // }
50 | //
51 | // The JSON representation for `Empty` is empty JSON object `{}`.
52 | message Empty {}
53 |
--------------------------------------------------------------------------------
/src/common/uuid/uuid.go:
--------------------------------------------------------------------------------
1 | // 参考了github.com/satori/go.uuid v1的代码,进行了一些修改减少了位数,可以在服务器群中生成一个唯一的UUID
2 | package uuid
3 |
4 | import (
5 | "INServer/src/common/global"
6 | "crypto/rand"
7 | "encoding/binary"
8 | "errors"
9 | "io"
10 | "net"
11 | "strconv"
12 | "sync"
13 | "time"
14 | )
15 |
16 | const epochStart = 122192928000000000
17 |
18 | type epochFunc func() time.Time
19 | type hwAddrFunc func() (net.HardwareAddr, error)
20 |
21 | type (
22 | rfc4122Generator struct {
23 | clockSequenceOnce sync.Once
24 | hardwareAddrOnce sync.Once
25 | storageMutex sync.Mutex
26 |
27 | rand io.Reader
28 |
29 | epochFunc epochFunc
30 | hwAddrFunc hwAddrFunc
31 | lastTime uint64
32 | clockSequence uint16
33 | hardwareAddr [6]byte
34 | }
35 | )
36 |
37 | var generator = newRFC4122Generator()
38 |
39 | func newRFC4122Generator() *rfc4122Generator {
40 | return &rfc4122Generator{
41 | epochFunc: time.Now,
42 | hwAddrFunc: defaultHWAddrFunc,
43 | rand: rand.Reader,
44 | }
45 | }
46 |
47 | func New() string {
48 | u := make([]byte, 8)
49 | timeNow, clockSeq, _ := generator.getClockSequence()
50 | binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
51 | binary.BigEndian.PutUint16(u[4:], clockSeq)
52 | binary.BigEndian.PutUint16(u[6:], uint16(global.CurrentServerID))
53 |
54 | return strconv.FormatUint(binary.BigEndian.Uint64(u), 36)
55 | }
56 |
57 | func (g *rfc4122Generator) getClockSequence() (uint64, uint16, error) {
58 | var err error
59 | g.clockSequenceOnce.Do(func() {
60 | buf := make([]byte, 2)
61 | if _, err = io.ReadFull(g.rand, buf); err != nil {
62 | return
63 | }
64 | g.clockSequence = binary.BigEndian.Uint16(buf)
65 | })
66 | if err != nil {
67 | return 0, 0, err
68 | }
69 |
70 | g.storageMutex.Lock()
71 | defer g.storageMutex.Unlock()
72 |
73 | timeNow := g.getEpoch()
74 | // Clock didn't change since last UUID generation.
75 | // Should increase clock sequence.
76 | if timeNow <= g.lastTime {
77 | g.clockSequence++
78 | }
79 | g.lastTime = timeNow
80 |
81 | return timeNow, g.clockSequence, nil
82 | }
83 |
84 | func (g *rfc4122Generator) getEpoch() uint64 {
85 | return epochStart + uint64(g.epochFunc().UnixNano()/100)
86 | }
87 |
88 | func defaultHWAddrFunc() (net.HardwareAddr, error) {
89 | ifaces, err := net.Interfaces()
90 | if err != nil {
91 | return []byte{}, err
92 | }
93 | for _, iface := range ifaces {
94 | if len(iface.HardwareAddr) >= 6 {
95 | return iface.HardwareAddr, nil
96 | }
97 | }
98 | return []byte{}, errors.New("uuid: no HW address found")
99 | }
100 |
--------------------------------------------------------------------------------
/src/proto/data/data.role.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: data.role.proto
3 |
4 | package data
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *RoleSummaryData) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *RoleSummaryData) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
28 | // MarshalJSON implements json.Marshaler
29 | func (msg *RoleAddress) MarshalJSON() ([]byte, error) {
30 | var buf bytes.Buffer
31 | err := (&jsonpb.Marshaler{
32 | EnumsAsInts: false,
33 | EmitDefaults: false,
34 | OrigName: false,
35 | }).Marshal(&buf, msg)
36 | return buf.Bytes(), err
37 | }
38 |
39 | // UnmarshalJSON implements json.Unmarshaler
40 | func (msg *RoleAddress) UnmarshalJSON(b []byte) error {
41 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
42 | }
43 |
44 | // MarshalJSON implements json.Marshaler
45 | func (msg *RoleOnlineData) MarshalJSON() ([]byte, error) {
46 | var buf bytes.Buffer
47 | err := (&jsonpb.Marshaler{
48 | EnumsAsInts: false,
49 | EmitDefaults: false,
50 | OrigName: false,
51 | }).Marshal(&buf, msg)
52 | return buf.Bytes(), err
53 | }
54 |
55 | // UnmarshalJSON implements json.Unmarshaler
56 | func (msg *RoleOnlineData) UnmarshalJSON(b []byte) error {
57 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
58 | }
59 |
60 | // MarshalJSON implements json.Marshaler
61 | func (msg *RoleRealtimeData) MarshalJSON() ([]byte, error) {
62 | var buf bytes.Buffer
63 | err := (&jsonpb.Marshaler{
64 | EnumsAsInts: false,
65 | EmitDefaults: false,
66 | OrigName: false,
67 | }).Marshal(&buf, msg)
68 | return buf.Bytes(), err
69 | }
70 |
71 | // UnmarshalJSON implements json.Unmarshaler
72 | func (msg *RoleRealtimeData) UnmarshalJSON(b []byte) error {
73 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
74 | }
75 |
76 | // MarshalJSON implements json.Marshaler
77 | func (msg *Role) MarshalJSON() ([]byte, error) {
78 | var buf bytes.Buffer
79 | err := (&jsonpb.Marshaler{
80 | EnumsAsInts: false,
81 | EmitDefaults: false,
82 | OrigName: false,
83 | }).Marshal(&buf, msg)
84 | return buf.Bytes(), err
85 | }
86 |
87 | // UnmarshalJSON implements json.Unmarshaler
88 | func (msg *Role) UnmarshalJSON(b []byte) error {
89 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
90 | }
91 |
--------------------------------------------------------------------------------
/src/engine/grid/grid.go:
--------------------------------------------------------------------------------
1 | package grid
2 |
3 | import (
4 | "INServer/src/proto/engine"
5 | "INServer/src/proto/msg"
6 | )
7 |
8 | type (
9 | Grid struct {
10 | grids [][]*msg.NearEntity
11 | gridSize float64
12 | width int32
13 | height int32
14 | }
15 | )
16 |
17 | func New(gridSize float64, width int32, height int32) *Grid {
18 | g := new(Grid)
19 | g.grids = make([][]*msg.NearEntity, width*height)
20 | g.gridSize = gridSize
21 | g.width = width
22 | g.height = height
23 | return g
24 | }
25 |
26 | func (g *Grid) Add(uuid string, position *engine.Vector3) {
27 | x := int32(position.X / g.gridSize)
28 | z := int32(position.Z / g.gridSize)
29 | index := g.getGirdIndex(x, z)
30 | if g.grids[index] == nil {
31 | g.grids[index] = make([]*msg.NearEntity, 0)
32 | }
33 | g.grids[index] = append(g.grids[index], &msg.NearEntity{
34 | EntityUUID: uuid,
35 | Position: position,
36 | })
37 | }
38 |
39 | func (g *Grid) Remove(uuid string, position *engine.Vector3) {
40 | x := int32(position.X / g.gridSize)
41 | z := int32(position.Z / g.gridSize)
42 | index := g.getGirdIndex(x, z)
43 | if g.grids[index] == nil {
44 | g.grids[index] = make([]*msg.NearEntity, 0)
45 | }
46 | for i, item := range g.grids[index] {
47 | if item.EntityUUID == uuid {
48 | g.grids[index] = append(g.grids[index][:i], g.grids[index][i+1:]...)
49 | break
50 | }
51 | }
52 | }
53 |
54 | func (g *Grid) Move(uuid string, from *engine.Vector3, to *engine.Vector3) {
55 | fromX := int32(from.X / g.gridSize)
56 | fromZ := int32(to.Z / g.gridSize)
57 | toX := int32(to.X / g.gridSize)
58 | toZ := int32(to.Z / g.gridSize)
59 | if fromX == toX && fromZ == toZ {
60 | return
61 | }
62 | g.Remove(uuid, from)
63 | g.Add(uuid, to)
64 | }
65 |
66 | func (g *Grid) GetNearItems(center *engine.Vector3) []*msg.NearEntity {
67 | x := int32(center.X / g.gridSize)
68 | z := int32(center.Z / g.gridSize)
69 | items := make([]*msg.NearEntity, 0)
70 | items = append(items, g.getGridItems(x, z)...)
71 | items = append(items, g.getGridItems(x-1, z-1)...)
72 | items = append(items, g.getGridItems(x-1, z)...)
73 | items = append(items, g.getGridItems(x-1, z+1)...)
74 | items = append(items, g.getGridItems(x, z-1)...)
75 | items = append(items, g.getGridItems(x, z+1)...)
76 | items = append(items, g.getGridItems(x+1, z-1)...)
77 | items = append(items, g.getGridItems(x+1, z)...)
78 | items = append(items, g.getGridItems(x+1, z+1)...)
79 | return items
80 | }
81 |
82 | func (g *Grid) getGirdIndex(x int32, z int32) int32 {
83 | return (z+g.height/2)*g.width + (x + g.width/2)
84 | }
85 |
86 | func (g *Grid) getGridItems(x int32, z int32) []*msg.NearEntity {
87 | if x >= 0 && z >= 0 {
88 | index := g.getGirdIndex(x, z)
89 | if index < int32(len(g.grids)) {
90 | return g.grids[index]
91 | }
92 | }
93 | return make([]*msg.NearEntity, 0)
94 | }
95 |
--------------------------------------------------------------------------------
/src/services/node/node.go:
--------------------------------------------------------------------------------
1 | package node
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/common/logger"
6 | "INServer/src/proto/msg"
7 | "INServer/src/services/cluster"
8 | "INServer/src/services/etcmgr"
9 | "INServer/src/services/innet"
10 | "time"
11 |
12 | "github.com/golang/protobuf/proto"
13 | )
14 |
15 | var (
16 | Instance *Node
17 | Net *innet.INNet
18 | )
19 |
20 | type (
21 | Node struct {
22 | }
23 | )
24 |
25 | func New() *Node {
26 | n := new(Node)
27 | Net = innet.New()
28 | n.registerListeners()
29 | Net.Start()
30 | return n
31 | }
32 |
33 | // Prepare 节点进入Ready状态 这个状态之后可以收到集群的状态信息了
34 | func (n *Node) Prepare() {
35 | ntf := &msg.NodesInfoNTF{}
36 | ntf.Nodes = make([]*msg.Node, 0)
37 | for index := 0; index < len(etcmgr.Instance.Servers()); index++ {
38 | ntf.Nodes = append(ntf.Nodes, &msg.Node{
39 | NodeState: msg.NodeState_Unset,
40 | NodeAddress: nil,
41 | })
42 | }
43 | ntf.Nodes[global.CurrentServerID] = &msg.Node{
44 | NodeState: msg.NodeState_Ready,
45 | NodeAddress: Net.IP,
46 | }
47 | Net.NotifyServer(msg.CMD_NODES_INFO_NTF, ntf, global.CenterID)
48 | }
49 |
50 | // Start 节点进入Running状态 工作状态
51 | func (n *Node) Start() {
52 | ntf := &msg.NodesInfoNTF{}
53 | ntf.Nodes = make([]*msg.Node, 0)
54 | for index := 0; index < len(etcmgr.Instance.Servers()); index++ {
55 | ntf.Nodes = append(ntf.Nodes, &msg.Node{
56 | NodeState: msg.NodeState_Unset,
57 | NodeAddress: nil,
58 | })
59 | }
60 | ntf.Nodes[global.CurrentServerID] = &msg.Node{
61 | NodeState: msg.NodeState_Running,
62 | NodeAddress: Net.IP,
63 | }
64 | Net.NotifyServer(msg.CMD_NODES_INFO_NTF, ntf, global.CenterID)
65 | n.keepAlive()
66 | }
67 |
68 | func (n *Node) registerListeners() {
69 | Net.Listen(msg.CMD_NODES_INFO_NTF, n.HANDLE_NODES_INFO_NTF)
70 | Net.Listen(msg.CMD_ETC_SYNC_NTF, etcmgr.Instance.HANDLE_ETC_SYNC_NTF)
71 | Net.Listen(msg.CMD_RESET_CONNECTION_NTF, n.HANDLE_RESET_CONNECTION_NTF)
72 | }
73 |
74 | func (n *Node) HANDLE_NODES_INFO_NTF(header *msg.MessageHeader, buffer []byte) {
75 | ntf := &msg.NodesInfoNTF{}
76 | err := proto.Unmarshal(buffer, ntf)
77 | if err != nil {
78 | logger.Error(err)
79 | return
80 | }
81 | cluster.SetNodes(ntf.Nodes)
82 | Net.RefreshNodesAddress()
83 | }
84 |
85 | func (n *Node) HANDLE_RESET_CONNECTION_NTF(header *msg.MessageHeader, buffer []byte) {
86 | ntf := &msg.ResetConnectionNTF{}
87 | err := proto.Unmarshal(buffer, ntf)
88 | if err != nil {
89 | logger.Error(err)
90 | return
91 | }
92 | Net.ResetServer(ntf.ServerID)
93 | }
94 |
95 | func (n *Node) keepAlive() {
96 | go func() {
97 | for {
98 | info := &msg.KeepAlive{
99 | ServerID: global.CurrentServerID,
100 | }
101 | Net.NotifyServer(msg.CMD_KEEP_ALIVE, info, 0)
102 | time.Sleep(time.Second)
103 | }
104 | }()
105 | }
106 |
--------------------------------------------------------------------------------
/src/dao/dao.map.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "INServer/src/common/dbobj"
5 | "INServer/src/common/logger"
6 | "INServer/src/proto/db"
7 | )
8 |
9 | func AllStaticMapQuery(DB *dbobj.DBObject) []*db.DBStaticMap {
10 | rows, err := DB.DB().Query("select ZoneID, MapID, UUID, SerializedData from staticmaps")
11 | if err != nil {
12 | logger.Fatal(err)
13 | }
14 | staticMaps := []*db.DBStaticMap{}
15 | for rows.Next() {
16 | staticMap := &db.DBStaticMap{}
17 | rows.Scan(&staticMap.ZoneID, &staticMap.MapID, &staticMap.UUID, &staticMap.SerializedData)
18 | staticMaps = append(staticMaps, staticMap)
19 | }
20 | return staticMaps
21 | }
22 |
23 | func StaticMapInsert(DB *dbobj.DBObject, staticMap *db.DBStaticMap) error {
24 | _, err := DB.DB().Exec("insert INTO staticmaps(ZoneID,MapID,UUID,SerializedData) values(?,?,?,?)", staticMap.ZoneID, staticMap.MapID, staticMap.UUID, staticMap.SerializedData)
25 | if err != nil {
26 | logger.Error(err)
27 | return err
28 | }
29 | return nil
30 | }
31 |
32 | func StaticMapUpdate(DB *dbobj.DBObject, staticMap *db.DBStaticMap) error {
33 | _, err := DB.DB().Exec("UPDATE staticmaps set SerializedData=? where UUID=?", staticMap.SerializedData, staticMap.UUID)
34 | if err != nil {
35 | logger.Error(err)
36 | return err
37 | }
38 | return nil
39 | }
40 |
41 | func BulkStaticMapUpdate(DB *dbobj.DBObject, staticMaps []*db.DBStaticMap) error {
42 | tx, err := DB.DB().Begin()
43 | if err != nil {
44 | logger.Error(err)
45 | return err
46 | }
47 | stmt, err := tx.Prepare(`UPDATE staticmaps set SerializedData=? where UUID=?`)
48 | if err != nil {
49 | logger.Error(err)
50 | return err
51 | }
52 | for _, staticMap := range staticMaps {
53 | _, err := stmt.Exec(staticMap.SerializedData, staticMap.UUID)
54 | if err != nil {
55 | logger.Error(err)
56 | return err
57 | }
58 | }
59 | err = tx.Commit()
60 | if err != nil {
61 | logger.Error(err)
62 | }
63 | return err
64 | }
65 |
66 | func DynamicMapQuery(DB *dbobj.DBObject, uuid string) (*db.DBDynamicMap, error) {
67 | dynamicMap := new(db.DBDynamicMap)
68 | row := DB.DB().QueryRow("select * from dynamicmaps where UUID=?", uuid)
69 | if err := row.Scan(&dynamicMap.UUID, &dynamicMap.SerializedData); err != nil {
70 | logger.Debug(err)
71 | return nil, err
72 | }
73 | return dynamicMap, nil
74 | }
75 |
76 | func DynamicMapInsert(DB *dbobj.DBObject, dynamicMap *db.DBDynamicMap) error {
77 | _, err := DB.DB().Exec("insert INTO dynamicmaps(UUID,SerializedData) values(?,?)", dynamicMap.UUID, dynamicMap.SerializedData)
78 | if err != nil {
79 | logger.Debug(err)
80 | return err
81 | }
82 | return nil
83 | }
84 |
85 | func DynamicMapUpdate(DB *dbobj.DBObject, dynamicMap *db.DBDynamicMap) error {
86 | _, err := DB.DB().Exec("UPDATE dynamicmaps set SerializedData=? where UUID=?", dynamicMap.SerializedData, dynamicMap.UUID)
87 | if err != nil {
88 | logger.Debug(err)
89 | return err
90 | }
91 | return nil
92 | }
93 |
--------------------------------------------------------------------------------
/src/services/innet/sender.go:
--------------------------------------------------------------------------------
1 | package innet
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/common/logger"
6 | "INServer/src/proto/msg"
7 | "encoding/binary"
8 | "net"
9 | "time"
10 |
11 | "github.com/golang/protobuf/proto"
12 | "github.com/gorilla/websocket"
13 | )
14 |
15 | type (
16 | sender struct {
17 | innet *INNet
18 | }
19 | )
20 |
21 | func newSender(innet *INNet) *sender {
22 | s := new(sender)
23 | s.innet = innet
24 | return s
25 | }
26 |
27 | func SendUDPBytesHelper(addr *net.UDPAddr, bytes []byte) error {
28 | sizebuf := make([]byte, 2)
29 | binary.BigEndian.PutUint16(sizebuf, uint16(len(bytes)))
30 | _, err := udpconn.WriteToUDP(append(sizebuf, bytes...), addr)
31 | if err != nil {
32 | logger.Debug(err)
33 | }
34 | return err
35 | }
36 |
37 | func SendBytesHelper(conn net.Conn, bytes []byte) error {
38 | sizebuf := make([]byte, 2)
39 | binary.BigEndian.PutUint16(sizebuf, uint16(len(bytes)))
40 | _, err := conn.Write(append(sizebuf, bytes...))
41 | if err != nil {
42 | logger.Debug(err)
43 | }
44 | return err
45 | }
46 |
47 | func SendWebBytesHelper(conn *websocket.Conn, bytes []byte) error {
48 | sizebuf := make([]byte, 2)
49 | binary.BigEndian.PutUint16(sizebuf, uint16(len(bytes)))
50 | err := conn.WriteMessage(websocket.BinaryMessage, append(sizebuf, bytes...))
51 | if err != nil {
52 | logger.Debug(err)
53 | }
54 | return err
55 | }
56 |
57 | func (s *sender) send(svr *server, buffer []byte) error {
58 | svr.packageID++
59 | slices := cutslices(buffer)
60 | var packages []*msg.Package
61 | total := int32(len(slices))
62 | for index, slice := range slices {
63 | packages = append(packages, &msg.Package{
64 | UniqueID: svr.packageID,
65 | From: int32(global.CurrentServerID),
66 | Index: int32(index),
67 | Total: total,
68 | Buffer: slice,
69 | })
70 | }
71 | s.sendPackages(svr.addr, packages)
72 |
73 | s.innet.retry.addPackagesCache(svr.packageID, &packageCache{
74 | addr: svr.addr,
75 | packages: packages,
76 | retryTime: time.Now().UnixNano() + timeout,
77 | toServerID: svr.id,
78 | })
79 | return nil
80 | }
81 |
82 | func (s *sender) start(svr *server, buffer []byte) {
83 | var packages []*msg.Package
84 | packages = append(packages, &msg.Package{
85 | UniqueID: 0,
86 | From: int32(global.CurrentServerID),
87 | Index: 0,
88 | Total: 1,
89 | Buffer: buffer,
90 | })
91 | s.sendPackages(svr.addr, packages)
92 | }
93 |
94 | func (s *sender) ack(addr *net.UDPAddr, pkg *msg.Package) {
95 | buffer, _ := proto.Marshal(&msg.Package{
96 | UniqueID: pkg.UniqueID,
97 | From: int32(global.CurrentServerID),
98 | Index: pkg.Index,
99 | Total: pkg.Total,
100 | })
101 | SendUDPBytesHelper(addr, buffer)
102 | }
103 |
104 | func (s *sender) sendPackages(addr *net.UDPAddr, packages []*msg.Package) {
105 | for _, pkg := range packages {
106 | buf, _ := proto.Marshal(pkg)
107 | SendUDPBytesHelper(addr, buf)
108 | }
109 | }
110 |
111 | func cutslices(buffer []byte) [][]byte {
112 | var slices [][]byte
113 | from := 0
114 | for len(buffer[from:]) > sliceSize {
115 | to := from + sliceSize
116 | slices = append(slices, buffer[from:to])
117 | from = to
118 | }
119 | slices = append(slices, buffer[from:])
120 | return slices
121 | }
122 |
--------------------------------------------------------------------------------
/src/lifetime/startup/startup.go:
--------------------------------------------------------------------------------
1 | package startup
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/common/logger"
6 | "INServer/src/common/util"
7 | "INServer/src/services/ai"
8 | "INServer/src/services/balcony"
9 | "INServer/src/services/center"
10 | "INServer/src/services/cluster"
11 | "INServer/src/services/database"
12 | "INServer/src/services/etcmgr"
13 | "INServer/src/services/gate"
14 | "INServer/src/services/gps"
15 | "INServer/src/services/login"
16 | "INServer/src/services/node"
17 | "INServer/src/services/robot"
18 | "INServer/src/services/web"
19 | "INServer/src/services/world"
20 | "fmt"
21 | "strings"
22 | "time"
23 | )
24 |
25 | // Run 服务器启动流程
26 | func Run() {
27 | if global.CurrentServerID == global.CenterID {
28 | go startCenter()
29 | } else {
30 | go startNode()
31 | }
32 | }
33 |
34 | func startCenter() {
35 | global.CurrentServerType = global.CenterServer
36 | util.SetProcessName(fmt.Sprintf("%s@in-%d ", strings.ToLower(global.CurrentServerType), global.CurrentServerID))
37 | etcmgr.Instance = etcmgr.New()
38 | global.CurrentServerConfig = etcmgr.Instance.GetServerConfig(global.CurrentServerID)
39 | center.Instance = center.New()
40 | center.Instance.Start()
41 | }
42 |
43 | func startNode() {
44 | etcmgr.Instance = etcmgr.New()
45 | node.Instance = node.New()
46 | for {
47 | if etcmgr.Instance.OK() {
48 | break
49 | } else {
50 | node.Net.SendNodeStartNTF()
51 | logger.Info("等待中心服启动完成...")
52 | time.Sleep(time.Second)
53 | }
54 | }
55 |
56 | global.CurrentServerType = etcmgr.Instance.GetServerType(global.CurrentServerID)
57 | global.CurrentServerConfig = etcmgr.Instance.GetServerConfig(global.CurrentServerID)
58 | util.SetProcessName(fmt.Sprintf("%s@in-%d ", strings.ToLower(global.CurrentServerType), global.CurrentServerID))
59 | node.Instance.Prepare()
60 | startServer()
61 | node.Instance.Start()
62 | logger.Info(fmt.Sprintf("服务器启动完成 ID:%d Type:%s", global.CurrentServerID, global.CurrentServerType))
63 | }
64 |
65 | func startServer() {
66 | switch global.CurrentServerType {
67 | case global.GateServer:
68 | gate.Instance = gate.New()
69 | gate.Instance.Start()
70 | break
71 | case global.LoginServer:
72 | login.Instance = login.New()
73 | login.Instance.Start()
74 | case global.DatabaseServer:
75 | database.Instance = database.New()
76 | database.Instance.Start()
77 | case global.WebServer:
78 | web.Instance = web.New()
79 | web.Instance.Start()
80 | case global.WorldServer:
81 | util.Wait(func() bool {
82 | return cluster.RunningDatabase() != global.InvalidServerID
83 | }, "等待数据库服务器启动完成...", time.Second)
84 | util.Wait(func() bool {
85 | return cluster.RunningGPS() != global.InvalidServerID
86 | }, "等待定位服务器启动完成...", time.Second)
87 | world.Instance = world.New()
88 | world.Instance.Start()
89 | case global.GPSServer:
90 | gps.Instance = gps.New()
91 | gps.Instance.Start()
92 | case global.BalconyServer:
93 | balcony.Instance = balcony.New()
94 | balcony.Instance.Start()
95 | case global.AIServer:
96 | ai.Instance = ai.New()
97 | ai.Instance.Start()
98 | case global.RobotServer:
99 | robot.Instance = robot.New()
100 | robot.Instance.Start()
101 | default:
102 | logger.Fatal("不支持的服务器类型:" + global.CurrentServerType)
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/services/innet/address.go:
--------------------------------------------------------------------------------
1 | package innet
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/common/logger"
6 | "INServer/src/proto/msg"
7 | "INServer/src/services/cluster"
8 | "fmt"
9 | "net"
10 | "strconv"
11 | )
12 |
13 | type (
14 | server struct {
15 | addr *net.UDPAddr
16 | packageID uint64
17 | id int32
18 | }
19 |
20 | address struct {
21 | innet *INNet
22 | servers map[int32]*server
23 | center *server
24 | }
25 | )
26 |
27 | func newAddress(innet *INNet) *address {
28 | a := new(address)
29 | a.innet = innet
30 | a.servers = make(map[int32]*server)
31 |
32 | addr, err := net.ResolveUDPAddr("udp4", "127.0.0.1:"+strconv.Itoa(int(global.CenterID)+recvport))
33 | if err != nil {
34 | logger.Fatal(err)
35 | }
36 | a.center = &server{
37 | addr: addr,
38 | packageID: 0,
39 | id: global.CenterID,
40 | }
41 | return a
42 | }
43 |
44 | func (a *address) refresh() {
45 | servers := cluster.GetNodes()
46 | for serverID, info := range servers {
47 | if info.NodeAddress != nil && len(info.NodeAddress) > 0 {
48 | var svr *server
49 | var ok = false
50 | if svr, ok = a.servers[int32(serverID)]; ok == false {
51 | svr = &server{
52 | packageID: 0,
53 | id: int32(serverID),
54 | }
55 | a.servers[svr.id] = svr
56 | }
57 | ip := &net.IPAddr{IP: info.NodeAddress}
58 | addr := &net.UDPAddr{IP: ip.IP, Port: serverID + recvport, Zone: ip.Zone}
59 | svr.addr = addr
60 | }
61 | }
62 | }
63 |
64 | func (a *address) resetServer(serverID int32) {
65 | if svr, ok := a.servers[serverID]; ok {
66 | svr.packageID = 0
67 | }
68 | }
69 |
70 | func (a *address) getByCommand(command msg.CMD) *server {
71 | switch command {
72 | case msg.CMD_KEEP_ALIVE, msg.CMD_RELOAD_ETC_REQ:
73 | return a.center
74 | case msg.CMD_LD_CREATE_PLAYER_REQ,
75 | msg.CMD_GD_LOAD_PLAYER_REQ,
76 | msg.CMD_GD_RELEASE_PLAYER_NTF,
77 | msg.CMD_GD_CREATE_ROLE_REQ,
78 | msg.CMD_GD_LOAD_ROLE_REQ,
79 | msg.CMD_SAVE_ROLE_REQ,
80 | msg.CMD_LOAD_STATIC_MAP_REQ,
81 | msg.CMD_SAVE_STATIC_MAP_REQ:
82 | serverID := cluster.RunningDatabase()
83 | if serverID != global.InvalidServerID {
84 | if svr, ok := a.servers[serverID]; ok {
85 | return svr
86 | }
87 | }
88 | logger.Error(fmt.Sprintf("没有找到Database服务器 %d", serverID))
89 | break
90 | case msg.CMD_GET_MAP_ADDRESS_REQ,
91 | msg.CMD_GET_STATIC_MAP_UUID_REQ,
92 | msg.CMD_UPDATE_MAP_ADDRESS_NTF,
93 | msg.CMD_UPDATE_ROLE_ADDRESS_NTF,
94 | msg.CMD_REMOVE_ROLE_ADDRESS_NTF,
95 | msg.CMD_UPDATE_STATIC_MAP_UUID_NTF:
96 | serverID := cluster.RunningGPS()
97 | if serverID != global.InvalidServerID {
98 | if svr, ok := a.servers[serverID]; ok {
99 | return svr
100 | }
101 | }
102 | logger.Error(fmt.Sprintf("没有找到GPS服务器 %d", serverID))
103 | break
104 | case msg.CMD_ROLE_ENTER:
105 | serverID := cluster.RunningBalcony()
106 | if serverID != global.InvalidServerID {
107 | if svr, ok := a.servers[serverID]; ok {
108 | return svr
109 | }
110 | }
111 | logger.Error(fmt.Sprintf("没有找到月台服务器 %d", serverID))
112 | break
113 | }
114 | return nil
115 | }
116 |
117 | func (a *address) getByServerID(serverID int32) *server {
118 | if serverID == global.CenterID {
119 | return a.center
120 | } else if info, ok := a.servers[serverID]; ok {
121 | return info
122 | }
123 |
124 | return nil
125 | }
126 |
--------------------------------------------------------------------------------
/src/services/web/web.go:
--------------------------------------------------------------------------------
1 | package web
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/common/logger"
6 | "INServer/src/common/util"
7 | "INServer/src/proto/msg"
8 | "INServer/src/services/etcmgr"
9 | "INServer/src/services/node"
10 | "encoding/base64"
11 | "encoding/json"
12 | "fmt"
13 | "html/template"
14 | "io"
15 | "net/http"
16 | "os"
17 | "strconv"
18 | "strings"
19 | )
20 |
21 | //定义全局的模板变量
22 | var webhtml *template.Template
23 | var Instance *Web
24 |
25 | type (
26 | Web struct {
27 | }
28 | )
29 |
30 | func New() *Web {
31 | w := new(Web)
32 | return w
33 | }
34 |
35 | func (w *Web) Start() {
36 | http.HandleFunc("/", w.root)
37 | http.HandleFunc("/zones", w.zones)
38 | http.HandleFunc("/reloadetc", w.reloadetc)
39 | dir, err := os.Getwd()
40 | if err != nil {
41 | logger.Fatal(err)
42 | }
43 | certFile := fmt.Sprintf("%s/web/server.crt", dir)
44 | keyFile := fmt.Sprintf("%s/web/server.key", dir)
45 | if util.PathExists(certFile) && util.PathExists(keyFile) {
46 | go http.ListenAndServeTLS(":"+strconv.Itoa(int(global.CurrentServerConfig.WebConfig.Port)), certFile, keyFile, nil)
47 | }
48 | go http.ListenAndServe(":"+strconv.Itoa(int(global.CurrentServerConfig.WebConfig.Port)), nil)
49 | }
50 |
51 | func (w *Web) checkauth(writer http.ResponseWriter, req *http.Request) bool {
52 | auth := req.Header.Get("Authorization")
53 | if auth == "" {
54 | writer.Header().Set("WWW-Authenticate", `Basic realm="Dotcoo User Login"`)
55 | writer.WriteHeader(http.StatusUnauthorized)
56 | return false
57 | }
58 | auths := strings.SplitN(auth, " ", 2)
59 | if len(auths) != 2 {
60 | fmt.Println("error")
61 | return false
62 | }
63 | authMethod := auths[0]
64 | authB64 := auths[1]
65 | switch authMethod {
66 | case "Basic":
67 | authstr, err := base64.StdEncoding.DecodeString(authB64)
68 | if err != nil {
69 | logger.Error(err)
70 | io.WriteString(writer, "Unauthorized!\n")
71 | return false
72 | }
73 | user := strings.SplitN(string(authstr), ":", 2)
74 | if len(user) != 2 {
75 | logger.Error(user)
76 | return false
77 | }
78 | account := user[0]
79 | password := user[1]
80 | config := global.CurrentServerConfig.WebConfig
81 | if account != config.Account || password != config.Password {
82 | io.WriteString(writer, "账号或密码错误!\n")
83 | return false
84 | }
85 | default:
86 | logger.Error(authMethod)
87 | return false
88 | }
89 | return true
90 | }
91 |
92 | func (w *Web) root(writer http.ResponseWriter, req *http.Request) {
93 | logger.Info("HTTP请求", req.RemoteAddr)
94 | if w.checkauth(writer, req) == false {
95 | return
96 | }
97 | err := webhtml.Execute(writer, nil)
98 | if err != nil {
99 | logger.Error(err)
100 | }
101 | }
102 |
103 | func (w *Web) zones(writer http.ResponseWriter, req *http.Request) {
104 | bytes, err := json.Marshal(etcmgr.Instance.Zones())
105 | if err != nil {
106 | logger.Debug(err)
107 | } else {
108 | io.WriteString(writer, string(bytes))
109 | }
110 | }
111 |
112 | func (w *Web) reloadetc(writer http.ResponseWriter, req *http.Request) {
113 | _, err := node.Net.RequestBytes(msg.CMD_RELOAD_ETC_REQ, make([]byte, 1))
114 | if err != nil {
115 | io.WriteString(writer, err.Error())
116 | } else {
117 | io.WriteString(writer, "success")
118 | }
119 | }
120 |
121 | func init() {
122 | dir, err := os.Getwd()
123 | if err != nil {
124 | logger.Fatal(err)
125 | }
126 | webhtml, err = template.ParseFiles(fmt.Sprintf("%s/web/web.html", dir))
127 | if err != nil {
128 | logger.Fatal(err)
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/proto/data/data.component.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: data.component.proto
3 |
4 | package data
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *TransformComponent) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *TransformComponent) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
28 | // MarshalJSON implements json.Marshaler
29 | func (msg *PhysicsComponent) MarshalJSON() ([]byte, error) {
30 | var buf bytes.Buffer
31 | err := (&jsonpb.Marshaler{
32 | EnumsAsInts: false,
33 | EmitDefaults: false,
34 | OrigName: false,
35 | }).Marshal(&buf, msg)
36 | return buf.Bytes(), err
37 | }
38 |
39 | // UnmarshalJSON implements json.Unmarshaler
40 | func (msg *PhysicsComponent) UnmarshalJSON(b []byte) error {
41 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
42 | }
43 |
44 | // MarshalJSON implements json.Marshaler
45 | func (msg *AttributeComponent) MarshalJSON() ([]byte, error) {
46 | var buf bytes.Buffer
47 | err := (&jsonpb.Marshaler{
48 | EnumsAsInts: false,
49 | EmitDefaults: false,
50 | OrigName: false,
51 | }).Marshal(&buf, msg)
52 | return buf.Bytes(), err
53 | }
54 |
55 | // UnmarshalJSON implements json.Unmarshaler
56 | func (msg *AttributeComponent) UnmarshalJSON(b []byte) error {
57 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
58 | }
59 |
60 | // MarshalJSON implements json.Marshaler
61 | func (msg *MoveComponent) MarshalJSON() ([]byte, error) {
62 | var buf bytes.Buffer
63 | err := (&jsonpb.Marshaler{
64 | EnumsAsInts: false,
65 | EmitDefaults: false,
66 | OrigName: false,
67 | }).Marshal(&buf, msg)
68 | return buf.Bytes(), err
69 | }
70 |
71 | // UnmarshalJSON implements json.Unmarshaler
72 | func (msg *MoveComponent) UnmarshalJSON(b []byte) error {
73 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
74 | }
75 |
76 | // MarshalJSON implements json.Marshaler
77 | func (msg *ControllerComponent) MarshalJSON() ([]byte, error) {
78 | var buf bytes.Buffer
79 | err := (&jsonpb.Marshaler{
80 | EnumsAsInts: false,
81 | EmitDefaults: false,
82 | OrigName: false,
83 | }).Marshal(&buf, msg)
84 | return buf.Bytes(), err
85 | }
86 |
87 | // UnmarshalJSON implements json.Unmarshaler
88 | func (msg *ControllerComponent) UnmarshalJSON(b []byte) error {
89 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
90 | }
91 |
92 | // MarshalJSON implements json.Marshaler
93 | func (msg *RebornComponent) MarshalJSON() ([]byte, error) {
94 | var buf bytes.Buffer
95 | err := (&jsonpb.Marshaler{
96 | EnumsAsInts: false,
97 | EmitDefaults: false,
98 | OrigName: false,
99 | }).Marshal(&buf, msg)
100 | return buf.Bytes(), err
101 | }
102 |
103 | // UnmarshalJSON implements json.Unmarshaler
104 | func (msg *RebornComponent) UnmarshalJSON(b []byte) error {
105 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
106 | }
107 |
108 | // MarshalJSON implements json.Marshaler
109 | func (msg *Component) MarshalJSON() ([]byte, error) {
110 | var buf bytes.Buffer
111 | err := (&jsonpb.Marshaler{
112 | EnumsAsInts: false,
113 | EmitDefaults: false,
114 | OrigName: false,
115 | }).Marshal(&buf, msg)
116 | return buf.Bytes(), err
117 | }
118 |
119 | // UnmarshalJSON implements json.Unmarshaler
120 | func (msg *Component) UnmarshalJSON(b []byte) error {
121 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
122 | }
123 |
--------------------------------------------------------------------------------
/src/gameplay/gamemap/scene.go:
--------------------------------------------------------------------------------
1 | package gamemap
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/common/logger"
6 | "INServer/src/engine/extensions/vector3"
7 | "INServer/src/engine/grid"
8 | "INServer/src/gameplay/ecs"
9 | "INServer/src/proto/config"
10 | "INServer/src/proto/data"
11 | "INServer/src/proto/engine"
12 | "INServer/src/proto/msg"
13 | "time"
14 | )
15 |
16 | type (
17 | Scene struct {
18 | masterMap *Map
19 | search *grid.Grid
20 | Width int32
21 | Height int32
22 | entities map[string]*ecs.Entity
23 |
24 | syncTime int64
25 | }
26 | )
27 |
28 | func NewScene(masterMap *Map, sceneConfig *config.Scene) *Scene {
29 | s := new(Scene)
30 | s.masterMap = masterMap
31 | s.Width = 1000
32 | s.Height = 1000
33 | s.search = grid.New(10, s.Width, s.Height)
34 | s.entities = make(map[string]*ecs.Entity)
35 | return s
36 | }
37 |
38 | func (s *Scene) Tick() {
39 | now := time.Now().UnixNano()
40 | if s.syncTime+global.NANO_PER_SECONE < now {
41 | s.syncEntitiesNTF()
42 | }
43 | }
44 |
45 | func (s *Scene) EntityEnter(uuid string, entity *ecs.Entity) {
46 | transform := entity.GetComponent(data.ComponentType_Transofrm).Transform
47 | if transform != nil {
48 | s.search.Add(uuid, transform.Position)
49 | }
50 | s.entities[uuid] = entity
51 | }
52 |
53 | func (s *Scene) EntityLeave(uuid string, entity *ecs.Entity) {
54 | transform := entity.GetComponent(data.ComponentType_Transofrm).Transform
55 | if transform != nil {
56 | s.search.Remove(uuid, transform.Position)
57 | }
58 | delete(s.entities, uuid)
59 | }
60 |
61 | func (s *Scene) SyncEntityPosition(uuid string, entity *ecs.Entity, from *engine.Vector3) {
62 | transform := entity.GetComponent(data.ComponentType_Transofrm).Transform
63 | if transform != nil {
64 | s.search.Move(uuid, from, transform.Position)
65 | }
66 | }
67 |
68 | func (s *Scene) onEntityMoveINF(entity *ecs.Entity, inf *msg.MoveINF) {
69 | transform := entity.GetComponent(data.ComponentType_Transofrm).Transform
70 | if transform != nil {
71 | s.search.Move(entity.UUID(), transform.Position, inf.Position)
72 | transform.Position = inf.Position
73 | physics := entity.GetComponent(data.ComponentType_Physics).Physics
74 | attribute := entity.GetComponent(data.ComponentType_Attribute).Attribute
75 | move := entity.GetComponent(data.ComponentType_Move).Move
76 | if physics != nil && attribute != nil && move != nil {
77 | move.Destination = inf.To
78 | physics.RawSpeed = vector3.Multiply(vector3.Normalize(vector3.Minus(inf.To, inf.Position)), float64(attribute.Speed))
79 | ntf := &msg.MoveNTF{}
80 | ntf.EntityUUID = entity.UUID()
81 | ntf.To = inf.To
82 | items := s.search.GetNearItems(inf.Position)
83 | for _, item := range items {
84 | logger.Info(item.EntityUUID)
85 | //nearEntity := s.masterMap.GetEntity(item.UUID())
86 | }
87 | }
88 | }
89 | }
90 |
91 | func (s *Scene) onEntityStopMoveINF(entity *ecs.Entity, inf *msg.StopMoveINF) {
92 | transform := entity.GetComponent(data.ComponentType_Transofrm).Transform
93 | if transform != nil {
94 | s.search.Move(entity.UUID(), transform.Position, inf.Position)
95 | transform.Position = inf.Position
96 | physics := entity.GetComponent(data.ComponentType_Physics).Physics
97 | if physics != nil {
98 | physics.RawSpeed = &engine.Vector3{}
99 | }
100 | move := entity.GetComponent(data.ComponentType_Move).Move
101 | if move != nil {
102 | move.Destination = inf.Position
103 | }
104 | }
105 | }
106 |
107 | func (s *Scene) syncEntitiesNTF() {
108 | for _, entity := range s.entities {
109 | controller := entity.GetComponent(data.ComponentType_Controller).Controller
110 | if controller.ControllerType != data.ControllerType_PlayerController {
111 | continue
112 | }
113 | transform := entity.GetComponent(data.ComponentType_Transofrm).Transform
114 | if transform != nil {
115 | items := s.search.GetNearItems(transform.Position)
116 | entity.Controller().OnNearEntities(items)
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/proto/protobuf/struct.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option cc_enable_arenas = true;
37 | option go_package = "types";
38 | option java_package = "com.google.protobuf";
39 | option java_outer_classname = "StructProto";
40 | option java_multiple_files = true;
41 | option objc_class_prefix = "GPB";
42 |
43 | // `Struct` represents a structured data value, consisting of fields
44 | // which map to dynamically typed values. In some languages, `Struct`
45 | // might be supported by a native representation. For example, in
46 | // scripting languages like JS a struct is represented as an
47 | // object. The details of that representation are described together
48 | // with the proto support for the language.
49 | //
50 | // The JSON representation for `Struct` is JSON object.
51 | message Struct {
52 | // Unordered map of dynamically typed values.
53 | map fields = 1;
54 | }
55 |
56 | // `Value` represents a dynamically typed value which can be either
57 | // null, a number, a string, a boolean, a recursive struct value, or a
58 | // list of values. A producer of value is expected to set one of that
59 | // variants, absence of any variant indicates an error.
60 | //
61 | // The JSON representation for `Value` is JSON value.
62 | message Value {
63 | // The kind of value.
64 | oneof kind {
65 | // Represents a null value.
66 | NullValue null_value = 1;
67 | // Represents a double value.
68 | double number_value = 2;
69 | // Represents a string value.
70 | string string_value = 3;
71 | // Represents a boolean value.
72 | bool bool_value = 4;
73 | // Represents a structured value.
74 | Struct struct_value = 5;
75 | // Represents a repeated `Value`.
76 | ListValue list_value = 6;
77 | }
78 | }
79 |
80 | // `NullValue` is a singleton enumeration to represent the null value for the
81 | // `Value` type union.
82 | //
83 | // The JSON representation for `NullValue` is JSON `null`.
84 | enum NullValue {
85 | // Null value.
86 | NULL_VALUE = 0;
87 | }
88 |
89 | // `ListValue` is a wrapper around a repeated field of values.
90 | //
91 | // The JSON representation for `ListValue` is JSON array.
92 | message ListValue {
93 | // Repeated field of dynamically typed values.
94 | repeated Value values = 1;
95 | }
96 |
--------------------------------------------------------------------------------
/src/gameplay/ecs/entity.go:
--------------------------------------------------------------------------------
1 | package ecs
2 |
3 | import (
4 | "INServer/src/proto/data"
5 | "INServer/src/proto/engine"
6 | )
7 |
8 | type (
9 | // Entity 游戏实体
10 | Entity struct {
11 | entityData *data.EntityData
12 | entityType data.EntityType
13 | controller Controller
14 | }
15 | )
16 |
17 | // NewEntity 构造实体
18 | func NewEntity(entityData *data.EntityData, entityType data.EntityType) *Entity {
19 | e := new(Entity)
20 | e.entityData = entityData
21 | e.entityType = entityType
22 | initController(e)
23 | return e
24 | }
25 |
26 | // AddComponent 添加组件
27 | func (e *Entity) AddComponent(component *data.Component) {
28 | e.entityData.Components[component.Type] = component
29 | }
30 |
31 | // RemoveComponent 移除组件
32 | func (e *Entity) RemoveComponent(componentType data.ComponentType) {
33 | e.entityData.Components[componentType] = nil
34 | }
35 |
36 | // GetComponent 取得组件
37 | func (e *Entity) GetComponent(componentType data.ComponentType) *data.Component {
38 | if e.entityData.Components[componentType] == nil {
39 | return &data.Component{}
40 | }
41 | return e.entityData.Components[componentType]
42 | }
43 |
44 | // RealTimeData 实时数据
45 | func (e *Entity) RealTimeData() *data.EntityRealtimeData {
46 | return e.entityData.RealTimeData
47 | }
48 |
49 | // EntityData 实体数据
50 | func (e *Entity) EntityData() *data.EntityData {
51 | return e.entityData
52 | }
53 |
54 | // UUID 返回UUID
55 | func (e *Entity) UUID() string {
56 | return e.entityData.EntityUUID
57 | }
58 |
59 | // Controller 返回Controller
60 | func (e *Entity) Controller() Controller {
61 | return e.controller
62 | }
63 |
64 | // InitComponents 根据实体类型初始化组件
65 | func InitComponents(entityType data.EntityType) []*data.Component {
66 | components := make([]*data.Component, len(data.ComponentType_name))
67 | for index := 0; index < len(data.ComponentType_name); index++ {
68 | components[index] = &data.Component{
69 | Type: data.ComponentType(index),
70 | }
71 | }
72 | switch entityType {
73 | case data.EntityType_MonsterEntity:
74 | components[data.ComponentType_Transofrm].Transform = &data.TransformComponent{
75 | Position: &engine.Vector3{},
76 | Rotation: &engine.Quaternion{},
77 | }
78 | components[data.ComponentType_Physics].Physics = &data.PhysicsComponent{
79 | Mass: 100,
80 | RawSpeed: &engine.Vector3{},
81 | PassiveSpeed: &engine.Vector3{},
82 | }
83 | components[data.ComponentType_Attribute].Attribute = &data.AttributeComponent{
84 | Speed: 10,
85 | HP: 100,
86 | MaxHP: 100,
87 | }
88 | components[data.ComponentType_Move].Move = &data.MoveComponent{
89 | Destination: &engine.Vector3{},
90 | }
91 | components[data.ComponentType_Controller].Controller = &data.ControllerComponent{
92 | ControllerType: data.ControllerType_PlayerController,
93 | }
94 | components[data.ComponentType_Reborn].Reborn = &data.RebornComponent{
95 | RebornTime: 0,
96 | RebornType: data.RebornType_Auto,
97 | }
98 | break
99 | case data.EntityType_RoleEntity:
100 | components[data.ComponentType_Transofrm].Transform = &data.TransformComponent{
101 | Position: &engine.Vector3{},
102 | Rotation: &engine.Quaternion{},
103 | }
104 | components[data.ComponentType_Physics].Physics = &data.PhysicsComponent{
105 | Mass: 100,
106 | RawSpeed: &engine.Vector3{},
107 | PassiveSpeed: &engine.Vector3{},
108 | }
109 | components[data.ComponentType_Attribute].Attribute = &data.AttributeComponent{
110 | Speed: 10,
111 | HP: 100,
112 | MaxHP: 100,
113 | }
114 | components[data.ComponentType_Move].Move = &data.MoveComponent{
115 | Destination: &engine.Vector3{},
116 | }
117 | components[data.ComponentType_Controller].Controller = &data.ControllerComponent{
118 | ControllerType: data.ControllerType_PlayerController,
119 | }
120 | components[data.ComponentType_Reborn].Reborn = &data.RebornComponent{
121 | RebornTime: 0,
122 | RebornType: data.RebornType_Auto,
123 | }
124 | break
125 | default:
126 | break
127 | }
128 | return components
129 | }
130 |
--------------------------------------------------------------------------------
/src/services/innet/receiver.go:
--------------------------------------------------------------------------------
1 | package innet
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/common/logger"
6 | "INServer/src/proto/msg"
7 | "encoding/binary"
8 | "net"
9 |
10 | "github.com/gogo/protobuf/proto"
11 | )
12 |
13 | type (
14 | serverPackageCache struct {
15 | currentUniqueID uint64
16 | packages map[uint64]map[int32]*msg.Package
17 | }
18 | receiver struct {
19 | innet *INNet
20 | packageCache map[int32]*serverPackageCache
21 | }
22 | )
23 |
24 | func newReceiver(innet *INNet) *receiver {
25 | r := new(receiver)
26 | r.innet = innet
27 | r.packageCache = make(map[int32]*serverPackageCache)
28 | return r
29 | }
30 |
31 | func (r *receiver) start() {
32 | go r.receiveLoop()
33 | }
34 |
35 | func (r *receiver) receiveLoop() {
36 | conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: int(global.CurrentServerID) + recvport})
37 | if err != nil {
38 | logger.Fatal(err)
39 | }
40 | var buf = make([]byte, 65536)
41 | current := 0
42 | var udpaddr *net.UDPAddr
43 | for {
44 | // 等待读取数据长度
45 | for current < 2 {
46 | n, addr, _ := conn.ReadFromUDP(buf[current:])
47 | udpaddr = addr
48 | current = current + n
49 | }
50 |
51 | // 等待读取数据
52 | size := binary.BigEndian.Uint16(buf[:2])
53 | for (current - 2) < int(size) {
54 | n, _ := conn.Read(buf[current:])
55 | current = current + n
56 | }
57 |
58 | pkg := &msg.Package{}
59 | proto.Unmarshal(buf[2:size+2], pkg)
60 | r.innet.retry.handlePackageReceive(pkg)
61 | if pkg.Buffer != nil {
62 | port := udpaddr.Port + recvport - sendport
63 | addr := &net.UDPAddr{IP: udpaddr.IP, Port: port}
64 | r.innet.sender.ack(addr, pkg)
65 | r.handlePackage(pkg)
66 | }
67 |
68 | copy(buf[0:], buf[size+2:current])
69 | current = current - int(size) - 2
70 | }
71 | }
72 |
73 | func (r *receiver) handlePackage(pkg *msg.Package) {
74 | if _, ok := r.packageCache[pkg.From]; ok == false {
75 | r.packageCache[pkg.From] = new(serverPackageCache)
76 | r.packageCache[pkg.From].packages = make(map[uint64]map[int32]*msg.Package)
77 | r.packageCache[pkg.From].currentUniqueID = 1
78 | }
79 | packages := r.packageCache[pkg.From]
80 |
81 | // 如果收到的UniqueID为0直接处理,因为这是服务器启动后的第一个包
82 | if pkg.UniqueID == 0 {
83 | msg := &msg.Message{}
84 | proto.Unmarshal(pkg.Buffer, msg)
85 | r.innet.pushToMessageChan(msg)
86 | } else if pkg.UniqueID >= packages.currentUniqueID {
87 | if _, ok := packages.packages[pkg.UniqueID]; ok == false {
88 | packages.packages[pkg.UniqueID] = make(map[int32]*msg.Package)
89 | }
90 | sequencePackages := packages.packages[pkg.UniqueID]
91 | if _, ok := sequencePackages[pkg.Index]; ok == false {
92 | sequencePackages[pkg.Index] = pkg
93 | if len(sequencePackages) == int(pkg.Total) && pkg.UniqueID == packages.currentUniqueID {
94 | r.onPackagesReceiveFinished(sequencePackages)
95 | delete(packages.packages, packages.currentUniqueID)
96 | packages.currentUniqueID++
97 | r.testCurrentPackages(packages)
98 | }
99 | }
100 | }
101 | }
102 |
103 | func (r *receiver) resetServer(serverID int32) {
104 | if _, ok := r.packageCache[serverID]; ok {
105 | delete(r.packageCache, serverID)
106 | }
107 | }
108 |
109 | func (r *receiver) testCurrentPackages(serverPackages *serverPackageCache) {
110 | if packages, ok := serverPackages.packages[serverPackages.currentUniqueID]; ok {
111 | for _, packageCache := range packages {
112 | if packageCache.Total == int32(len(packages)) {
113 | r.onPackagesReceiveFinished(packages)
114 | delete(serverPackages.packages, serverPackages.currentUniqueID)
115 | serverPackages.currentUniqueID++
116 | r.testCurrentPackages(serverPackages)
117 | }
118 | break
119 | }
120 | }
121 | }
122 |
123 | func (r *receiver) onPackagesReceiveFinished(packages map[int32]*msg.Package) {
124 | var buffer []byte
125 | for index := int32(0); index < int32(len(packages)); index++ {
126 | buffer = append(buffer, packages[index].Buffer...)
127 | }
128 | msg := &msg.Message{}
129 | proto.Unmarshal(buffer, msg)
130 | r.innet.pushToMessageChan(msg)
131 | }
132 |
--------------------------------------------------------------------------------
/src/gameplay/gamemap/gamemap.go:
--------------------------------------------------------------------------------
1 | package gamemap
2 |
3 | import (
4 | "INServer/src/gameplay/ecs"
5 | "INServer/src/gameplay/ecs/system"
6 | "INServer/src/proto/config"
7 | "INServer/src/proto/data"
8 | "INServer/src/proto/engine"
9 | "INServer/src/proto/msg"
10 | "time"
11 | )
12 |
13 | type (
14 | ComponentValueCache struct {
15 | position engine.Vector3
16 | }
17 |
18 | Map struct {
19 | mapData *data.MapData
20 | mapConfig *config.Map
21 | scenes []*Scene
22 |
23 | firstScene *Scene
24 | entitiesMap map[string]*ecs.Entity
25 | running bool
26 | }
27 | )
28 |
29 | func NewMap(mapConfig *config.Map, mapData *data.MapData) *Map {
30 | m := new(Map)
31 | m.scenes = make([]*Scene, 0)
32 | m.firstScene = NewScene(m, nil)
33 | m.scenes = append(m.scenes, m.firstScene)
34 | m.mapData = mapData
35 | m.mapConfig = mapConfig
36 | m.entitiesMap = make(map[string]*ecs.Entity)
37 | if m.mapData == nil {
38 | m.mapData = &data.MapData{
39 | MapID: mapConfig.MapID,
40 | MapUUID: mapData.MapUUID,
41 | Entities: make([]*data.EntityData, 0),
42 | }
43 | }
44 | return m
45 | }
46 |
47 | func (m *Map) MapData() *data.MapData {
48 | return m.mapData
49 | }
50 |
51 | func (m *Map) MapConfig() *config.Map {
52 | return m.mapConfig
53 | }
54 |
55 | func (m *Map) Scenes() []*Scene {
56 | return m.scenes
57 | }
58 |
59 | func (m *Map) GetEntity(uuid string) *ecs.Entity {
60 | if entity, ok := m.entitiesMap[uuid]; ok {
61 | return entity
62 | }
63 | return nil
64 | }
65 |
66 | func (m *Map) Start() {
67 | m.running = true
68 | if m.mapData.LastTickTime == 0 {
69 | m.mapData.LastTickTime = time.Now().UnixNano()
70 | }
71 | go func() {
72 | for m.running {
73 | lasttime := m.mapData.LastTickTime
74 | now := time.Now().UnixNano()
75 | dt := float64(now-lasttime) / float64(1E9)
76 |
77 | m.tickSystems(dt)
78 |
79 | time.Sleep(time.Millisecond * 33)
80 | }
81 | }()
82 | }
83 |
84 | func (m *Map) EntityEnter(uuid string, entity *ecs.Entity) {
85 | m.mapData.Entities = append(m.mapData.Entities, entity.EntityData())
86 | m.entitiesMap[uuid] = entity
87 | m.firstScene.EntityEnter(uuid, entity)
88 | }
89 |
90 | func (m *Map) EntityLeave(uuid string) {
91 | if entity, ok := m.entitiesMap[uuid]; ok {
92 | m.firstScene.EntityLeave(uuid, entity)
93 | delete(m.entitiesMap, uuid)
94 | for index, entityData := range m.mapData.Entities {
95 | if entityData.EntityUUID == uuid {
96 | m.mapData.Entities = append(m.mapData.Entities[:index], m.mapData.Entities[index+1:]...)
97 | break
98 | }
99 | }
100 | }
101 | }
102 |
103 | func (m *Map) Tick() {
104 | for _, scene := range m.scenes {
105 | scene.Tick()
106 | }
107 | }
108 |
109 | func (m *Map) tickSystems(dt float64) {
110 | cachedValues := make(map[string]*ComponentValueCache)
111 | for uuid, entity := range m.entitiesMap {
112 | cache := &ComponentValueCache{}
113 | cachedValues[uuid] = cache
114 | transform := entity.GetComponent(data.ComponentType_Transofrm).Transform
115 | if transform != nil {
116 | cache.position = *transform.Position
117 | }
118 | }
119 | system.Tick(dt, m.entitiesMap)
120 | for uuid, entity := range m.entitiesMap {
121 | transform := entity.GetComponent(data.ComponentType_Transofrm).Transform
122 | if transform != nil {
123 | m.firstScene.SyncEntityPosition(uuid, entity, &cachedValues[uuid].position)
124 | }
125 | }
126 | }
127 |
128 | // OnRoleMoveINF 响应角色移动
129 | func (m *Map) OnRoleMoveINF(role *data.Role, inf *msg.MoveINF) {
130 | entity := m.GetEntity(role.SummaryData.RoleUUID)
131 | if entity != nil {
132 | m.firstScene.onEntityMoveINF(entity, inf)
133 | }
134 | }
135 |
136 | // OnRoleStopMoveINF 响应角色停止移动
137 | func (m *Map) OnRoleStopMoveINF(role *data.Role, inf *msg.StopMoveINF) {
138 | entity := m.GetEntity(role.SummaryData.RoleUUID)
139 | if entity != nil {
140 | m.firstScene.onEntityStopMoveINF(entity, inf)
141 | }
142 | }
143 |
144 | // FillEntityData 填充实体信息
145 | func (m *Map) FillEntityData(uuids []string, resp *msg.EntityDataRes) {
146 | for _, uuid := range uuids {
147 | if entity, ok := m.entitiesMap[uuid]; ok {
148 | resp.Entities = append(resp.Entities, entity.EntityData())
149 | }
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/proto/protobuf/wrappers.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | // Wrappers for primitive (non-message) types. These types are useful
32 | // for embedding primitives in the `google.protobuf.Any` type and for places
33 | // where we need to distinguish between the absence of a primitive
34 | // typed field and its default value.
35 | //
36 | // These wrappers have no meaningful use within repeated fields as they lack
37 | // the ability to detect presence on individual elements.
38 | // These wrappers have no meaningful use within a map or a oneof since
39 | // individual entries of a map or fields of a oneof can already detect presence.
40 |
41 | syntax = "proto3";
42 |
43 | package google.protobuf;
44 |
45 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
46 | option cc_enable_arenas = true;
47 | option go_package = "types";
48 | option java_package = "com.google.protobuf";
49 | option java_outer_classname = "WrappersProto";
50 | option java_multiple_files = true;
51 | option objc_class_prefix = "GPB";
52 |
53 | // Wrapper message for `double`.
54 | //
55 | // The JSON representation for `DoubleValue` is JSON number.
56 | message DoubleValue {
57 | // The double value.
58 | double value = 1;
59 | }
60 |
61 | // Wrapper message for `float`.
62 | //
63 | // The JSON representation for `FloatValue` is JSON number.
64 | message FloatValue {
65 | // The float value.
66 | float value = 1;
67 | }
68 |
69 | // Wrapper message for `int64`.
70 | //
71 | // The JSON representation for `Int64Value` is JSON string.
72 | message Int64Value {
73 | // The int64 value.
74 | int64 value = 1;
75 | }
76 |
77 | // Wrapper message for `uint64`.
78 | //
79 | // The JSON representation for `UInt64Value` is JSON string.
80 | message UInt64Value {
81 | // The uint64 value.
82 | uint64 value = 1;
83 | }
84 |
85 | // Wrapper message for `int32`.
86 | //
87 | // The JSON representation for `Int32Value` is JSON number.
88 | message Int32Value {
89 | // The int32 value.
90 | int32 value = 1;
91 | }
92 |
93 | // Wrapper message for `uint32`.
94 | //
95 | // The JSON representation for `UInt32Value` is JSON number.
96 | message UInt32Value {
97 | // The uint32 value.
98 | uint32 value = 1;
99 | }
100 |
101 | // Wrapper message for `bool`.
102 | //
103 | // The JSON representation for `BoolValue` is JSON `true` and `false`.
104 | message BoolValue {
105 | // The bool value.
106 | bool value = 1;
107 | }
108 |
109 | // Wrapper message for `string`.
110 | //
111 | // The JSON representation for `StringValue` is JSON string.
112 | message StringValue {
113 | // The string value.
114 | string value = 1;
115 | }
116 |
117 | // Wrapper message for `bytes`.
118 | //
119 | // The JSON representation for `BytesValue` is JSON string.
120 | message BytesValue {
121 | // The bytes value.
122 | bytes value = 1;
123 | }
124 |
--------------------------------------------------------------------------------
/src/services/gps/gps.go:
--------------------------------------------------------------------------------
1 | package gps
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/common/logger"
6 | "INServer/src/proto/data"
7 | "INServer/src/proto/msg"
8 | "INServer/src/services/node"
9 | "fmt"
10 |
11 | "github.com/gogo/protobuf/proto"
12 | )
13 |
14 | var Instance *GPS
15 |
16 | type (
17 | role struct {
18 | address *data.RoleAddress
19 | uuid string
20 | }
21 |
22 | // GPS 定位服务器 可以查询每个地图和每个角色的位置
23 | GPS struct {
24 | maps map[string]int32
25 | roles map[string]*role
26 | staticmaps map[int32]map[int32]string
27 | }
28 | )
29 |
30 | // New 创建定位服务器
31 | func New() *GPS {
32 | g := new(GPS)
33 | g.maps = make(map[string]int32)
34 | g.roles = make(map[string]*role)
35 | g.staticmaps = make(map[int32]map[int32]string)
36 | return g
37 | }
38 |
39 | // Start 启动定位服务器
40 | func (g *GPS) Start() {
41 | g.initMessageHandler()
42 | }
43 |
44 | func (g *GPS) initMessageHandler() {
45 | node.Net.Listen(msg.CMD_UPDATE_ROLE_ADDRESS_NTF, g.HANDLE_UPDATE_ROLE_ADDRESS_NTF)
46 | node.Net.Listen(msg.CMD_REMOVE_ROLE_ADDRESS_NTF, g.HANDLE_REMOVE_ROLE_ADDRESS_NTF)
47 | node.Net.Listen(msg.CMD_UPDATE_MAP_ADDRESS_NTF, g.onUpdateMapAddressNTF)
48 | node.Net.Listen(msg.CMD_REMOVE_MAP_ADDRESS_NTF, g.onRemoveMapAddressNTF)
49 | node.Net.Listen(msg.CMD_GET_MAP_ADDRESS_REQ, g.onGetMapLocationReq)
50 | node.Net.Listen(msg.CMD_UPDATE_STATIC_MAP_UUID_NTF, g.onUpdateStaticMapUUIDNTF)
51 | node.Net.Listen(msg.CMD_GET_STATIC_MAP_UUID_REQ, g.onGetStaticMapUUIDReq)
52 | }
53 |
54 | func (g *GPS) HANDLE_UPDATE_ROLE_ADDRESS_NTF(header *msg.MessageHeader, buffer []byte) {
55 | ntf := &msg.UpdateRoleAddressNTF{}
56 | err := proto.Unmarshal(buffer, ntf)
57 | if err != nil {
58 | logger.Error(err)
59 | return
60 | }
61 | if len(ntf.RoleUUID) > 0 {
62 | if _, ok := g.roles[ntf.RoleUUID]; ok == false {
63 | address := &data.RoleAddress{
64 | Gate: global.InvalidServerID,
65 | World: global.InvalidServerID,
66 | }
67 | g.roles[ntf.RoleUUID] = &role{
68 | address: address,
69 | }
70 |
71 | }
72 | if ntf.Address.Gate != global.InvalidServerID {
73 | g.roles[ntf.RoleUUID].address.Gate = ntf.Address.Gate
74 | }
75 | if ntf.Address.World != global.InvalidServerID {
76 | g.roles[ntf.RoleUUID].address.World = ntf.Address.World
77 | }
78 | } else {
79 | logger.Error("Empty RoleUUID")
80 | }
81 | node.Net.NotifyServer(msg.CMD_UPDATE_ROLE_ADDRESS_NTF, ntf, g.roles[ntf.RoleUUID].address.Gate)
82 | }
83 |
84 | func (g *GPS) HANDLE_REMOVE_ROLE_ADDRESS_NTF(header *msg.MessageHeader, buffer []byte) {
85 | ntf := &msg.RemoveRoleAddressNTF{}
86 | proto.Unmarshal(buffer, ntf)
87 | if r, ok := g.roles[ntf.RoleUUID]; ok {
88 | if _, ok := g.roles[r.uuid]; ok {
89 | delete(g.roles, r.uuid)
90 | }
91 | }
92 | }
93 |
94 | func (g *GPS) onUpdateMapAddressNTF(header *msg.MessageHeader, buffer []byte) {
95 | ntf := &msg.UpdateMapAddressNTF{}
96 | err := proto.Unmarshal(buffer, ntf)
97 | if err != nil {
98 | logger.Error(err)
99 | } else {
100 | g.maps[ntf.MapUUID] = ntf.ServerID
101 | logger.Info(fmt.Sprintf("MapAddress UUID:%s ServerID:%d", ntf.MapUUID, ntf.ServerID))
102 | }
103 | }
104 |
105 | func (g *GPS) onUpdateStaticMapUUIDNTF(header *msg.MessageHeader, buffer []byte) {
106 | ntf := &msg.UpdateStaticMapUUIDNTF{}
107 | err := proto.Unmarshal(buffer, ntf)
108 | if err != nil {
109 | logger.Error(err)
110 | } else {
111 | if _, ok := g.staticmaps[ntf.ZoneID]; ok == false {
112 | g.staticmaps[ntf.ZoneID] = make(map[int32]string)
113 | }
114 | g.staticmaps[ntf.ZoneID][ntf.StaticMapID] = ntf.StaticMapUUID
115 | logger.Info(fmt.Sprintf("StaticMap ZoneID:%d StaticMapID:%d UUID:%s", ntf.ZoneID, ntf.StaticMapID, ntf.StaticMapUUID))
116 | }
117 | }
118 |
119 | func (g *GPS) onGetStaticMapUUIDReq(header *msg.MessageHeader, buffer []byte) {
120 | resp := &msg.GetStaticMapUUIDResp{}
121 | defer node.Net.Responce(header, resp)
122 | req := &msg.GetStaticMapUUIDReq{}
123 | err := proto.Unmarshal(buffer, req)
124 | if err != nil {
125 | logger.Error(err)
126 | } else {
127 | if maps, ok := g.staticmaps[req.ZoneID]; ok {
128 | if uuid, ok := maps[req.StaticMapID]; ok {
129 | resp.StaticMapUUID = uuid
130 | }
131 | }
132 | }
133 | }
134 |
135 | func (g *GPS) onRemoveMapAddressNTF(header *msg.MessageHeader, buffer []byte) {
136 | ntf := &msg.RemoveMapAddressNTF{}
137 | proto.Unmarshal(buffer, ntf)
138 | delete(g.maps, ntf.MapUUID)
139 | }
140 |
141 | func (g *GPS) onGetMapLocationReq(header *msg.MessageHeader, buffer []byte) {
142 | resp := &msg.GetMapAddressResp{
143 | ServerID: global.InvalidServerID,
144 | }
145 | defer node.Net.Responce(header, resp)
146 | req := &msg.GetMapAddressReq{}
147 | err := proto.Unmarshal(buffer, req)
148 | if err != nil {
149 | logger.Error(err)
150 | return
151 | }
152 | if serverID, ok := g.maps[req.MapUUID]; ok {
153 | resp.ServerID = serverID
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/proto/protobuf/duration.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option cc_enable_arenas = true;
37 | option go_package = "types";
38 | option java_package = "com.google.protobuf";
39 | option java_outer_classname = "DurationProto";
40 | option java_multiple_files = true;
41 | option objc_class_prefix = "GPB";
42 |
43 | // A Duration represents a signed, fixed-length span of time represented
44 | // as a count of seconds and fractions of seconds at nanosecond
45 | // resolution. It is independent of any calendar and concepts like "day"
46 | // or "month". It is related to Timestamp in that the difference between
47 | // two Timestamp values is a Duration and it can be added or subtracted
48 | // from a Timestamp. Range is approximately +-10,000 years.
49 | //
50 | // # Examples
51 | //
52 | // Example 1: Compute Duration from two Timestamps in pseudo code.
53 | //
54 | // Timestamp start = ...;
55 | // Timestamp end = ...;
56 | // Duration duration = ...;
57 | //
58 | // duration.seconds = end.seconds - start.seconds;
59 | // duration.nanos = end.nanos - start.nanos;
60 | //
61 | // if (duration.seconds < 0 && duration.nanos > 0) {
62 | // duration.seconds += 1;
63 | // duration.nanos -= 1000000000;
64 | // } else if (durations.seconds > 0 && duration.nanos < 0) {
65 | // duration.seconds -= 1;
66 | // duration.nanos += 1000000000;
67 | // }
68 | //
69 | // Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
70 | //
71 | // Timestamp start = ...;
72 | // Duration duration = ...;
73 | // Timestamp end = ...;
74 | //
75 | // end.seconds = start.seconds + duration.seconds;
76 | // end.nanos = start.nanos + duration.nanos;
77 | //
78 | // if (end.nanos < 0) {
79 | // end.seconds -= 1;
80 | // end.nanos += 1000000000;
81 | // } else if (end.nanos >= 1000000000) {
82 | // end.seconds += 1;
83 | // end.nanos -= 1000000000;
84 | // }
85 | //
86 | // Example 3: Compute Duration from datetime.timedelta in Python.
87 | //
88 | // td = datetime.timedelta(days=3, minutes=10)
89 | // duration = Duration()
90 | // duration.FromTimedelta(td)
91 | //
92 | // # JSON Mapping
93 | //
94 | // In JSON format, the Duration type is encoded as a string rather than an
95 | // object, where the string ends in the suffix "s" (indicating seconds) and
96 | // is preceded by the number of seconds, with nanoseconds expressed as
97 | // fractional seconds. For example, 3 seconds with 0 nanoseconds should be
98 | // encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
99 | // be expressed in JSON format as "3.000000001s", and 3 seconds and 1
100 | // microsecond should be expressed in JSON format as "3.000001s".
101 | //
102 | //
103 | message Duration {
104 | // Signed seconds of the span of time. Must be from -315,576,000,000
105 | // to +315,576,000,000 inclusive. Note: these bounds are computed from:
106 | // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
107 | int64 seconds = 1;
108 |
109 | // Signed fractions of a second at nanosecond resolution of the span
110 | // of time. Durations less than one second are represented with a 0
111 | // `seconds` field and a positive or negative `nanos` field. For durations
112 | // of one second or more, a non-zero value for the `nanos` field must be
113 | // of the same sign as the `seconds` field. Must be from -999,999,999
114 | // to +999,999,999 inclusive.
115 | int32 nanos = 2;
116 | }
117 |
--------------------------------------------------------------------------------
/proto/gogoproto/gogo.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers for Go with Gadgets
2 | //
3 | // Copyright (c) 2013, The GoGo Authors. All rights reserved.
4 | // http://github.com/gogo/protobuf
5 | //
6 | // Redistribution and use in source and binary forms, with or without
7 | // modification, are permitted provided that the following conditions are
8 | // met:
9 | //
10 | // * Redistributions of source code must retain the above copyright
11 | // notice, this list of conditions and the following disclaimer.
12 | // * Redistributions in binary form must reproduce the above
13 | // copyright notice, this list of conditions and the following disclaimer
14 | // in the documentation and/or other materials provided with the
15 | // distribution.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | syntax = "proto2";
30 | package gogoproto;
31 |
32 | import "descriptor.proto";
33 |
34 | option java_package = "com.google.protobuf";
35 | option java_outer_classname = "GoGoProtos";
36 | option go_package = "github.com/gogo/protobuf/gogoproto";
37 |
38 | extend google.protobuf.EnumOptions {
39 | optional bool goproto_enum_prefix = 62001;
40 | optional bool goproto_enum_stringer = 62021;
41 | optional bool enum_stringer = 62022;
42 | optional string enum_customname = 62023;
43 | optional bool enumdecl = 62024;
44 | }
45 |
46 | extend google.protobuf.EnumValueOptions {
47 | optional string enumvalue_customname = 66001;
48 | }
49 |
50 | extend google.protobuf.FileOptions {
51 | optional bool goproto_getters_all = 63001;
52 | optional bool goproto_enum_prefix_all = 63002;
53 | optional bool goproto_stringer_all = 63003;
54 | optional bool verbose_equal_all = 63004;
55 | optional bool face_all = 63005;
56 | optional bool gostring_all = 63006;
57 | optional bool populate_all = 63007;
58 | optional bool stringer_all = 63008;
59 | optional bool onlyone_all = 63009;
60 |
61 | optional bool equal_all = 63013;
62 | optional bool description_all = 63014;
63 | optional bool testgen_all = 63015;
64 | optional bool benchgen_all = 63016;
65 | optional bool marshaler_all = 63017;
66 | optional bool unmarshaler_all = 63018;
67 | optional bool stable_marshaler_all = 63019;
68 |
69 | optional bool sizer_all = 63020;
70 |
71 | optional bool goproto_enum_stringer_all = 63021;
72 | optional bool enum_stringer_all = 63022;
73 |
74 | optional bool unsafe_marshaler_all = 63023;
75 | optional bool unsafe_unmarshaler_all = 63024;
76 |
77 | optional bool goproto_extensions_map_all = 63025;
78 | optional bool goproto_unrecognized_all = 63026;
79 | optional bool gogoproto_import = 63027;
80 | optional bool protosizer_all = 63028;
81 | optional bool compare_all = 63029;
82 | optional bool typedecl_all = 63030;
83 | optional bool enumdecl_all = 63031;
84 |
85 | optional bool goproto_registration = 63032;
86 | optional bool messagename_all = 63033;
87 |
88 | optional bool goproto_sizecache_all = 63034;
89 | optional bool goproto_unkeyed_all = 63035;
90 | }
91 |
92 | extend google.protobuf.MessageOptions {
93 | optional bool goproto_getters = 64001;
94 | optional bool goproto_stringer = 64003;
95 | optional bool verbose_equal = 64004;
96 | optional bool face = 64005;
97 | optional bool gostring = 64006;
98 | optional bool populate = 64007;
99 | optional bool stringer = 67008;
100 | optional bool onlyone = 64009;
101 |
102 | optional bool equal = 64013;
103 | optional bool description = 64014;
104 | optional bool testgen = 64015;
105 | optional bool benchgen = 64016;
106 | optional bool marshaler = 64017;
107 | optional bool unmarshaler = 64018;
108 | optional bool stable_marshaler = 64019;
109 |
110 | optional bool sizer = 64020;
111 |
112 | optional bool unsafe_marshaler = 64023;
113 | optional bool unsafe_unmarshaler = 64024;
114 |
115 | optional bool goproto_extensions_map = 64025;
116 | optional bool goproto_unrecognized = 64026;
117 |
118 | optional bool protosizer = 64028;
119 | optional bool compare = 64029;
120 |
121 | optional bool typedecl = 64030;
122 |
123 | optional bool messagename = 64033;
124 |
125 | optional bool goproto_sizecache = 64034;
126 | optional bool goproto_unkeyed = 64035;
127 | }
128 |
129 | extend google.protobuf.FieldOptions {
130 | optional bool nullable = 65001;
131 | optional bool embed = 65002;
132 | optional string customtype = 65003;
133 | optional string customname = 65004;
134 | optional string jsontag = 65005;
135 | optional string moretags = 65006;
136 | optional string casttype = 65007;
137 | optional string castkey = 65008;
138 | optional string castvalue = 65009;
139 |
140 | optional bool stdtime = 65010;
141 | optional bool stdduration = 65011;
142 | optional bool wktpointer = 65012;
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/src/proto/etc/etc.servers.pb.json.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go-json. DO NOT EDIT.
2 | // source: etc.servers.proto
3 |
4 | package etc
5 |
6 | import (
7 | "bytes"
8 |
9 | "github.com/golang/protobuf/jsonpb"
10 | )
11 |
12 | // MarshalJSON implements json.Marshaler
13 | func (msg *GateConfig) MarshalJSON() ([]byte, error) {
14 | var buf bytes.Buffer
15 | err := (&jsonpb.Marshaler{
16 | EnumsAsInts: false,
17 | EmitDefaults: false,
18 | OrigName: false,
19 | }).Marshal(&buf, msg)
20 | return buf.Bytes(), err
21 | }
22 |
23 | // UnmarshalJSON implements json.Unmarshaler
24 | func (msg *GateConfig) UnmarshalJSON(b []byte) error {
25 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
26 | }
27 |
28 | // MarshalJSON implements json.Marshaler
29 | func (msg *LoginConfig) MarshalJSON() ([]byte, error) {
30 | var buf bytes.Buffer
31 | err := (&jsonpb.Marshaler{
32 | EnumsAsInts: false,
33 | EmitDefaults: false,
34 | OrigName: false,
35 | }).Marshal(&buf, msg)
36 | return buf.Bytes(), err
37 | }
38 |
39 | // UnmarshalJSON implements json.Unmarshaler
40 | func (msg *LoginConfig) UnmarshalJSON(b []byte) error {
41 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
42 | }
43 |
44 | // MarshalJSON implements json.Marshaler
45 | func (msg *ChatConfig) MarshalJSON() ([]byte, error) {
46 | var buf bytes.Buffer
47 | err := (&jsonpb.Marshaler{
48 | EnumsAsInts: false,
49 | EmitDefaults: false,
50 | OrigName: false,
51 | }).Marshal(&buf, msg)
52 | return buf.Bytes(), err
53 | }
54 |
55 | // UnmarshalJSON implements json.Unmarshaler
56 | func (msg *ChatConfig) UnmarshalJSON(b []byte) error {
57 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
58 | }
59 |
60 | // MarshalJSON implements json.Marshaler
61 | func (msg *DatabaseConfig) MarshalJSON() ([]byte, error) {
62 | var buf bytes.Buffer
63 | err := (&jsonpb.Marshaler{
64 | EnumsAsInts: false,
65 | EmitDefaults: false,
66 | OrigName: false,
67 | }).Marshal(&buf, msg)
68 | return buf.Bytes(), err
69 | }
70 |
71 | // UnmarshalJSON implements json.Unmarshaler
72 | func (msg *DatabaseConfig) UnmarshalJSON(b []byte) error {
73 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
74 | }
75 |
76 | // MarshalJSON implements json.Marshaler
77 | func (msg *WebConfig) MarshalJSON() ([]byte, error) {
78 | var buf bytes.Buffer
79 | err := (&jsonpb.Marshaler{
80 | EnumsAsInts: false,
81 | EmitDefaults: false,
82 | OrigName: false,
83 | }).Marshal(&buf, msg)
84 | return buf.Bytes(), err
85 | }
86 |
87 | // UnmarshalJSON implements json.Unmarshaler
88 | func (msg *WebConfig) UnmarshalJSON(b []byte) error {
89 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
90 | }
91 |
92 | // MarshalJSON implements json.Marshaler
93 | func (msg *ZoneWorld) MarshalJSON() ([]byte, error) {
94 | var buf bytes.Buffer
95 | err := (&jsonpb.Marshaler{
96 | EnumsAsInts: false,
97 | EmitDefaults: false,
98 | OrigName: false,
99 | }).Marshal(&buf, msg)
100 | return buf.Bytes(), err
101 | }
102 |
103 | // UnmarshalJSON implements json.Unmarshaler
104 | func (msg *ZoneWorld) UnmarshalJSON(b []byte) error {
105 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
106 | }
107 |
108 | // MarshalJSON implements json.Marshaler
109 | func (msg *WorldConfig) MarshalJSON() ([]byte, error) {
110 | var buf bytes.Buffer
111 | err := (&jsonpb.Marshaler{
112 | EnumsAsInts: false,
113 | EmitDefaults: false,
114 | OrigName: false,
115 | }).Marshal(&buf, msg)
116 | return buf.Bytes(), err
117 | }
118 |
119 | // UnmarshalJSON implements json.Unmarshaler
120 | func (msg *WorldConfig) UnmarshalJSON(b []byte) error {
121 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
122 | }
123 |
124 | // MarshalJSON implements json.Marshaler
125 | func (msg *AIConfig) MarshalJSON() ([]byte, error) {
126 | var buf bytes.Buffer
127 | err := (&jsonpb.Marshaler{
128 | EnumsAsInts: false,
129 | EmitDefaults: false,
130 | OrigName: false,
131 | }).Marshal(&buf, msg)
132 | return buf.Bytes(), err
133 | }
134 |
135 | // UnmarshalJSON implements json.Unmarshaler
136 | func (msg *AIConfig) UnmarshalJSON(b []byte) error {
137 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
138 | }
139 |
140 | // MarshalJSON implements json.Marshaler
141 | func (msg *RobotConfig) MarshalJSON() ([]byte, error) {
142 | var buf bytes.Buffer
143 | err := (&jsonpb.Marshaler{
144 | EnumsAsInts: false,
145 | EmitDefaults: false,
146 | OrigName: false,
147 | }).Marshal(&buf, msg)
148 | return buf.Bytes(), err
149 | }
150 |
151 | // UnmarshalJSON implements json.Unmarshaler
152 | func (msg *RobotConfig) UnmarshalJSON(b []byte) error {
153 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
154 | }
155 |
156 | // MarshalJSON implements json.Marshaler
157 | func (msg *ServerConfig) MarshalJSON() ([]byte, error) {
158 | var buf bytes.Buffer
159 | err := (&jsonpb.Marshaler{
160 | EnumsAsInts: false,
161 | EmitDefaults: false,
162 | OrigName: false,
163 | }).Marshal(&buf, msg)
164 | return buf.Bytes(), err
165 | }
166 |
167 | // UnmarshalJSON implements json.Unmarshaler
168 | func (msg *ServerConfig) UnmarshalJSON(b []byte) error {
169 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
170 | }
171 |
172 | // MarshalJSON implements json.Marshaler
173 | func (msg *Server) MarshalJSON() ([]byte, error) {
174 | var buf bytes.Buffer
175 | err := (&jsonpb.Marshaler{
176 | EnumsAsInts: false,
177 | EmitDefaults: false,
178 | OrigName: false,
179 | }).Marshal(&buf, msg)
180 | return buf.Bytes(), err
181 | }
182 |
183 | // UnmarshalJSON implements json.Unmarshaler
184 | func (msg *Server) UnmarshalJSON(b []byte) error {
185 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
186 | }
187 |
188 | // MarshalJSON implements json.Marshaler
189 | func (msg *ServerList) MarshalJSON() ([]byte, error) {
190 | var buf bytes.Buffer
191 | err := (&jsonpb.Marshaler{
192 | EnumsAsInts: false,
193 | EmitDefaults: false,
194 | OrigName: false,
195 | }).Marshal(&buf, msg)
196 | return buf.Bytes(), err
197 | }
198 |
199 | // UnmarshalJSON implements json.Unmarshaler
200 | func (msg *ServerList) UnmarshalJSON(b []byte) error {
201 | return jsonpb.Unmarshal(bytes.NewReader(b), msg)
202 | }
203 |
--------------------------------------------------------------------------------
/proto/protobuf/any.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option go_package = "types";
37 | option java_package = "com.google.protobuf";
38 | option java_outer_classname = "AnyProto";
39 | option java_multiple_files = true;
40 | option objc_class_prefix = "GPB";
41 |
42 | // `Any` contains an arbitrary serialized protocol buffer message along with a
43 | // URL that describes the type of the serialized message.
44 | //
45 | // Protobuf library provides support to pack/unpack Any values in the form
46 | // of utility functions or additional generated methods of the Any type.
47 | //
48 | // Example 1: Pack and unpack a message in C++.
49 | //
50 | // Foo foo = ...;
51 | // Any any;
52 | // any.PackFrom(foo);
53 | // ...
54 | // if (any.UnpackTo(&foo)) {
55 | // ...
56 | // }
57 | //
58 | // Example 2: Pack and unpack a message in Java.
59 | //
60 | // Foo foo = ...;
61 | // Any any = Any.pack(foo);
62 | // ...
63 | // if (any.is(Foo.class)) {
64 | // foo = any.unpack(Foo.class);
65 | // }
66 | //
67 | // Example 3: Pack and unpack a message in Python.
68 | //
69 | // foo = Foo(...)
70 | // any = Any()
71 | // any.Pack(foo)
72 | // ...
73 | // if any.Is(Foo.DESCRIPTOR):
74 | // any.Unpack(foo)
75 | // ...
76 | //
77 | // Example 4: Pack and unpack a message in Go
78 | //
79 | // foo := &pb.Foo{...}
80 | // any, err := ptypes.MarshalAny(foo)
81 | // ...
82 | // foo := &pb.Foo{}
83 | // if err := ptypes.UnmarshalAny(any, foo); err != nil {
84 | // ...
85 | // }
86 | //
87 | // The pack methods provided by protobuf library will by default use
88 | // 'type.googleapis.com/full.type.name' as the type URL and the unpack
89 | // methods only use the fully qualified type name after the last '/'
90 | // in the type URL, for example "foo.bar.com/x/y.z" will yield type
91 | // name "y.z".
92 | //
93 | //
94 | // JSON
95 | // ====
96 | // The JSON representation of an `Any` value uses the regular
97 | // representation of the deserialized, embedded message, with an
98 | // additional field `@type` which contains the type URL. Example:
99 | //
100 | // package google.profile;
101 | // message Person {
102 | // string first_name = 1;
103 | // string last_name = 2;
104 | // }
105 | //
106 | // {
107 | // "@type": "type.googleapis.com/google.profile.Person",
108 | // "firstName": ,
109 | // "lastName":
110 | // }
111 | //
112 | // If the embedded message type is well-known and has a custom JSON
113 | // representation, that representation will be embedded adding a field
114 | // `value` which holds the custom JSON in addition to the `@type`
115 | // field. Example (for message [google.protobuf.Duration][]):
116 | //
117 | // {
118 | // "@type": "type.googleapis.com/google.protobuf.Duration",
119 | // "value": "1.212s"
120 | // }
121 | //
122 | message Any {
123 | // A URL/resource name that uniquely identifies the type of the serialized
124 | // protocol buffer message. This string must contain at least
125 | // one "/" character. The last segment of the URL's path must represent
126 | // the fully qualified name of the type (as in
127 | // `path/google.protobuf.Duration`). The name should be in a canonical form
128 | // (e.g., leading "." is not accepted).
129 | //
130 | // In practice, teams usually precompile into the binary all types that they
131 | // expect it to use in the context of Any. However, for URLs which use the
132 | // scheme `http`, `https`, or no scheme, one can optionally set up a type
133 | // server that maps type URLs to message definitions as follows:
134 | //
135 | // * If no scheme is provided, `https` is assumed.
136 | // * An HTTP GET on the URL must yield a [google.protobuf.Type][]
137 | // value in binary format, or produce an error.
138 | // * Applications are allowed to cache lookup results based on the
139 | // URL, or have them precompiled into a binary to avoid any
140 | // lookup. Therefore, binary compatibility needs to be preserved
141 | // on changes to types. (Use versioned type names to manage
142 | // breaking changes.)
143 | //
144 | // Note: this functionality is not currently available in the official
145 | // protobuf release, and it is not used for type URLs beginning with
146 | // type.googleapis.com.
147 | //
148 | // Schemes other than `http`, `https` (or the empty scheme) might be
149 | // used with implementation specific semantics.
150 | //
151 | string type_url = 1;
152 |
153 | // Must be a valid serialized protocol buffer of the above specified type.
154 | bytes value = 2;
155 | }
156 |
--------------------------------------------------------------------------------
/src/services/center/center.go:
--------------------------------------------------------------------------------
1 | package center
2 |
3 | import (
4 | "INServer/src/common/global"
5 | "INServer/src/common/logger"
6 | "INServer/src/proto/msg"
7 | "INServer/src/services/cluster"
8 | "INServer/src/services/etcmgr"
9 | "INServer/src/services/innet"
10 | "fmt"
11 | "os"
12 | "time"
13 |
14 | "github.com/golang/protobuf/proto"
15 | )
16 |
17 | // Instance 中心服务器的单例
18 | var Instance *Center
19 |
20 | const (
21 | timeout = 2000 * 1E6 // 纳秒
22 | )
23 |
24 | type (
25 | // Center 中心服务器
26 | Center struct {
27 | Net *innet.INNet
28 | keepAliveTime []int64
29 | }
30 | )
31 |
32 | // New 创建中心服务器
33 | func New() *Center {
34 | c := new(Center)
35 | c.Net = innet.New()
36 | c.keepAliveTime = make([]int64, len(etcmgr.Instance.Servers()))
37 | c.tickServerState()
38 | return c
39 | }
40 |
41 | // Start 启动中心服务器
42 | func (c *Center) Start() {
43 | c.Net.Start()
44 | cluster.SetNode(global.CurrentServerID, &msg.Node{
45 | NodeState: msg.NodeState_Running,
46 | NodeAddress: c.Net.IP,
47 | })
48 | c.registerListeners()
49 | logger.Info(fmt.Sprintf("Server Start Type:%s ID:%d", global.CurrentServerType, global.CurrentServerID))
50 | }
51 |
52 | func (c *Center) registerListeners() {
53 | c.Net.Listen(msg.CMD_NODE_START_NTF, c.HANDLE_NODE_START_NTF)
54 | c.Net.Listen(msg.CMD_KEEP_ALIVE, c.HANDLE_KEEP_ALIVE)
55 | c.Net.Listen(msg.CMD_RELOAD_ETC_REQ, c.HANDLE_RELOAD_ETC_REQ)
56 | c.Net.Listen(msg.CMD_NODES_INFO_NTF, c.HANDLE_NODES_INFO_NTF)
57 | }
58 |
59 | // HANDLE_NODE_START_NTF 节点启动
60 | func (c *Center) HANDLE_NODE_START_NTF(header *msg.MessageHeader, buffer []byte) {
61 | if global.PendingExit {
62 | return
63 | }
64 | ntf := &msg.NodeStartNTF{}
65 | err := proto.Unmarshal(buffer, ntf)
66 | if err != nil {
67 | return
68 | }
69 | cluster.SetNode(header.From, &msg.Node{
70 | NodeState: msg.NodeState_Unset,
71 | NodeAddress: ntf.Address,
72 | })
73 | cluster.RefreshRunning()
74 | cluster.RefreshRunningZones()
75 | c.Net.RefreshNodesAddress()
76 | c.Net.ResetServer(header.From)
77 | c.broadcastResetConnectionNTF(header.From)
78 | c.sendETCSyncNTF(header.From)
79 | }
80 |
81 | // HANDLE_NODES_INFO_NTF 每个节点会同步自己的状态过来
82 | func (c *Center) HANDLE_NODES_INFO_NTF(header *msg.MessageHeader, buffer []byte) {
83 | ntf := &msg.NodesInfoNTF{}
84 | err := proto.Unmarshal(buffer, ntf)
85 | if err != nil {
86 | return
87 | }
88 | cluster.SetNodes(ntf.Nodes)
89 | c.Net.RefreshNodesAddress()
90 | c.pushNodesInfo()
91 | }
92 |
93 | func (c *Center) pushNodesInfo() {
94 | nodes := cluster.GetNodes()
95 | ntf := &msg.NodesInfoNTF{Nodes: nodes}
96 | for serverID, node := range nodes {
97 | if serverID != int(global.CenterID) {
98 | if node.NodeState == msg.NodeState_Ready || node.NodeState == msg.NodeState_Running {
99 | c.Net.NotifyServer(msg.CMD_NODES_INFO_NTF, ntf, int32(serverID))
100 | }
101 | }
102 | }
103 | c.printServerState()
104 | }
105 |
106 | // HANDLE_KEEP_ALIVE 心跳消息
107 | func (c *Center) HANDLE_KEEP_ALIVE(header *msg.MessageHeader, buffer []byte) {
108 | message := &msg.KeepAlive{}
109 | err := proto.Unmarshal(buffer, message)
110 | if err != nil {
111 | return
112 | }
113 | serverID := message.ServerID
114 | c.keepAliveTime[serverID] = time.Now().UnixNano() + timeout
115 | info := cluster.GetNode(serverID)
116 | if info.NodeState == msg.NodeState_Offline {
117 | info.NodeState = msg.NodeState_Running
118 | cluster.RefreshRunning()
119 | cluster.RefreshRunningZones()
120 | c.pushNodesInfo()
121 | }
122 | }
123 |
124 | // HANDLE_RELOAD_ETC_REQ 重载配置
125 | func (c *Center) HANDLE_RELOAD_ETC_REQ(header *msg.MessageHeader, buffer []byte) {
126 | defer c.Net.ResponceBytes(header, make([]byte, 1))
127 | dir, _ := os.Getwd()
128 | etcmgr.Instance.Load(dir + "/etc")
129 | c.broadcastETCSyncNTF()
130 | }
131 |
132 | func (c *Center) tickServerState() {
133 | go func() {
134 | for {
135 | time.Sleep(time.Millisecond * 10)
136 | now := time.Now().UnixNano()
137 | stateDirty := false
138 | for serverID, info := range cluster.GetNodes() {
139 | if int32(serverID) == global.CenterID {
140 | continue
141 | }
142 | if info.NodeState == msg.NodeState_Running {
143 | if c.keepAliveTime[serverID] == 0 {
144 | c.keepAliveTime[serverID] = now
145 | }
146 | if c.keepAliveTime[serverID] < now {
147 | info.NodeState = msg.NodeState_Offline
148 | serverType := etcmgr.Instance.GetServerType(int32(serverID))
149 | logger.Info(fmt.Sprintf("Node Offline ID:%d Type:%s", serverID, serverType))
150 | stateDirty = true
151 | }
152 | }
153 | }
154 | if stateDirty {
155 | cluster.RefreshRunning()
156 | cluster.RefreshRunningZones()
157 | c.pushNodesInfo()
158 | }
159 | }
160 | }()
161 | }
162 |
163 | func (c *Center) broadcastETCSyncNTF() {
164 | ntf := etcmgr.Instance.GenerateETCSyncNTF()
165 | for serverID, info := range cluster.GetNodes() {
166 | if int32(serverID) != global.CenterID {
167 | if info.NodeState == msg.NodeState_Ready || info.NodeState == msg.NodeState_Running {
168 | c.Net.NotifyServer(msg.CMD_ETC_SYNC_NTF, ntf, int32(serverID))
169 | }
170 | }
171 | }
172 | }
173 |
174 | func (c *Center) sendETCSyncNTF(serverID int32) {
175 | ntf := etcmgr.Instance.GenerateETCSyncNTF()
176 | c.Net.NotifyServer(msg.CMD_ETC_SYNC_NTF, ntf, int32(serverID))
177 | }
178 |
179 | func (c *Center) broadcastResetConnectionNTF(server int32) {
180 | ntf := &msg.ResetConnectionNTF{
181 | ServerID: server,
182 | }
183 | for serverID, info := range cluster.GetNodes() {
184 | if int32(serverID) != global.CenterID {
185 | if info.NodeState != msg.NodeState_Unset {
186 | c.Net.NotifyServer(msg.CMD_RESET_CONNECTION_NTF, ntf, int32(serverID))
187 | }
188 | }
189 | }
190 | }
191 |
192 | func (c *Center) printServerState() {
193 | states := "[ServerState] "
194 | for _, svr := range etcmgr.Instance.Servers() {
195 | if svr.ServerID == 0 {
196 | continue
197 | }
198 | info := cluster.GetNode(svr.ServerID)
199 | running := info.NodeState == msg.NodeState_Running
200 | ready := info.NodeState == msg.NodeState_Ready
201 | offline := info.NodeState == msg.NodeState_Offline
202 | if running {
203 | states = states + fmt.Sprintf("%d%s ", svr.ServerID, "O")
204 | } else if ready {
205 | states = states + fmt.Sprintf("%d%s ", svr.ServerID, "R")
206 | } else if offline {
207 | states = states + fmt.Sprintf("%d%s ", svr.ServerID, "?")
208 | } else {
209 | states = states + fmt.Sprintf("%d%s ", svr.ServerID, "X")
210 | }
211 | }
212 | logger.Info(states)
213 | }
214 |
--------------------------------------------------------------------------------
/proto/protobuf/timestamp.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option cc_enable_arenas = true;
37 | option go_package = "types";
38 | option java_package = "com.google.protobuf";
39 | option java_outer_classname = "TimestampProto";
40 | option java_multiple_files = true;
41 | option objc_class_prefix = "GPB";
42 |
43 | // A Timestamp represents a point in time independent of any time zone or local
44 | // calendar, encoded as a count of seconds and fractions of seconds at
45 | // nanosecond resolution. The count is relative to an epoch at UTC midnight on
46 | // January 1, 1970, in the proleptic Gregorian calendar which extends the
47 | // Gregorian calendar backwards to year one.
48 | //
49 | // All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
50 | // second table is needed for interpretation, using a [24-hour linear
51 | // smear](https://developers.google.com/time/smear).
52 | //
53 | // The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
54 | // restricting to that range, we ensure that we can convert to and from [RFC
55 | // 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
56 | //
57 | // # Examples
58 | //
59 | // Example 1: Compute Timestamp from POSIX `time()`.
60 | //
61 | // Timestamp timestamp;
62 | // timestamp.set_seconds(time(NULL));
63 | // timestamp.set_nanos(0);
64 | //
65 | // Example 2: Compute Timestamp from POSIX `gettimeofday()`.
66 | //
67 | // struct timeval tv;
68 | // gettimeofday(&tv, NULL);
69 | //
70 | // Timestamp timestamp;
71 | // timestamp.set_seconds(tv.tv_sec);
72 | // timestamp.set_nanos(tv.tv_usec * 1000);
73 | //
74 | // Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
75 | //
76 | // FILETIME ft;
77 | // GetSystemTimeAsFileTime(&ft);
78 | // UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
79 | //
80 | // // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
81 | // // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
82 | // Timestamp timestamp;
83 | // timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
84 | // timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
85 | //
86 | // Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
87 | //
88 | // long millis = System.currentTimeMillis();
89 | //
90 | // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
91 | // .setNanos((int) ((millis % 1000) * 1000000)).build();
92 | //
93 | //
94 | // Example 5: Compute Timestamp from current time in Python.
95 | //
96 | // timestamp = Timestamp()
97 | // timestamp.GetCurrentTime()
98 | //
99 | // # JSON Mapping
100 | //
101 | // In JSON format, the Timestamp type is encoded as a string in the
102 | // [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
103 | // format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
104 | // where {year} is always expressed using four digits while {month}, {day},
105 | // {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
106 | // seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
107 | // are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
108 | // is required. A proto3 JSON serializer should always use UTC (as indicated by
109 | // "Z") when printing the Timestamp type and a proto3 JSON parser should be
110 | // able to accept both UTC and other timezones (as indicated by an offset).
111 | //
112 | // For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
113 | // 01:30 UTC on January 15, 2017.
114 | //
115 | // In JavaScript, one can convert a Date object to this format using the
116 | // standard
117 | // [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
118 | // method. In Python, a standard `datetime.datetime` object can be converted
119 | // to this format using
120 | // [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
121 | // the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
122 | // the Joda Time's [`ISODateTimeFormat.dateTime()`](
123 | // http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
124 | // ) to obtain a formatter capable of generating timestamps in this format.
125 | //
126 | //
127 | message Timestamp {
128 | // Represents seconds of UTC time since Unix epoch
129 | // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
130 | // 9999-12-31T23:59:59Z inclusive.
131 | int64 seconds = 1;
132 |
133 | // Non-negative fractions of a second at nanosecond resolution. Negative
134 | // second values with fractions must still have non-negative nanos values
135 | // that count forward in time. Must be from 0 to 999,999,999
136 | // inclusive.
137 | int32 nanos = 2;
138 | }
139 |
--------------------------------------------------------------------------------
/proto/protobuf/type.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | import "google/protobuf/any.proto";
36 | import "google/protobuf/source_context.proto";
37 |
38 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
39 | option cc_enable_arenas = true;
40 | option java_package = "com.google.protobuf";
41 | option java_outer_classname = "TypeProto";
42 | option java_multiple_files = true;
43 | option objc_class_prefix = "GPB";
44 | option go_package = "types";
45 |
46 | // A protocol buffer message type.
47 | message Type {
48 | // The fully qualified message name.
49 | string name = 1;
50 | // The list of fields.
51 | repeated Field fields = 2;
52 | // The list of types appearing in `oneof` definitions in this type.
53 | repeated string oneofs = 3;
54 | // The protocol buffer options.
55 | repeated Option options = 4;
56 | // The source context.
57 | SourceContext source_context = 5;
58 | // The source syntax.
59 | Syntax syntax = 6;
60 | }
61 |
62 | // A single field of a message type.
63 | message Field {
64 | // Basic field types.
65 | enum Kind {
66 | // Field type unknown.
67 | TYPE_UNKNOWN = 0;
68 | // Field type double.
69 | TYPE_DOUBLE = 1;
70 | // Field type float.
71 | TYPE_FLOAT = 2;
72 | // Field type int64.
73 | TYPE_INT64 = 3;
74 | // Field type uint64.
75 | TYPE_UINT64 = 4;
76 | // Field type int32.
77 | TYPE_INT32 = 5;
78 | // Field type fixed64.
79 | TYPE_FIXED64 = 6;
80 | // Field type fixed32.
81 | TYPE_FIXED32 = 7;
82 | // Field type bool.
83 | TYPE_BOOL = 8;
84 | // Field type string.
85 | TYPE_STRING = 9;
86 | // Field type group. Proto2 syntax only, and deprecated.
87 | TYPE_GROUP = 10;
88 | // Field type message.
89 | TYPE_MESSAGE = 11;
90 | // Field type bytes.
91 | TYPE_BYTES = 12;
92 | // Field type uint32.
93 | TYPE_UINT32 = 13;
94 | // Field type enum.
95 | TYPE_ENUM = 14;
96 | // Field type sfixed32.
97 | TYPE_SFIXED32 = 15;
98 | // Field type sfixed64.
99 | TYPE_SFIXED64 = 16;
100 | // Field type sint32.
101 | TYPE_SINT32 = 17;
102 | // Field type sint64.
103 | TYPE_SINT64 = 18;
104 | }
105 |
106 | // Whether a field is optional, required, or repeated.
107 | enum Cardinality {
108 | // For fields with unknown cardinality.
109 | CARDINALITY_UNKNOWN = 0;
110 | // For optional fields.
111 | CARDINALITY_OPTIONAL = 1;
112 | // For required fields. Proto2 syntax only.
113 | CARDINALITY_REQUIRED = 2;
114 | // For repeated fields.
115 | CARDINALITY_REPEATED = 3;
116 | };
117 |
118 | // The field type.
119 | Kind kind = 1;
120 | // The field cardinality.
121 | Cardinality cardinality = 2;
122 | // The field number.
123 | int32 number = 3;
124 | // The field name.
125 | string name = 4;
126 | // The field type URL, without the scheme, for message or enumeration
127 | // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
128 | string type_url = 6;
129 | // The index of the field type in `Type.oneofs`, for message or enumeration
130 | // types. The first type has index 1; zero means the type is not in the list.
131 | int32 oneof_index = 7;
132 | // Whether to use alternative packed wire representation.
133 | bool packed = 8;
134 | // The protocol buffer options.
135 | repeated Option options = 9;
136 | // The field JSON name.
137 | string json_name = 10;
138 | // The string value of the default value of this field. Proto2 syntax only.
139 | string default_value = 11;
140 | }
141 |
142 | // Enum type definition.
143 | message Enum {
144 | // Enum type name.
145 | string name = 1;
146 | // Enum value definitions.
147 | repeated EnumValue enumvalue = 2;
148 | // Protocol buffer options.
149 | repeated Option options = 3;
150 | // The source context.
151 | SourceContext source_context = 4;
152 | // The source syntax.
153 | Syntax syntax = 5;
154 | }
155 |
156 | // Enum value definition.
157 | message EnumValue {
158 | // Enum value name.
159 | string name = 1;
160 | // Enum value number.
161 | int32 number = 2;
162 | // Protocol buffer options.
163 | repeated Option options = 3;
164 | }
165 |
166 | // A protocol buffer option, which can be attached to a message, field,
167 | // enumeration, etc.
168 | message Option {
169 | // The option's name. For protobuf built-in options (options defined in
170 | // descriptor.proto), this is the short name. For example, `"map_entry"`.
171 | // For custom options, it should be the fully-qualified name. For example,
172 | // `"google.api.http"`.
173 | string name = 1;
174 | // The option's value packed in an Any message. If the value is a primitive,
175 | // the corresponding wrapper type defined in google/protobuf/wrappers.proto
176 | // should be used. If the value is an enum, it should be stored as an int32
177 | // value using the google.protobuf.Int32Value type.
178 | Any value = 2;
179 | }
180 |
181 | // The syntax in which a protocol buffer element is defined.
182 | enum Syntax {
183 | // Syntax `proto2`.
184 | SYNTAX_PROTO2 = 0;
185 | // Syntax `proto3`.
186 | SYNTAX_PROTO3 = 1;
187 | }
188 |
--------------------------------------------------------------------------------