From 506f7ed5ed84994c45c238b112f9b4af3ce3c729 Mon Sep 17 00:00:00 2001 From: "DESKTOP-V763RJ7\\Administrator" <835606593@qq.com> Date: Sat, 3 Jan 2026 14:26:10 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E5=88=9D=E6=AC=A1=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/app.go | 58 ++++++ app/base.go | 33 ++++ app/db.go | 23 +++ app/grpc.go | 27 +++ config/config.dev.yaml | 19 ++ config/config.go | 25 +++ config/config.prod.yaml | 19 ++ deploy/Dockerfile | 11 ++ go.mod | 55 ++++++ go.sum | 168 ++++++++++++++++++ internal/grpc_server/server/server.go | 74 ++++++++ internal/grpc_server/server/server_init.go | 32 ++++ internal/grpc_server/stream_client/gateway.go | 65 +++++++ internal/instance/instance.go | 131 ++++++++++++++ internal/instance/manager.go | 42 +++++ internal/npc/npc.go | 25 +++ internal/npc/player.go | 64 +++++++ main.go | 14 ++ 18 files changed, 885 insertions(+) create mode 100644 app/app.go create mode 100644 app/base.go create mode 100644 app/db.go create mode 100644 app/grpc.go create mode 100644 config/config.dev.yaml create mode 100644 config/config.go create mode 100644 config/config.prod.yaml create mode 100644 deploy/Dockerfile create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/grpc_server/server/server.go create mode 100644 internal/grpc_server/server/server_init.go create mode 100644 internal/grpc_server/stream_client/gateway.go create mode 100644 internal/instance/instance.go create mode 100644 internal/instance/manager.go create mode 100644 internal/npc/npc.go create mode 100644 internal/npc/player.go create mode 100644 main.go diff --git a/app/app.go b/app/app.go new file mode 100644 index 0000000..ffe7c54 --- /dev/null +++ b/app/app.go @@ -0,0 +1,58 @@ +package app + +import ( + "common/discover" + "common/log" + "fmt" + "github.com/judwhite/go-svc" + "scene/config" +) + +type Program struct { + moduleList []Module // 模块列表 +} + +type Module interface { + init() error + start() error + stop() error +} + +func (p *Program) Init(_ svc.Environment) error { + p.moduleList = append(p.moduleList, &ModuleBase{}) + p.moduleList = append(p.moduleList, &ModuleDB{}) + p.moduleList = append(p.moduleList, &ModuleGrpcServer{}) + + for _, module := range p.moduleList { + if err := module.init(); err != nil { + return err + } + } + log.Infof(fmt.Sprintf("%v Init successful...", config.Get().App.Name)) + return nil +} + +func (p *Program) Start() error { + for _, module := range p.moduleList { + if err := module.start(); err != nil { + return err + } + } + discover.Listen() + + log.Infof(fmt.Sprintf("%v Start successful...", config.Get().App.Name)) + return nil +} + +func (p *Program) Stop() error { + discover.Close() + for i := len(p.moduleList) - 1; i >= 0; i-- { + module := p.moduleList[i] + if err := module.stop(); err != nil { + log.Errorf("module stop error: %v", err) + } + } + + log.Infof(fmt.Sprintf("%v Stop successful...", config.Get().App.Name)) + return nil +} diff --git a/app/base.go b/app/base.go new file mode 100644 index 0000000..3614b3d --- /dev/null +++ b/app/base.go @@ -0,0 +1,33 @@ +package app + +import ( + "common/log" + "common/utils" + "math/rand" + "scene/config" +) + +// ModuleBase 基础模块,或者一些零散的模块 +type ModuleBase struct { +} + +func (p *ModuleBase) init() error { + // 配置 + if err := config.LoadConfig(); err != nil { + return err + } + cfg := config.Get() + // 日志 + log.Init(cfg.Log.Debug, cfg.Log.MaxSize, cfg.Log.MaxBackups, cfg.Log.MaxAge, cfg.Log.Level) + // 雪花 + utils.InitSnowflake(int64(rand.Intn(1000))) + return nil +} + +func (p *ModuleBase) start() error { + return nil +} + +func (p *ModuleBase) stop() error { + return nil +} diff --git a/app/db.go b/app/db.go new file mode 100644 index 0000000..a457f05 --- /dev/null +++ b/app/db.go @@ -0,0 +1,23 @@ +package app + +import ( + "common/db" + "scene/config" +) + +// ModuleDB 数据库模块 +type ModuleDB struct { + dbModule *db.ModuleDB +} + +func (p *ModuleDB) init() error { + return p.dbModule.Init(config.Get().DB) +} + +func (p *ModuleDB) start() error { + return nil +} + +func (p *ModuleDB) stop() error { + return p.dbModule.Stop() +} diff --git a/app/grpc.go b/app/grpc.go new file mode 100644 index 0000000..0438b5c --- /dev/null +++ b/app/grpc.go @@ -0,0 +1,27 @@ +package app + +import ( + "common/net/grpc/service" + "scene/config" + "scene/internal/grpc_server/server" +) + +// ModuleGrpcServer Grpc服务模块 +type ModuleGrpcServer struct { + server service.IService +} + +func (m *ModuleGrpcServer) init() error { + return nil +} + +func (m *ModuleGrpcServer) start() error { + m.server = server.NewServer(config.Get().Serve.Grpc.TTL) + m.server.Init(config.Get().Serve.Grpc.Address, config.Get().Serve.Grpc.Port) + return nil +} + +func (m *ModuleGrpcServer) stop() error { + m.server.Close() + return nil +} diff --git a/config/config.dev.yaml b/config/config.dev.yaml new file mode 100644 index 0000000..56b62e9 --- /dev/null +++ b/config/config.dev.yaml @@ -0,0 +1,19 @@ +app: + name: "scene-dev" + +log: + debug: true + level: "debug" + maxSize: 10 + maxBackups: 100 + maxAge: 7 + +db: + etcd: + endpoints: [ "10.0.40.9:2379" ] + +serve: + grpc: + address: "10.0.40.199" + port: 8601 + ttl: 20 diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..0abe5cd --- /dev/null +++ b/config/config.go @@ -0,0 +1,25 @@ +package config + +import "common/config" + +const path = "./config" + +type Config struct { + App *config.AppConfig `yaml:"app"` + Log *config.LogConfig `yaml:"log"` + DB *config.DBConfig `yaml:"db"` + Serve *config.ServeConfig `yaml:"serve"` +} + +var cfg *Config + +// LoadConfig 加载应用配置 +func LoadConfig() error { + c, err := config.LoadConfig(path, cfg) + cfg = c + return err +} + +func Get() *Config { + return cfg +} diff --git a/config/config.prod.yaml b/config/config.prod.yaml new file mode 100644 index 0000000..32a2c2e --- /dev/null +++ b/config/config.prod.yaml @@ -0,0 +1,19 @@ +app: + name: "scene-prod" + +log: + debug: false + level: "debug" + maxSize: 10 + maxBackups: 100 + maxAge: 7 + +db: + etcd: + endpoints: [ "172.18.28.0:2379" ] + +serve: + grpc: + address: "172.18.28.0" + port: 8601 + ttl: 20 diff --git a/deploy/Dockerfile b/deploy/Dockerfile new file mode 100644 index 0000000..2212be1 --- /dev/null +++ b/deploy/Dockerfile @@ -0,0 +1,11 @@ +FROM alpine:latest + +RUN apk add --no-cache tzdata && \ + ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ + echo "Asia/Shanghai" > /etc/timezone + +COPY scene/ /app/ +RUN chmod 777 /app/server-scene + +WORKDIR /app +CMD ["./server-scene"] \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1e51b18 --- /dev/null +++ b/go.mod @@ -0,0 +1,55 @@ +module scene + +go 1.23.1 + +require ( + common v0.0.0-00010101000000-000000000000 + github.com/judwhite/go-svc v1.2.1 + go.uber.org/zap v1.27.0 + google.golang.org/grpc v1.71.1 + google.golang.org/protobuf v1.36.9 +) + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/bwmarrin/snowflake v0.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/coreos/go-semver v0.3.1 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v5 v5.3.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/natefinch/lumberjack v2.0.0+incompatible // indirect + github.com/panjf2000/gnet/v2 v2.9.7 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/redis/go-redis/v9 v9.10.0 // indirect + github.com/sagikazarmark/locafero v0.11.0 // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/spf13/viper v1.21.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + go.etcd.io/etcd/api/v3 v3.6.1 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.1 // indirect + go.etcd.io/etcd/client/v3 v3.6.1 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/net v0.42.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + gorm.io/driver/mysql v1.6.0 // indirect + gorm.io/gorm v1.31.1 // indirect +) + +replace common => ../common diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..9b83e81 --- /dev/null +++ b/go.sum @@ -0,0 +1,168 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= +github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/judwhite/go-svc v1.2.1 h1:a7fsJzYUa33sfDJRF2N/WXhA+LonCEEY8BJb1tuS5tA= +github.com/judwhite/go-svc v1.2.1/go.mod h1:mo/P2JNX8C07ywpP9YtO2gnBgnUiFTHqtsZekJrUuTk= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= +github.com/panjf2000/gnet/v2 v2.9.1 h1:bKewICy/0xnQ9PMzNaswpe/Ah14w1TrRk91LHTcbIlA= +github.com/panjf2000/gnet/v2 v2.9.1/go.mod h1:WQTxDWYuQ/hz3eccH0FN32IVuvZ19HewEWx0l62fx7E= +github.com/panjf2000/gnet/v2 v2.9.7 h1:6zW7Jl3oAfXwSuh1PxHLndoL2MQRWx0AJR6aaQjxUgA= +github.com/panjf2000/gnet/v2 v2.9.7/go.mod h1:WQTxDWYuQ/hz3eccH0FN32IVuvZ19HewEWx0l62fx7E= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.10.0 h1:FxwK3eV8p/CQa0Ch276C7u2d0eNC9kCmAYQ7mCXCzVs= +github.com/redis/go-redis/v9 v9.10.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/etcd/api/v3 v3.6.1 h1:yJ9WlDih9HT457QPuHt/TH/XtsdN2tubyxyQHSHPsEo= +go.etcd.io/etcd/api/v3 v3.6.1/go.mod h1:lnfuqoGsXMlZdTJlact3IB56o3bWp1DIlXPIGKRArto= +go.etcd.io/etcd/client/pkg/v3 v3.6.1 h1:CxDVv8ggphmamrXM4Of8aCC8QHzDM4tGcVr9p2BSoGk= +go.etcd.io/etcd/client/pkg/v3 v3.6.1/go.mod h1:aTkCp+6ixcVTZmrJGa7/Mc5nMNs59PEgBbq+HCmWyMc= +go.etcd.io/etcd/client/v3 v3.6.1 h1:KelkcizJGsskUXlsxjVrSmINvMMga0VWwFF0tSPGEP0= +go.etcd.io/etcd/client/v3 v3.6.1/go.mod h1:fCbPUdjWNLfx1A6ATo9syUmFVxqHH9bCnPLBZmnLmMY= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI= +google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= +gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo= +gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= +gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= diff --git a/internal/grpc_server/server/server.go b/internal/grpc_server/server/server.go new file mode 100644 index 0000000..5aa3173 --- /dev/null +++ b/internal/grpc_server/server/server.go @@ -0,0 +1,74 @@ +package server + +import ( + "common/log" + "common/proto/sc/sc_pb" + "common/proto/ss/grpc_pb" + "context" + "google.golang.org/protobuf/proto" + instance2 "scene/internal/instance" + "sync" +) + +func (s *Server) Enter(ctx context.Context, req *grpc_pb.EnterReq) (*grpc_pb.EnterResp, error) { + var i *instance2.Instance + if len(instance2.Mgr.GetAll()) == 0 { + i = instance2.NewScene(s.SID, req.InstanceID) + i.Start(s.EtcdTTL) + } else { + for _, v := range instance2.Mgr.GetAll() { + i = v + break + } + } + i.EventIn <- req + + payload, _ := proto.Marshal(&sc_pb.S2C_EnterInstance{ + Info: &sc_pb.PositionInfo{ + USN: req.USN, + X: 1, + Y: 1, + }, + }) + return &grpc_pb.EnterResp{ + SceneSID: s.SID, + UniqueNo: i.UniqueNo, + MessageID: int32(sc_pb.MessageID_MESSAGE_ID_ENTER_INSTANCE), + Payload: payload, + }, nil +} + +func (s *Server) Leave(ctx context.Context, req *grpc_pb.LeaveReq) (*grpc_pb.LeaveResp, error) { + if i := instance2.Mgr.GetByUniqueNo(req.UniqueNo); i != nil { + i.EventIn <- req + } + return &grpc_pb.LeaveResp{}, nil +} + +func (s *Server) Action(server grpc_pb.Scene_ActionServer) error { + wg := &sync.WaitGroup{} + wg.Add(1) + go func() { + defer wg.Done() + defer func() { + if err := recover(); err != nil { + log.Errorf("Action panic: %v", err) + } + }() + for { + if args, err := server.Recv(); err != nil { + return + } else { + if ins := instance2.Mgr.GetByUniqueNo(args.UniqueNo); ins != nil { + select { + case ins.EventIn <- args: + default: + log.Warnf("instance event in full: %v, %v", ins.InstanceID, ins.UniqueNo) + } + } + } + } + }() + wg.Wait() + return server.SendAndClose(&grpc_pb.ActionResp{}) +} diff --git a/internal/grpc_server/server/server_init.go b/internal/grpc_server/server/server_init.go new file mode 100644 index 0000000..b3c239b --- /dev/null +++ b/internal/grpc_server/server/server_init.go @@ -0,0 +1,32 @@ +package server + +import ( + "common/discover/common" + "common/net/grpc/service" + "common/proto/ss/grpc_pb" + "google.golang.org/grpc" +) + +type Server struct { + grpc_pb.UnimplementedSceneServer + service.Base +} + +func NewServer(ttl int64) *Server { + s := &Server{ + Base: service.Base{ + Target: common.KeyDiscoverScene, + EtcdTTL: ttl, + }, + } + s.Base.OnInit = s.OnInit + s.Base.OnClose = s.OnClose + return s +} + +func (s *Server) OnInit(serve *grpc.Server) { + grpc_pb.RegisterSceneServer(serve, s) +} + +func (s *Server) OnClose() { +} diff --git a/internal/grpc_server/stream_client/gateway.go b/internal/grpc_server/stream_client/gateway.go new file mode 100644 index 0000000..fd735ee --- /dev/null +++ b/internal/grpc_server/stream_client/gateway.go @@ -0,0 +1,65 @@ +package stream_client + +import ( + "common/log" + "common/net/grpc/service" + "context" + "google.golang.org/grpc" + "google.golang.org/protobuf/proto" +) + +var gatewayServerM map[int64]map[GatewayFun]grpc.ClientStream // map[sid]map[方法名]流连接 + +type GatewayFun int + +const ( + FunToClient GatewayFun = iota +) + +func init() { + gatewayServerM = make(map[int64]map[GatewayFun]grpc.ClientStream) +} + +func FindGatewayBySID(sid int64, fun GatewayFun) (grpc.ClientStream, error) { + g := gatewayServerM[sid] + if g == nil { + g = make(map[GatewayFun]grpc.ClientStream) + gatewayServerM[sid] = g + } + gatewayLink := g[fun] + if gatewayLink == nil { + gatewayClient, err := service.GatewayNewClient(sid) + if err != nil { + log.Errorf("cannot find gatewayClient: %v", err) + return nil, err + } + var link grpc.ClientStream + switch fun { + case FunToClient: + link, err = gatewayClient.ToClient(context.Background()) + } + if err != nil { + log.Errorf("FindGatewayBySID %v err: %v, sid: %v", fun, err, sid) + return nil, err + } + g[fun] = link + gatewayLink = link + } + return gatewayLink, nil +} + +func SendMessageToGateway(sid int64, fun GatewayFun, msg proto.Message, re ...bool) error { + stream, err := FindGatewayBySID(sid, fun) + if err != nil { + return err + } + if err = stream.SendMsg(msg); err != nil { + if re == nil || !re[0] { + _ = stream.CloseSend() + delete(gatewayServerM[sid], fun) + return SendMessageToGateway(sid, fun, msg, true) + } + return err + } + return nil +} diff --git a/internal/instance/instance.go b/internal/instance/instance.go new file mode 100644 index 0000000..edcc8ad --- /dev/null +++ b/internal/instance/instance.go @@ -0,0 +1,131 @@ +package instance + +import ( + "common/discover" + "common/log" + "common/proto/sc/sc_pb" + "common/proto/ss/grpc_pb" + "common/utils" + "context" + "fmt" + "go.uber.org/zap" + "google.golang.org/protobuf/proto" + "runtime/debug" + "scene/internal/grpc_server/stream_client" + "scene/internal/npc" + "sync" + "time" +) + +// Instance 场景类 +type Instance struct { + wg sync.WaitGroup + players map[int64]*npc.PlayerNode // 存储所有玩家节点 [usn] + ctx context.Context // 停止指令 + cancel context.CancelFunc // 停止函数 + logger *zap.SugaredLogger // 日志 + lastLogicTime int64 // 上次逻辑帧执行时间(毫秒时间戳) + + SID int64 // 服务ID + InstanceID int32 // 副本ID + UniqueNo int64 // 唯一编号 + EventIn chan proto.Message // 消息入口 +} + +// NewScene 初始化场景 +func NewScene(sid int64, instanceID int32) *Instance { + s := &Instance{ + players: make(map[int64]*npc.PlayerNode), + SID: sid, + InstanceID: instanceID, + UniqueNo: utils.SnowflakeInstance().Generate().Int64(), + EventIn: make(chan proto.Message, 1024), + } + s.logger = log.GetLogger().Named(fmt.Sprintf("instance %v:%v", s.InstanceID, s.UniqueNo)) + s.ctx, s.cancel = context.WithCancel(context.Background()) + return s +} + +func (i *Instance) Start(ttl int64) { + i.wg.Add(1) + go func() { + defer i.wg.Done() + defer func() { + if err := recover(); err != nil { + i.logger.Infof("instance err: %v", err) + debug.PrintStack() + } + }() + Mgr.Add(i.UniqueNo, i) + defer func() { + i.logger.Infof("instance destroy") + discover.UnRegisterInstance(i.UniqueNo) + close(i.EventIn) + Mgr.Delete(i.UniqueNo) + }() + + if err := discover.RegisterInstance(i.SID, i.InstanceID, i.UniqueNo, ttl); err != nil { + i.logger.Errorf("register discover error") + return + } + // 场景心跳 + tick := time.NewTicker(50 * time.Millisecond) + i.lastLogicTime = time.Now().UnixMilli() + for { + select { + case <-i.ctx.Done(): + return + case <-tick.C: + now := time.Now().UnixMilli() + i.onLogic(now - i.lastLogicTime) + i.lastLogicTime = now + case e := <-i.EventIn: + i.onEvent(e) + } + } + }() + i.logger.Infof("new scene start") +} + +// 网络帧,将玩家的操作储存起来,到逻辑帧再处理玩家操作 +func (i *Instance) onEvent(e proto.Message) { + switch v := e.(type) { + case *grpc_pb.EnterReq: + i.players[v.USN] = npc.NewPlayerNode(v.GatewaySID, v.USN) + case *grpc_pb.ActionReq: + if node, ok := i.players[v.USN]; ok { + node.AddAction(v) + } + case *grpc_pb.LeaveReq: + delete(i.players, v.USN) + } +} + +// 逻辑帧 +func (i *Instance) onLogic(delta int64) { + positionUpdate := make([]*sc_pb.PositionInfo, 0) + sid := int64(0) + // 处理玩家指令 + for _, node := range i.players { + if node.LogicAction(delta) { + positionUpdate = append(positionUpdate, &sc_pb.PositionInfo{ + USN: node.USN, + X: int32(node.Position[0] * 100), + Y: int32(node.Position[1] * 100), + }) + sid = node.GatewaySID + } + } + if len(positionUpdate) > 0 { + payload, _ := proto.Marshal(&sc_pb.S2C_Position{ + Info: positionUpdate, + }) + if err := stream_client.SendMessageToGateway(sid, stream_client.FunToClient, &grpc_pb.ToClientReq{ + USN: -1, + MessageID: int32(sc_pb.MessageID_MESSAGE_ID_POSITION), + Payload: payload, + }); err != nil { + i.logger.Errorf("send action err: %v", err) + } + } +} diff --git a/internal/instance/manager.go b/internal/instance/manager.go new file mode 100644 index 0000000..e515fdc --- /dev/null +++ b/internal/instance/manager.go @@ -0,0 +1,42 @@ +package instance + +import ( + "sync" +) + +var Mgr *insManager + +type insManager struct { + sync.RWMutex + insMap map[int64]*Instance // [uniqueNo] +} + +func init() { + Mgr = &insManager{ + insMap: make(map[int64]*Instance), + } +} + +func (m *insManager) Add(uniqueNo int64, ins *Instance) { + m.Lock() + defer m.Unlock() + m.insMap[uniqueNo] = ins +} + +func (m *insManager) Delete(uniqueNo int64) { + m.Lock() + defer m.Unlock() + delete(m.insMap, uniqueNo) +} + +func (m *insManager) GetAll() map[int64]*Instance { + m.RLock() + defer m.RUnlock() + return m.insMap +} + +func (m *insManager) GetByUniqueNo(uniqueNo int64) *Instance { + m.RLock() + defer m.RUnlock() + return m.insMap[uniqueNo] +} diff --git a/internal/npc/npc.go b/internal/npc/npc.go new file mode 100644 index 0000000..e07b3f6 --- /dev/null +++ b/internal/npc/npc.go @@ -0,0 +1,25 @@ +package npc + +import ( + "common/proto/ss/grpc_pb" +) + +// NPCNode 定义NPC节点 +type NPCNode struct { + USN int64 // 用户ID + GatewaySID int64 // 网关服务ID + + Position [2]float64 // 二维坐标 [x, y] + MoveCross int8 // 移动十字,1 上 2 下 4 左 8 右 + Action []*grpc_pb.ActionReq // 其他操作 +} + +func NewNPCNode(gatewaySID int64, usn int64) *NPCNode { + return &NPCNode{ + USN: usn, + GatewaySID: gatewaySID, + Position: [2]float64{0, 0}, + MoveCross: 0, + Action: make([]*grpc_pb.ActionReq, 0), + } +} diff --git a/internal/npc/player.go b/internal/npc/player.go new file mode 100644 index 0000000..945d5a4 --- /dev/null +++ b/internal/npc/player.go @@ -0,0 +1,64 @@ +package npc + +import ( + "common/proto/sc/sc_pb" + "common/proto/ss/grpc_pb" +) + +// PlayerNode 定义玩家节点结构体 +type PlayerNode struct { + USN int64 // 用户ID + GatewaySID int64 // 网关服务ID + MoveSpeed float32 // 移动速度 + + Position [2]float32 // 二维坐标 [x, y] + MoveDirection [2]int8 // 移动方向 [x, y] + MoveCount int8 // 移动指令使用计数 + Action []*grpc_pb.ActionReq // 其他操作 +} + +func NewPlayerNode(gatewaySID int64, usn int64) *PlayerNode { + return &PlayerNode{ + USN: usn, + GatewaySID: gatewaySID, + MoveSpeed: 5 * 0.00001, + Position: [2]float32{0, 0}, + Action: make([]*grpc_pb.ActionReq, 0), + } +} + +// AddAction 将指令存储到玩家身上 +func (p *PlayerNode) AddAction(e *grpc_pb.ActionReq) { + p.Action = append(p.Action, e) +} + +// LogicAction 处理玩家操作指令 +// return 是否更新玩家状态 +func (p *PlayerNode) LogicAction(delta int64) bool { + for _, a := range p.Action { + switch sc_pb.ActionID(a.Action) { + case sc_pb.ActionID_ACTION_ID_MOVE: + p.MoveDirection = [2]int8{int8(a.DirX), int8(a.DirY)} + p.MoveCount = 0 + case sc_pb.ActionID_ACTION_ID_ATTACK: + } + } + p.Action = make([]*grpc_pb.ActionReq, 0) + + return p.move(delta) +} + +func (p *PlayerNode) move(delta int64) bool { + if p.MoveDirection[0] == 0 && p.MoveDirection[1] == 0 { + return false + } + // 移动指令只能用2秒,客户端需要定期续上 + if p.MoveCount >= 40 { + p.MoveDirection = [2]int8{0, 0} + return false + } + p.Position[0] += float32(p.MoveDirection[0]) * float32(delta) * p.MoveSpeed + p.Position[1] += float32(p.MoveDirection[1]) * float32(delta) * p.MoveSpeed + p.MoveCount++ + return true +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..394c871 --- /dev/null +++ b/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "fmt" + "github.com/judwhite/go-svc" + "scene/app" + "syscall" +) + +func main() { + if err := svc.Run(&app.Program{}, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL); err != nil { + fmt.Println(err) + } +}