init commit

This commit is contained in:
flswld
2022-11-20 15:38:00 +08:00
parent eda2b643b9
commit 3efed3defe
5834 changed files with 636508 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
package entity
type TestEntity struct {
ID uint64
Name string
Age int64
}

View File

@@ -0,0 +1,8 @@
package entity
type User struct {
Uid uint64
Username string
Password string
IsAdmin bool
}

View File

@@ -0,0 +1,3 @@
module annie-user-api
go 1.19

View File

@@ -0,0 +1,17 @@
http_port = 9002
[logger]
level = "DEBUG"
method = "CONSOLE"
track_line = true
[air]
addr = "air"
port = 8086
service_name = "annie-user-app"
[database]
url = "root:flswld@(mysql:3306)/annie_user?charset=utf8&parseTime=True&loc=Local"
[light]
port = 10003

View File

@@ -0,0 +1,58 @@
package main
import (
"annie-user/controller"
"annie-user/dao"
"annie-user/service"
"flswld.com/common/config"
"flswld.com/light"
"flswld.com/logger"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
filePath := "./application.toml"
config.InitConfig(filePath)
logger.InitLogger()
logger.LOG.Info("user start")
httpProvider := light.NewHttpProvider()
db := dao.NewDao()
svc := service.NewService(db)
rpcSvc := service.NewRpcService(db, svc)
rpcProvider := light.NewRpcProvider(rpcSvc)
// 认证服务
rpcWaterAuthConsumer := light.NewRpcConsumer("water-auth")
rpcHk4eGatewayConsumer := light.NewRpcConsumer("hk4e-gateway")
_ = controller.NewController(svc, rpcWaterAuthConsumer, rpcHk4eGatewayConsumer)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
logger.LOG.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
rpcProvider.CloseRpcProvider()
db.CloseDao()
rpcWaterAuthConsumer.CloseRpcConsumer()
httpProvider.CloseHttpProvider()
logger.LOG.Info("user exit")
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,34 @@
package controller
import (
apiEntity "annie-user/entity/api"
"flswld.com/common/entity/dto"
waterAuth "flswld.com/water-api/auth"
"github.com/gin-gonic/gin"
"net/http"
)
func (c *Controller) queryUserByUsername(context *gin.Context) {
accessToken := c.getAccessToken(context)
user, err := waterAuth.WaterQueryUserByAccessToken(c.rpcWaterAuthConsumer, accessToken)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(1001, "服务器内部错误", nil))
return
}
if !user.IsAdmin {
context.JSON(http.StatusOK, dto.NewResponseResult(10001, "没有访问权限", nil))
return
}
username := context.Query("username")
userQuery := c.service.QueryUserByUsername(username)
if userQuery == nil {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "未查询到用户", nil))
return
}
userRet := new(apiEntity.User)
userRet.Uid = userQuery.Uid
userRet.Username = userQuery.Username
userRet.Password = userQuery.Password
userRet.IsAdmin = userQuery.IsAdmin
context.JSON(http.StatusOK, dto.NewResponseResult(0, "查询用户成功", userRet))
}

View File

@@ -0,0 +1,78 @@
package controller
import (
"annie-user/service"
"flswld.com/common/config"
"flswld.com/light"
waterAuth "flswld.com/water-api/auth"
"github.com/gin-gonic/gin"
"net/http"
"strconv"
"strings"
)
type Controller struct {
service *service.Service
rpcWaterAuthConsumer *light.Consumer
rpcHk4eGatewayConsumer *light.Consumer
}
func NewController(service *service.Service, rpcWaterAuthConsumer *light.Consumer, rpcHk4eGatewayConsumer *light.Consumer) (r *Controller) {
r = new(Controller)
r.service = service
r.rpcWaterAuthConsumer = rpcWaterAuthConsumer
r.rpcHk4eGatewayConsumer = rpcHk4eGatewayConsumer
go r.registerRouter()
return r
}
func (c *Controller) getAccessToken(context *gin.Context) string {
accessToken := context.GetHeader("Authorization")
divIndex := strings.Index(accessToken, " ")
if divIndex > 0 {
payload := accessToken[divIndex+1:]
return payload
} else {
return ""
}
}
// access_token鉴权
func (c *Controller) authorize() gin.HandlerFunc {
return func(context *gin.Context) {
valid, err := waterAuth.WaterVerifyAccessToken(c.rpcWaterAuthConsumer, c.getAccessToken(context))
if err == nil && valid == true {
// 验证通过
context.Next()
return
}
// 验证不通过
context.Abort()
context.JSON(http.StatusOK, gin.H{
"code": "10001",
"msg": "没有访问权限",
})
}
}
func (c *Controller) registerRouter() {
if config.CONF.Logger.Level == "DEBUG" {
gin.SetMode(gin.DebugMode)
} else {
gin.SetMode(gin.ReleaseMode)
}
engine := gin.Default()
// 未认证接口
engine.POST("/user/reg", c.userRegister)
engine.Use(c.authorize())
// 认证接口
engine.POST("/user/update/pwd", c.userUpdatePassword)
// 管理员
admin := engine.Group("/user/admin")
{
admin.GET("/query/user", c.queryUserByUsername)
}
port := strconv.FormatInt(int64(config.CONF.HttpPort), 10)
portStr := ":" + port
_ = engine.Run(portStr)
}

View File

@@ -0,0 +1,93 @@
package controller
import (
apiEntity "annie-user/entity/api"
dbEntity "annie-user/entity/db"
"flswld.com/common/entity/dto"
"flswld.com/common/utils/endec"
"flswld.com/logger"
waterAuth "flswld.com/water-api/auth"
"github.com/gin-gonic/gin"
"net/http"
"regexp"
)
func (c *Controller) userRegister(context *gin.Context) {
userRegInfo := new(apiEntity.User)
err := context.BindJSON(&userRegInfo)
if err != nil {
context.JSON(http.StatusOK, gin.H{
"code": 10003,
"msg": "参数错误",
})
return
}
username := userRegInfo.Username
password := userRegInfo.Password
if len(username) < 6 || len(username) > 20 {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "用户名为6-20位字符", nil))
return
}
if len(password) < 8 || len(password) > 20 {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "密码为8-20位字符", nil))
return
}
ok, err := regexp.MatchString("^[a-zA-Z0-9]{6,20}$", username)
if err != nil || !ok {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "用户名只能包含大小写字母和数字", nil))
return
}
user := c.service.QueryUserByUsername(username)
if user != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "用户名已注册", nil))
return
}
user = new(dbEntity.User)
user.Username = username
user.Password = password
ok = c.service.RegisterUser(user)
if !ok {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "用户注册失败", nil))
return
}
logger.LOG.Info("user register success, username: %v", username)
context.JSON(http.StatusOK, dto.NewResponseResult(0, "用户注册成功", nil))
}
func (c *Controller) userUpdatePassword(context *gin.Context) {
accessToken := c.getAccessToken(context)
user, err := waterAuth.WaterQueryUserByAccessToken(c.rpcWaterAuthConsumer, accessToken)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(1001, "服务器内部错误", nil))
return
}
json := make(map[string]string)
err = context.BindJSON(&json)
if err != nil {
context.JSON(http.StatusOK, gin.H{
"code": 10003,
"msg": "参数错误",
})
return
}
oldPassword := json["oldPassword"]
newPassword := json["newPassword"]
if len(oldPassword) < 8 || len(oldPassword) > 20 || len(newPassword) < 8 || len(newPassword) > 20 {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "密码为8-20位字符", nil))
return
}
dbUser := c.service.QueryUserByUsername(user.Username)
if dbUser.Password != endec.Md5Str(oldPassword) {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "旧密码错误", nil))
return
}
dbUser.Password = endec.Md5Str(newPassword)
ok := c.service.UpdateUser(dbUser)
if !ok {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "修改密码失败", nil))
return
}
context.JSON(http.StatusOK, dto.NewResponseResult(0, "修改密码成功", nil))
// TODO 处理各种失效
_ = c.rpcHk4eGatewayConsumer.CallFunction("RpcManager", "UserPasswordChange", &dbUser.Uid, &ok)
}

View File

@@ -0,0 +1,30 @@
package dao
import (
"flswld.com/common/config"
"flswld.com/logger"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
type Dao struct {
db *gorm.DB
}
func NewDao() (r *Dao) {
r = new(Dao)
db, err := gorm.Open("mysql", config.CONF.Database.Url)
if err != nil {
logger.LOG.Error("db open error: %v", err)
panic(err)
}
if config.CONF.Logger.Level == "DEBUG" {
db.LogMode(true)
}
r.db = db
return r
}
func (d *Dao) CloseDao() {
_ = d.db.Close()
}

View File

@@ -0,0 +1,37 @@
package dao
import (
dbEntity "annie-user/entity/db"
)
func (d *Dao) InsertUser(user *dbEntity.User) error {
db := d.db
err := db.Create(user).Error
return err
}
func (d *Dao) UpdateUser(user *dbEntity.User) error {
db := d.db
db = db.Model(&user)
err := db.Updates(user).Error
return err
}
func (d *Dao) QueryUser(user *dbEntity.User) ([]dbEntity.User, error) {
var userList []dbEntity.User
db := d.db
if user.Uid != 0 {
db = db.Where("`uid` = ?", user.Uid)
}
if user.Username != "" {
db = db.Where("`username` = ?", user.Username)
}
if user.Password != "" {
db = db.Where("`password` = ?", user.Password)
}
if user.IsAdmin != false {
db = db.Where("`is_admin` = ?", user.IsAdmin)
}
err := db.Find(&userList).Error
return userList, err
}

View File

@@ -0,0 +1,8 @@
package api
type User struct {
Uid uint64 `json:"uid"`
Username string `json:"username"`
Password string `json:"password"`
IsAdmin bool `json:"isAdmin"`
}

View File

@@ -0,0 +1,12 @@
package db
type User struct {
Uid uint64 `gorm:"column:uid;primary_key;auto_increment"`
Username string `gorm:"column:username"`
Password string `gorm:"column:password"`
IsAdmin bool `gorm:"column:is_admin"`
}
func (User) TableName() string {
return "user"
}

51
service/annie-user/go.mod Normal file
View File

@@ -0,0 +1,51 @@
module annie-user
go 1.19
require flswld.com/common v0.0.0-incompatible
replace flswld.com/common => ../../common
require flswld.com/logger v0.0.0-incompatible
replace flswld.com/logger => ../../logger
require flswld.com/air-api v0.0.0-incompatible // indirect
replace flswld.com/air-api => ../../air-api
require flswld.com/light v0.0.0-incompatible
replace flswld.com/light => ../../light
require flswld.com/annie-user-api v0.0.0-incompatible
replace flswld.com/annie-user-api => ../annie-user-api
require flswld.com/water-api v0.0.0-incompatible
replace flswld.com/water-api => ../../water-api
require (
github.com/gin-gonic/gin v1.6.3
github.com/jinzhu/gorm v1.9.16
)
require (
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.2.0 // indirect
github.com/go-sql-driver/mysql v1.5.0 // indirect
github.com/golang/protobuf v1.3.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
)

80
service/annie-user/go.sum Normal file
View File

@@ -0,0 +1,80 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
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.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
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-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -0,0 +1,17 @@
package service
import (
"annie-user/dao"
)
type RpcService struct {
dao *dao.Dao
service *Service
}
func NewRpcService(dao *dao.Dao, service *Service) (r *RpcService) {
r = new(RpcService)
r.service = service
r.dao = dao
return r
}

View File

@@ -0,0 +1,28 @@
package service
import (
dbEntity "annie-user/entity/db"
"errors"
rpcEntity "flswld.com/annie-user-api/entity"
"flswld.com/common/utils/object"
"flswld.com/logger"
)
func (s *RpcService) RpcQueryUser(user *rpcEntity.User, res *[]rpcEntity.User) error {
dbUser := new(dbEntity.User)
dbUser.Uid = user.Uid
dbUser.Username = user.Username
dbUser.Password = user.Password
dbUser.IsAdmin = user.IsAdmin
userList, err := s.dao.QueryUser(dbUser)
if err != nil {
logger.LOG.Error("QueryUser error: %v", err)
return errors.New("query user error")
}
err = object.ObjectDeepCopy(userList, res)
if err != nil {
logger.LOG.Error("ObjectDeepCopy error: %v", err)
return errors.New("query user error")
}
return nil
}

View File

@@ -0,0 +1,15 @@
package service
import (
"annie-user/dao"
)
type Service struct {
dao *dao.Dao
}
func NewService(dao *dao.Dao) (r *Service) {
r = new(Service)
r.dao = dao
return r
}

View File

@@ -0,0 +1,43 @@
package service
import (
dbEntity "annie-user/entity/db"
"flswld.com/common/utils/endec"
"flswld.com/logger"
)
func (s *Service) RegisterUser(user *dbEntity.User) bool {
user.Password = endec.Md5Str(user.Password)
user.IsAdmin = false
err := s.dao.InsertUser(user)
if err != nil {
logger.LOG.Error("insert user to db error: %v", err)
return false
}
return true
}
func (s *Service) UpdateUser(user *dbEntity.User) bool {
err := s.dao.UpdateUser(user)
if err != nil {
logger.LOG.Error("update user from db error: %v", err)
return false
}
return true
}
func (s *Service) QueryUserByUsername(username string) *dbEntity.User {
userList, err := s.dao.QueryUser(&dbEntity.User{Username: username})
if err != nil {
logger.LOG.Error("query user from db error: %v", err)
return nil
}
if len(userList) == 0 {
return nil
} else if len(userList) == 1 {
return &(userList[0])
} else {
logger.LOG.Error("find not only one user")
return nil
}
}

View File

@@ -0,0 +1,22 @@
[hk4e]
resource_path = "/usr/local/game_hk4e/resources/GameDataConfigTable"
gacha_history_server = "https://hk4e.flswld.com/api/v1"
[logger]
level = "DEBUG"
method = "CONSOLE"
track_line = true
[air]
addr = "air"
port = 8086
service_name = "game-hk4e-app"
[light]
port = 10006
[database]
url = "mongodb://mongo:27017"
[mq]
nats_url = "nats://nats1:4222,nats://nats2:4222,nats://nats3:4222"

View File

@@ -0,0 +1,81 @@
package main
import (
"flswld.com/common/config"
"flswld.com/gate-hk4e-api/proto"
"flswld.com/light"
"flswld.com/logger"
gdc "game-hk4e/config"
"game-hk4e/constant"
"game-hk4e/dao"
"game-hk4e/game"
"game-hk4e/mq"
"game-hk4e/rpc"
"github.com/arl/statsviz"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
filePath := "./application.toml"
config.InitConfig(filePath)
logger.InitLogger()
logger.LOG.Info("game-hk4e start")
go func() {
// 性能检测
err := statsviz.RegisterDefault()
if err != nil {
logger.LOG.Error("statsviz init error: %v", err)
}
err = http.ListenAndServe("0.0.0.0:3456", nil)
if err != nil {
logger.LOG.Error("perf debug http start error: %v", err)
}
}()
constant.InitConstant()
gdc.InitGameDataConfig()
db := dao.NewDao()
netMsgInput := make(chan *proto.NetMsg, 10000)
netMsgOutput := make(chan *proto.NetMsg, 10000)
hk4eGatewayConsumer := light.NewRpcConsumer("hk4e-gateway")
rpcManager := rpc.NewRpcManager(hk4eGatewayConsumer)
gameServiceProvider := light.NewRpcProvider(rpcManager)
messageQueue := mq.NewMessageQueue(netMsgInput, netMsgOutput)
messageQueue.Start()
gameManager := game.NewGameManager(db, rpcManager, netMsgInput, netMsgOutput)
gameManager.Start()
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
logger.LOG.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
logger.LOG.Info("game-hk4e exit")
gameManager.Stop()
db.CloseDao()
gameServiceProvider.CloseRpcProvider()
hk4eGatewayConsumer.CloseRpcConsumer()
messageQueue.Close()
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,73 @@
package config
import (
"encoding/json"
"flswld.com/logger"
"io/ioutil"
"strings"
)
type AvatarConfigAbility struct {
AbilityName string `json:"abilityName"`
}
type AvatarConfig struct {
Abilities []*AvatarConfigAbility `json:"abilities"`
TargetAbilities []*AvatarConfigAbility `json:"targetAbilities"`
}
type AbilityEmbryoEntry struct {
Name string
Abilities []string
}
func (g *GameDataConfig) loadAbilityEmbryos() {
dirPath := g.binPrefix + "Avatar"
fileList, err := ioutil.ReadDir(dirPath)
if err != nil {
logger.LOG.Error("open dir error: %v", err)
return
}
embryoList := make([]*AbilityEmbryoEntry, 0)
for _, file := range fileList {
fileName := file.Name()
if !strings.Contains(fileName, "ConfigAvatar_") {
continue
}
startIndex := strings.Index(fileName, "ConfigAvatar_")
endIndex := strings.Index(fileName, ".json")
if startIndex == -1 || endIndex == -1 || startIndex+13 > endIndex {
logger.LOG.Error("file name format error: %v", fileName)
continue
}
avatarName := fileName[startIndex+13 : endIndex]
fileData, err := ioutil.ReadFile(dirPath + "/" + fileName)
if err != nil {
logger.LOG.Error("open file error: %v", err)
continue
}
avatarConfig := new(AvatarConfig)
err = json.Unmarshal(fileData, avatarConfig)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
if len(avatarConfig.Abilities) == 0 {
continue
}
abilityEmbryoEntry := new(AbilityEmbryoEntry)
abilityEmbryoEntry.Name = avatarName
for _, v := range avatarConfig.Abilities {
abilityEmbryoEntry.Abilities = append(abilityEmbryoEntry.Abilities, v.AbilityName)
}
embryoList = append(embryoList, abilityEmbryoEntry)
}
if len(embryoList) == 0 {
logger.LOG.Error("no embryo load")
}
g.AbilityEmbryos = make(map[string]*AbilityEmbryoEntry)
for _, v := range embryoList {
g.AbilityEmbryos[v.Name] = v
}
logger.LOG.Info("load %v AbilityEmbryos", len(g.AbilityEmbryos))
}

View File

@@ -0,0 +1,102 @@
package config
import (
"encoding/json"
"flswld.com/common/utils/endec"
"flswld.com/logger"
"io/ioutil"
"strings"
)
type AvatarData struct {
IconName string `json:"iconName"`
BodyType string `json:"bodyType"`
QualityType string `json:"qualityType"`
ChargeEfficiency int32 `json:"chargeEfficiency"`
InitialWeapon int32 `json:"initialWeapon"`
WeaponType string `json:"weaponType"`
ImageName string `json:"imageName"`
AvatarPromoteId int32 `json:"avatarPromoteId"`
CutsceneShow string `json:"cutsceneShow"`
SkillDepotId int32 `json:"skillDepotId"`
StaminaRecoverSpeed int32 `json:"staminaRecoverSpeed"`
CandSkillDepotIds []int32 `json:"candSkillDepotIds"`
AvatarIdentityType string `json:"avatarIdentityType"`
AvatarPromoteRewardLevelList []int32 `json:"avatarPromoteRewardLevelList"`
AvatarPromoteRewardIdList []int32 `json:"avatarPromoteRewardIdList"`
NameTextMapHash int64 `json:"nameTextMapHash"`
HpBase float64 `json:"hpBase"`
AttackBase float64 `json:"attackBase"`
DefenseBase float64 `json:"defenseBase"`
Critical float64 `json:"critical"`
CriticalHurt float64 `json:"criticalHurt"`
PropGrowCurves []*PropGrowCurve `json:"propGrowCurves"`
Id int32 `json:"id"`
// 计算数据
Name string `json:"-"`
Abilities []int32 `json:"-"`
}
func (g *GameDataConfig) loadAvatarData() {
g.AvatarDataMap = make(map[int32]*AvatarData)
fileNameList := []string{"AvatarExcelConfigData.json"}
for _, fileName := range fileNameList {
fileData, err := ioutil.ReadFile(g.excelBinPrefix + fileName)
if err != nil {
logger.LOG.Error("open file error: %v", err)
continue
}
list := make([]map[string]any, 0)
err = json.Unmarshal(fileData, &list)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
for _, v := range list {
i, err := json.Marshal(v)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
avatarData := new(AvatarData)
err = json.Unmarshal(i, avatarData)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
g.AvatarDataMap[avatarData.Id] = avatarData
}
}
logger.LOG.Info("load %v AvatarData", len(g.AvatarDataMap))
for _, v := range g.AvatarDataMap {
split := strings.Split(v.IconName, "_")
if len(split) > 0 {
v.Name = split[len(split)-1]
info := g.AbilityEmbryos[v.Name]
if info != nil {
v.Abilities = make([]int32, 0)
for _, ability := range info.Abilities {
v.Abilities = append(v.Abilities, endec.Hk4eAbilityHashCode(ability))
}
}
}
}
}
// TODO 成长属性要读表
func (a *AvatarData) GetBaseHpByLevel(level uint8) float64 {
return a.HpBase * float64(level)
}
func (a *AvatarData) GetBaseAttackByLevel(level uint8) float64 {
return a.AttackBase * float64(level)
}
func (a *AvatarData) GetBaseDefenseByLevel(level uint8) float64 {
return a.DefenseBase * float64(level)
}

View File

@@ -0,0 +1,65 @@
package config
import (
"encoding/json"
"flswld.com/logger"
"game-hk4e/constant"
"io/ioutil"
)
type AvatarSkillData struct {
Id int32 `json:"id"`
CdTime float64 `json:"cdTime"`
CostElemVal int32 `json:"costElemVal"`
MaxChargeNum int32 `json:"maxChargeNum"`
TriggerID int32 `json:"triggerID"`
IsAttackCameraLock bool `json:"isAttackCameraLock"`
ProudSkillGroupId int32 `json:"proudSkillGroupId"`
CostElemType string `json:"costElemType"`
LockWeightParams []float64 `json:"lockWeightParams"`
NameTextMapHash int64 `json:"nameTextMapHash"`
AbilityName string `json:"abilityName"`
LockShape string `json:"lockShape"`
GlobalValueKey string `json:"globalValueKey"`
// 计算属性
CostElemTypeX *constant.ElementTypeValue `json:"-"`
}
func (g *GameDataConfig) loadAvatarSkillData() {
g.AvatarSkillDataMap = make(map[int32]*AvatarSkillData)
fileNameList := []string{"AvatarSkillExcelConfigData.json"}
for _, fileName := range fileNameList {
fileData, err := ioutil.ReadFile(g.excelBinPrefix + fileName)
if err != nil {
logger.LOG.Error("open file error: %v", err)
continue
}
list := make([]map[string]any, 0)
err = json.Unmarshal(fileData, &list)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
for _, v := range list {
i, err := json.Marshal(v)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
avatarSkillData := new(AvatarSkillData)
err = json.Unmarshal(i, avatarSkillData)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
g.AvatarSkillDataMap[avatarSkillData.Id] = avatarSkillData
}
}
logger.LOG.Info("load %v AvatarSkillData", len(g.AvatarSkillDataMap))
for _, v := range g.AvatarSkillDataMap {
v.CostElemTypeX = constant.ElementTypeConst.STRING_MAP[v.CostElemType]
}
}

View File

@@ -0,0 +1,84 @@
package config
import (
"encoding/json"
"flswld.com/common/utils/endec"
"flswld.com/logger"
"game-hk4e/constant"
"io/ioutil"
)
type InherentProudSkillOpens struct {
ProudSkillGroupId int32 `json:"proudSkillGroupId"`
NeedAvatarPromoteLevel int32 `json:"needAvatarPromoteLevel"`
}
type AvatarSkillDepotData struct {
Id int32 `json:"id"`
EnergySkill int32 `json:"energySkill"`
AttackModeSkill int32 `json:"attackModeSkill"`
Skills []int32 `json:"skills"`
SubSkills []int32 `json:"subSkills"`
ExtraAbilities []string `json:"extraAbilities"`
Talents []int32 `json:"talents"`
InherentProudSkillOpens []*InherentProudSkillOpens `json:"inherentProudSkillOpens"`
TalentStarName string `json:"talentStarName"`
SkillDepotAbilityGroup string `json:"skillDepotAbilityGroup"`
// 计算属性
EnergySkillData *AvatarSkillData `json:"-"`
ElementType *constant.ElementTypeValue `json:"-"`
Abilities []int32 `json:"-"`
}
func (g *GameDataConfig) loadAvatarSkillDepotData() {
g.AvatarSkillDepotDataMap = make(map[int32]*AvatarSkillDepotData)
fileNameList := []string{"AvatarSkillDepotExcelConfigData.json"}
for _, fileName := range fileNameList {
fileData, err := ioutil.ReadFile(g.excelBinPrefix + fileName)
if err != nil {
logger.LOG.Error("open file error: %v", err)
continue
}
list := make([]map[string]any, 0)
err = json.Unmarshal(fileData, &list)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
for _, v := range list {
i, err := json.Marshal(v)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
avatarSkillDepotData := new(AvatarSkillDepotData)
err = json.Unmarshal(i, avatarSkillDepotData)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
g.AvatarSkillDepotDataMap[avatarSkillDepotData.Id] = avatarSkillDepotData
}
}
logger.LOG.Info("load %v AvatarSkillDepotData", len(g.AvatarSkillDepotDataMap))
for _, v := range g.AvatarSkillDepotDataMap {
// set energy skill data
v.EnergySkillData = g.AvatarSkillDataMap[v.EnergySkill]
if v.EnergySkillData != nil {
v.ElementType = v.EnergySkillData.CostElemTypeX
} else {
v.ElementType = constant.ElementTypeConst.None
}
// set embryo abilities if player skill depot
if v.SkillDepotAbilityGroup != "" {
config := g.GameDepot.PlayerAbilities[v.SkillDepotAbilityGroup]
if config != nil {
for _, targetAbility := range config.TargetAbilities {
v.Abilities = append(v.Abilities, endec.Hk4eAbilityHashCode(targetAbility.AbilityName))
}
}
}
}
}

View File

@@ -0,0 +1,59 @@
package config
import (
"flswld.com/logger"
"github.com/jszwec/csvutil"
"io/ioutil"
"strings"
)
type Drop struct {
DropId int32 `csv:"DropId"`
Weight int32 `csv:"Weight"`
Result int32 `csv:"Result"`
IsEnd bool `csv:"IsEnd"`
}
type DropGroupData struct {
DropId int32
WeightAll int32
DropConfig []*Drop
}
func (g *GameDataConfig) loadDropGroupData() {
g.DropGroupDataMap = make(map[int32]*DropGroupData)
fileNameList := []string{"DropGachaAvatarUp.csv", "DropGachaWeaponUp.csv", "DropGachaNormal.csv"}
for _, fileName := range fileNameList {
fileData, err := ioutil.ReadFile(g.csvPrefix + fileName)
if err != nil {
logger.LOG.Error("open file error: %v", err)
return
}
// 去除第二三行的内容变成标准格式的csv
index1 := strings.Index(string(fileData), "\n")
index2 := strings.Index(string(fileData[(index1+1):]), "\n")
index3 := strings.Index(string(fileData[(index2+1)+(index1+1):]), "\n")
standardCsvData := make([]byte, 0)
standardCsvData = append(standardCsvData, fileData[:index1]...)
standardCsvData = append(standardCsvData, fileData[index3+(index2+1)+(index1+1):]...)
var dropList []*Drop
err = csvutil.Unmarshal(standardCsvData, &dropList)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
return
}
for _, drop := range dropList {
dropGroupData, exist := g.DropGroupDataMap[drop.DropId]
if !exist {
dropGroupData = new(DropGroupData)
dropGroupData.DropId = drop.DropId
dropGroupData.WeightAll = 0
dropGroupData.DropConfig = make([]*Drop, 0)
g.DropGroupDataMap[drop.DropId] = dropGroupData
}
dropGroupData.WeightAll += drop.Weight
dropGroupData.DropConfig = append(dropGroupData.DropConfig, drop)
}
}
logger.LOG.Info("load %v DropGroupData", len(g.DropGroupDataMap))
}

View File

@@ -0,0 +1,54 @@
package config
import (
"encoding/json"
"flswld.com/logger"
"io/ioutil"
)
type FetterData struct {
AvatarId int32 `json:"avatarId"`
FetterId int32 `json:"fetterId"`
}
func (g *GameDataConfig) loadFetterData() {
g.FetterDataMap = make(map[int32]*FetterData)
fileNameList := []string{"FetterInfoExcelConfigData.json", "FettersExcelConfigData.json", "FetterStoryExcelConfigData.json", "PhotographExpressionExcelConfigData.json", "PhotographPosenameExcelConfigData.json"}
for _, fileName := range fileNameList {
fileData, err := ioutil.ReadFile(g.excelBinPrefix + fileName)
if err != nil {
logger.LOG.Error("open file error: %v", err)
continue
}
list := make([]map[string]any, 0)
err = json.Unmarshal(fileData, &list)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
for _, v := range list {
i, err := json.Marshal(v)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
fetterData := new(FetterData)
err = json.Unmarshal(i, fetterData)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
g.FetterDataMap[fetterData.FetterId] = fetterData
}
}
logger.LOG.Info("load %v FetterData", len(g.FetterDataMap))
g.AvatarFetterDataMap = make(map[int32][]int32)
for _, v := range g.FetterDataMap {
avatarFetterIdList, exist := g.AvatarFetterDataMap[v.AvatarId]
if !exist {
avatarFetterIdList = make([]int32, 0)
}
avatarFetterIdList = append(avatarFetterIdList, v.FetterId)
g.AvatarFetterDataMap[v.AvatarId] = avatarFetterIdList
}
}

View File

@@ -0,0 +1,60 @@
package config
import (
"encoding/json"
"flswld.com/logger"
"game-hk4e/constant"
"io/ioutil"
)
type GadgetData struct {
Id int32 `json:"id"`
Type string `json:"type"`
JsonName string `json:"jsonName"`
IsInteractive bool `json:"isInteractive"`
Tags []string `json:"tags"`
ItemJsonName string `json:"itemJsonName"`
InteeIconName string `json:"inteeIconName"`
NameTextMapHash int64 `json:"nameTextMapHash"`
CampID int32 `json:"campID"`
LODPatternName string `json:"LODPatternName"`
// 计算属性
TypeX uint16 `json:"-"`
}
func (g *GameDataConfig) loadGadgetData() {
g.GadgetDataMap = make(map[int32]*GadgetData)
fileNameList := []string{"GadgetExcelConfigData.json"}
for _, fileName := range fileNameList {
fileData, err := ioutil.ReadFile(g.excelBinPrefix + fileName)
if err != nil {
logger.LOG.Error("open file error: %v", err)
continue
}
list := make([]map[string]any, 0)
err = json.Unmarshal(fileData, &list)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
for _, v := range list {
i, err := json.Marshal(v)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
gadgetData := new(GadgetData)
err = json.Unmarshal(i, gadgetData)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
g.GadgetDataMap[gadgetData.Id] = gadgetData
}
}
logger.LOG.Info("load %v GadgetData", len(g.GadgetDataMap))
for _, v := range g.GadgetDataMap {
v.TypeX = constant.EntityTypeConst.STRING_MAP[v.Type]
}
}

View File

@@ -0,0 +1,154 @@
package config
import (
appConfig "flswld.com/common/config"
"flswld.com/logger"
"io/ioutil"
"os"
"runtime"
)
var CONF *GameDataConfig = nil
type GameDataConfig struct {
binPrefix string
excelBinPrefix string
csvPrefix string
GameDepot *GameDepot
// 配置表
// BinOutput
// 技能列表
AbilityEmbryos map[string]*AbilityEmbryoEntry
OpenConfigEntries map[string]*OpenConfigEntry
// ExcelBinOutput
FetterDataMap map[int32]*FetterData
AvatarFetterDataMap map[int32][]int32
// 资源
// 场景传送点
ScenePointEntries map[string]*ScenePointEntry
ScenePointIdList []int32
// 角色
AvatarDataMap map[int32]*AvatarData
// 道具
ItemDataMap map[int32]*ItemData
// 角色技能
AvatarSkillDataMap map[int32]*AvatarSkillData
AvatarSkillDepotDataMap map[int32]*AvatarSkillDepotData
// 掉落组配置表
DropGroupDataMap map[int32]*DropGroupData
// GG
GadgetDataMap map[int32]*GadgetData
// 采集物
GatherDataMap map[int32]*GatherData
}
func InitGameDataConfig() {
CONF = new(GameDataConfig)
CONF.binPrefix = ""
CONF.excelBinPrefix = ""
CONF.csvPrefix = ""
CONF.loadAll()
}
func (g *GameDataConfig) load() {
g.loadGameDepot()
// 技能列表
g.loadAbilityEmbryos()
g.loadOpenConfig()
// 资源
g.loadFetterData()
// 场景传送点
g.loadScenePoints()
// 角色
g.loadAvatarData()
// 道具
g.loadItemData()
// 角色技能
g.loadAvatarSkillData()
g.loadAvatarSkillDepotData()
// 掉落组配置表
g.loadDropGroupData()
// GG
g.loadGadgetData()
// 采集物
g.loadGatherData()
}
func (g *GameDataConfig) getResourcePathPrefix() string {
resourcePath := appConfig.CONF.Hk4e.ResourcePath
// for dev
if runtime.GOOS == "windows" {
resourcePath = "C:/Users/FlourishingWorld/Desktop/GI/GameDataConfigTable"
}
return resourcePath
}
func (g *GameDataConfig) loadAll() {
resourcePath := g.getResourcePathPrefix()
dirInfo, err := os.Stat(resourcePath)
if err != nil || !dirInfo.IsDir() {
logger.LOG.Error("open game data config dir error: %v", err)
return
}
g.binPrefix = resourcePath + "/BinOutput"
g.excelBinPrefix = resourcePath + "/ExcelBinOutput"
g.csvPrefix = resourcePath + "/Csv"
dirInfo, err = os.Stat(g.binPrefix)
if err != nil || !dirInfo.IsDir() {
logger.LOG.Error("open game data bin output config dir error: %v", err)
return
}
dirInfo, err = os.Stat(g.excelBinPrefix)
if err != nil || !dirInfo.IsDir() {
logger.LOG.Error("open game data excel bin output config dir error: %v", err)
return
}
dirInfo, err = os.Stat(g.csvPrefix)
if err != nil || !dirInfo.IsDir() {
logger.LOG.Error("open game data csv config dir error: %v", err)
return
}
g.binPrefix += "/"
g.excelBinPrefix += "/"
g.csvPrefix += "/"
g.load()
}
func (g *GameDataConfig) ReadWorldTerrain() []byte {
resourcePath := g.getResourcePathPrefix()
dirInfo, err := os.Stat(resourcePath)
if err != nil || !dirInfo.IsDir() {
logger.LOG.Error("open game data config dir error: %v", err)
return nil
}
dirInfo, err = os.Stat(resourcePath + "/WorldStatic")
if err != nil || !dirInfo.IsDir() {
logger.LOG.Error("open game data world static dir error: %v", err)
return nil
}
data, err := ioutil.ReadFile(resourcePath + "/WorldStatic/world_terrain.bin")
if err != nil {
logger.LOG.Error("read world terrain file error: %v", err)
return nil
}
return data
}
func (g *GameDataConfig) WriteWorldTerrain(data []byte) {
resourcePath := g.getResourcePathPrefix()
dirInfo, err := os.Stat(resourcePath)
if err != nil || !dirInfo.IsDir() {
logger.LOG.Error("open game data config dir error: %v", err)
return
}
dirInfo, err = os.Stat(resourcePath + "/WorldStatic")
if err != nil || !dirInfo.IsDir() {
logger.LOG.Error("open game data world static dir error: %v", err)
return
}
err = ioutil.WriteFile(resourcePath+"/WorldStatic/world_terrain.bin", data, 0644)
if err != nil {
logger.LOG.Error("write world terrain file error: %v", err)
return
}
}

View File

@@ -0,0 +1,29 @@
package config
import (
"encoding/json"
"flswld.com/logger"
"io/ioutil"
)
type GameDepot struct {
PlayerAbilities map[string]*AvatarConfig
}
func (g *GameDataConfig) loadGameDepot() {
g.GameDepot = new(GameDepot)
playerElementsFilePath := g.binPrefix + "AbilityGroup/AbilityGroup_Other_PlayerElementAbility.json"
playerElementsFile, err := ioutil.ReadFile(playerElementsFilePath)
if err != nil {
logger.LOG.Error("open file error: %v", err)
return
}
playerAbilities := make(map[string]*AvatarConfig)
err = json.Unmarshal(playerElementsFile, &playerAbilities)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
return
}
g.GameDepot.PlayerAbilities = playerAbilities
logger.LOG.Info("load %v PlayerAbilities", len(g.GameDepot.PlayerAbilities))
}

View File

@@ -0,0 +1,50 @@
package config
import (
"encoding/json"
"flswld.com/logger"
"io/ioutil"
)
type GatherData struct {
Id int32 `json:"id"`
PointType int32 `json:"pointType"`
GadgetId int32 `json:"gadgetId"`
ItemId int32 `json:"itemId"`
Cd int32 `json:"cd"`
IsForbidGuest bool `json:"isForbidGuest"`
InitDisableInteract bool `json:"initDisableInteract"`
}
func (g *GameDataConfig) loadGatherData() {
g.GatherDataMap = make(map[int32]*GatherData)
fileNameList := []string{"GatherExcelConfigData.json"}
for _, fileName := range fileNameList {
fileData, err := ioutil.ReadFile(g.excelBinPrefix + fileName)
if err != nil {
logger.LOG.Error("open file error: %v", err)
continue
}
list := make([]map[string]any, 0)
err = json.Unmarshal(fileData, &list)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
for _, v := range list {
i, err := json.Marshal(v)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
gatherData := new(GatherData)
err = json.Unmarshal(i, gatherData)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
g.GatherDataMap[gatherData.Id] = gatherData
}
}
logger.LOG.Info("load %v GatherData", len(g.GatherDataMap))
}

View File

@@ -0,0 +1,161 @@
package config
import (
"encoding/json"
"flswld.com/logger"
"game-hk4e/constant"
"io/ioutil"
)
type ItemUseData struct {
UseOp string `json:"useOp"`
UseParam []string `json:"useParam"`
}
type WeaponProperty struct {
PropType string `json:"propType"`
InitValue float64 `json:"initValue"`
Type string `json:"type"`
FightProp uint16 `json:"-"`
}
type ItemData struct {
Id int32 `json:"id"`
StackLimit int32 `json:"stackLimit"`
MaxUseCount int32 `json:"maxUseCount"`
RankLevel int32 `json:"rankLevel"`
EffectName string `json:"effectName"`
SatiationParams []int32 `json:"satiationParams"`
Rank int32 `json:"rank"`
Weight int32 `json:"weight"`
GadgetId int32 `json:"gadgetId"`
DestroyReturnMaterial []int32 `json:"destroyReturnMaterial"`
DestroyReturnMaterialCount []int32 `json:"destroyReturnMaterialCount"`
ItemUse []*ItemUseData `json:"itemUse"`
// food
FoodQuality string `json:"foodQuality"`
UseTarget string `json:"useTarget"`
IseParam []string `json:"iseParam"`
// string enums
ItemType string `json:"itemType"`
MaterialType string `json:"materialType"`
EquipType string `json:"equipType"`
EffectType string `json:"effectType"`
DestroyRule string `json:"destroyRule"`
// post load enum forms of above
MaterialEnumType uint16 `json:"-"`
ItemEnumType uint16 `json:"-"`
EquipEnumType uint16 `json:"-"`
// relic
MainPropDepotId int32 `json:"mainPropDepotId"`
AppendPropDepotId int32 `json:"appendPropDepotId"`
AppendPropNum int32 `json:"appendPropNum"`
SetId int32 `json:"setId"`
AddPropLevels []int32 `json:"addPropLevels"`
BaseConvExp int32 `json:"baseConvExp"`
MaxLevel int32 `json:"maxLevel"`
// weapon
WeaponPromoteId int32 `json:"weaponPromoteId"`
WeaponBaseExp int32 `json:"weaponBaseExp"`
StoryId int32 `json:"storyId"`
AvatarPromoteId int32 `json:"avatarPromoteId"`
AwakenMaterial int32 `json:"awakenMaterial"`
AwakenCosts []int32 `json:"awakenCosts"`
SkillAffix []int32 `json:"skillAffix"`
WeaponProp []*WeaponProperty `json:"weaponProp"`
// hash
Icon string `json:"icon"`
NameTextMapHash int64 `json:"nameTextMapHash"`
AddPropLevelSet map[int32]bool `json:"-"`
// furniture
Comfort int32 `json:"comfort"`
FurnType []int32 `json:"furnType"`
FurnitureGadgetID []int32 `json:"furnitureGadgetID"`
RoomSceneId int32 `json:"roomSceneId"`
}
func (g *GameDataConfig) loadItemData() {
g.ItemDataMap = make(map[int32]*ItemData)
fileNameList := []string{"MaterialExcelConfigData.json", "WeaponExcelConfigData.json", "ReliquaryExcelConfigData.json", "HomeWorldFurnitureExcelConfigData.json"}
for _, fileName := range fileNameList {
fileData, err := ioutil.ReadFile(g.excelBinPrefix + fileName)
if err != nil {
logger.LOG.Error("open file error: %v", err)
continue
}
list := make([]map[string]any, 0)
err = json.Unmarshal(fileData, &list)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
for _, v := range list {
i, err := json.Marshal(v)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
itemData := new(ItemData)
err = json.Unmarshal(i, itemData)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
g.ItemDataMap[itemData.Id] = itemData
}
}
logger.LOG.Info("load %v ItemData", len(g.ItemDataMap))
for _, itemData := range g.ItemDataMap {
itemData.ItemEnumType = constant.ItemTypeConst.STRING_MAP[itemData.ItemType]
itemData.MaterialEnumType = constant.MaterialTypeConst.STRING_MAP[itemData.MaterialType]
if itemData.ItemEnumType == constant.ItemTypeConst.ITEM_RELIQUARY {
itemData.EquipEnumType = constant.EquipTypeConst.STRING_MAP[itemData.EquipType]
if itemData.AddPropLevels != nil || len(itemData.AddPropLevels) > 0 {
itemData.AddPropLevelSet = make(map[int32]bool)
for _, v := range itemData.AddPropLevels {
itemData.AddPropLevelSet[v] = true
}
}
} else if itemData.ItemEnumType == constant.ItemTypeConst.ITEM_WEAPON {
itemData.EquipEnumType = constant.EquipTypeConst.EQUIP_WEAPON
} else {
itemData.EquipEnumType = constant.EquipTypeConst.EQUIP_NONE
}
if itemData.WeaponProp != nil {
for i, v := range itemData.WeaponProp {
v.FightProp = constant.FightPropertyConst.STRING_MAP[v.PropType]
itemData.WeaponProp[i] = v
}
}
if itemData.FurnType != nil {
furnType := make([]int32, 0)
for _, v := range itemData.FurnType {
if v > 0 {
furnType = append(furnType, v)
}
}
itemData.FurnType = furnType
}
if itemData.FurnitureGadgetID != nil {
furnitureGadgetID := make([]int32, 0)
for _, v := range itemData.FurnitureGadgetID {
if v > 0 {
furnitureGadgetID = append(furnitureGadgetID, v)
}
}
itemData.FurnitureGadgetID = furnitureGadgetID
}
}
}

View File

@@ -0,0 +1,92 @@
package config
import (
"encoding/json"
"flswld.com/logger"
"io/ioutil"
"strings"
)
type SkillPointModifier struct {
SkillId int32
Delta int32
}
type OpenConfigEntry struct {
Name string
AddAbilities []string
ExtraTalentIndex int32
SkillPointModifiers []*SkillPointModifier
}
func NewOpenConfigEntry(name string, data []*OpenConfigData) (r *OpenConfigEntry) {
r = new(OpenConfigEntry)
r.Name = name
abilityList := make([]string, 0)
modList := make([]*SkillPointModifier, 0)
for _, v := range data {
if strings.Contains(v.DollarType, "AddAbility") {
abilityList = append(abilityList, v.AbilityName)
} else if v.TalentIndex > 0 {
r.ExtraTalentIndex = v.TalentIndex
} else if strings.Contains(v.DollarType, "ModifySkillPoint") {
modList = append(modList, &SkillPointModifier{
SkillId: v.SkillID,
Delta: v.PointDelta,
})
}
}
r.AddAbilities = abilityList
r.SkillPointModifiers = modList
return r
}
type OpenConfigData struct {
DollarType string `json:"$type"`
AbilityName string `json:"abilityName"`
TalentIndex int32 `json:"talentIndex"`
SkillID int32 `json:"skillID"`
PointDelta int32 `json:"pointDelta"`
}
func (g *GameDataConfig) loadOpenConfig() {
list := make([]*OpenConfigEntry, 0)
folderNames := []string{"Talent/EquipTalents", "Talent/AvatarTalents"}
for _, v := range folderNames {
dirPath := g.binPrefix + v
fileList, err := ioutil.ReadDir(dirPath)
if err != nil {
logger.LOG.Error("open dir error: %v", err)
return
}
for _, file := range fileList {
fileName := file.Name()
if !strings.Contains(fileName, ".json") {
continue
}
config := make(map[string][]*OpenConfigData)
fileData, err := ioutil.ReadFile(dirPath + "/" + fileName)
if err != nil {
logger.LOG.Error("open file error: %v", err)
continue
}
err = json.Unmarshal(fileData, &config)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
for kk, vv := range config {
entry := NewOpenConfigEntry(kk, vv)
list = append(list, entry)
}
}
}
if len(list) == 0 {
logger.LOG.Error("no open config entries load")
}
g.OpenConfigEntries = make(map[string]*OpenConfigEntry)
for _, v := range list {
g.OpenConfigEntries[v.Name] = v
}
logger.LOG.Info("load %v OpenConfig", len(g.OpenConfigEntries))
}

View File

@@ -0,0 +1,6 @@
package config
type PropGrowCurve struct {
Type string `json:"type"`
GrowCurve string `json:"growCurve"`
}

View File

@@ -0,0 +1,85 @@
package config
import (
"encoding/json"
"flswld.com/logger"
"io/ioutil"
"strconv"
"strings"
)
type ScenePointEntry struct {
Name string
PointData *PointData
}
type ScenePointConfig struct {
Points map[string]*PointData `json:"points"`
}
type PointData struct {
Id int32 `json:"-"`
DollarType string `json:"$type"`
TranPos *Position `json:"tranPos"`
DungeonIds []int32 `json:"dungeonIds"`
DungeonRandomList []int32 `json:"dungeonRandomList"`
TranSceneId int32 `json:"tranSceneId"`
}
type Position struct {
X float64 `json:"x"`
Y float64 `json:"y"`
Z float64 `json:"z"`
}
func (g *GameDataConfig) loadScenePoints() {
g.ScenePointEntries = make(map[string]*ScenePointEntry)
g.ScenePointIdList = make([]int32, 0)
dirPath := g.binPrefix + "Scene/Point"
fileList, err := ioutil.ReadDir(dirPath)
if err != nil {
logger.LOG.Error("open dir error: %v", err)
return
}
for _, file := range fileList {
fileName := file.Name()
if !strings.Contains(fileName, "scene") {
continue
}
startIndex := strings.Index(fileName, "scene")
endIndex := strings.Index(fileName, "_point.json")
if startIndex == -1 || endIndex == -1 || startIndex+5 > endIndex {
logger.LOG.Error("file name format error: %v", fileName)
continue
}
sceneId := fileName[startIndex+5 : endIndex]
fileData, err := ioutil.ReadFile(dirPath + "/" + fileName)
if err != nil {
logger.LOG.Error("open file error: %v", err)
continue
}
scenePointConfig := new(ScenePointConfig)
err = json.Unmarshal(fileData, scenePointConfig)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
if len(scenePointConfig.Points) == 0 {
continue
}
for k, v := range scenePointConfig.Points {
sceneIdInt32, err := strconv.ParseInt(k, 10, 32)
if err != nil {
logger.LOG.Error("parse file error: %v", err)
continue
}
v.Id = int32(sceneIdInt32)
scenePointEntry := new(ScenePointEntry)
scenePointEntry.Name = sceneId + "_" + k
scenePointEntry.PointData = v
g.ScenePointIdList = append(g.ScenePointIdList, int32(sceneIdInt32))
g.ScenePointEntries[scenePointEntry.Name] = scenePointEntry
}
}
logger.LOG.Info("load %v ScenePointEntries", len(g.ScenePointEntries))
}

View File

@@ -0,0 +1,357 @@
package constant
var ActionReasonConst *ActionReason
type ActionReason struct {
None uint16
QuestItem uint16
QuestReward uint16
Trifle uint16
Shop uint16
PlayerUpgradeReward uint16
AddAvatar uint16
GadgetEnvAnimal uint16
MonsterEnvAnimal uint16
Compound uint16
Cook uint16
Gather uint16
MailAttachment uint16
CityLevelupReturn uint16
CityLevelupReward uint16
AreaExploreReward uint16
UnlockPointReward uint16
DungeonFirstPass uint16
DungeonPass uint16
ChangeElemType uint16
FetterOpen uint16
DailyTaskScore uint16
DailyTaskHost uint16
RandTaskHost uint16
Expedition uint16
Gacha uint16
Combine uint16
RandTaskGuest uint16
DailyTaskGuest uint16
ForgeOutput uint16
ForgeReturn uint16
InitAvatar uint16
MonsterDie uint16
Gm uint16
OpenChest uint16
GadgetDie uint16
MonsterChangeHp uint16
SubfieldDrop uint16
PushTipsReward uint16
ActivityMonsterDrop uint16
ActivityGather uint16
ActivitySubfieldDrop uint16
TowerScheduleReward uint16
TowerFloorStarReward uint16
TowerFirstPassReward uint16
TowerDailyReward uint16
HitClientTrivialEntity uint16
OpenWorldBossChest uint16
MaterialDeleteReturn uint16
SignInReward uint16
OpenBlossomChest uint16
Recharge uint16
BonusActivityReward uint16
TowerCommemorativeReward uint16
TowerSkipFloorReward uint16
RechargeBonus uint16
RechargeCard uint16
RechargeCardDaily uint16
RechargeCardReplace uint16
RechargeCardReplaceFree uint16
RechargePlayReplace uint16
MpPlayTakeReward uint16
ActivityWatcher uint16
SalesmanDeliverItem uint16
SalesmanReward uint16
Rebate uint16
McoinExchangeHcoin uint16
DailyTaskExchangeLegendaryKey uint16
UnlockPersonLine uint16
FetterLevelReward uint16
BuyResin uint16
RechargePackage uint16
DeliveryDailyReward uint16
CityReputationLevel uint16
CityReputationQuest uint16
CityReputationRequest uint16
CityReputationExplore uint16
OffergingLevel uint16
RoutineHost uint16
RoutineGuest uint16
TreasureMapSpotToken uint16
TreasureMapBonusLevelReward uint16
TreasureMapMpReward uint16
Convert uint16
OverflowTransform uint16
ActivityAvatarSelectionReward uint16
ActivityWatcherBatch uint16
HitTreeDrop uint16
GetHomeLevelupReward uint16
HomeDefaultFurniture uint16
ActivityCond uint16
BattlePassNotify uint16
PlayerUseItem uint16
DropItem uint16
WeaponUpgrade uint16
WeaponPromote uint16
WeaponAwaken uint16
RelicUpgrade uint16
Ability uint16
DungeonStatueDrop uint16
OfflineMsg uint16
AvatarUpgrade uint16
AvatarPromote uint16
QuestAction uint16
CityLevelup uint16
UpgradeSkill uint16
UnlockTalent uint16
UpgradeProudSkill uint16
PlayerLevelLimitUp uint16
DungeonDaily uint16
ItemGiving uint16
ForgeCost uint16
InvestigationReward uint16
InvestigationTargetReward uint16
GadgetInteract uint16
SeaLampCiMaterial uint16
SeaLampContributionReward uint16
SeaLampPhaseReward uint16
SeaLampFlyLamp uint16
AutoRecover uint16
ActivityExpireItem uint16
SubCoinNegative uint16
BargainDeduct uint16
BattlePassPaidReward uint16
BattlePassLevelReward uint16
TrialAvatarActivityFirstPassReward uint16
BuyBattlePassLevel uint16
GrantBirthdayBenefit uint16
AchievementReward uint16
AchievementGoalReward uint16
FirstShareToSocialNetwork uint16
DestroyMaterial uint16
CodexLevelupReward uint16
HuntingOfferReward uint16
UseWidgetAnchorPoint uint16
UseWidgetBonfire uint16
UngradeWeaponReturnMaterial uint16
UseWidgetOneoffGatherPointDetector uint16
UseWidgetClientCollector uint16
UseWidgetClientDetector uint16
TakeGeneralReward uint16
AsterTakeSpecialReward uint16
RemoveCodexBook uint16
OfferingItem uint16
UseWidgetGadgetBuilder uint16
EffigyFirstPassReward uint16
EffigyReward uint16
ReunionFirstGiftReward uint16
ReunionSignInReward uint16
ReunionWatcherReward uint16
SalesmanMpReward uint16
ActionReasionAvatarPromoteReward uint16
BlessingRedeemReward uint16
ActionMiracleRingReward uint16
ExpeditionReward uint16
TreasureMapRemoveDetector uint16
MechanicusDungeonTicket uint16
MechanicusLevelupGear uint16
MechanicusBattleSettle uint16
RegionSearchReward uint16
UnlockCoopChapter uint16
TakeCoopReward uint16
FleurFairDungeonReward uint16
ActivityScore uint16
ChannellerSlabOneoffDungeonReward uint16
FurnitureMakeStart uint16
FurnitureMakeTake uint16
FurnitureMakeCancel uint16
FurnitureMakeFastFinish uint16
ChannellerSlabLoopDungeonFirstPassReward uint16
ChannellerSlabLoopDungeonScoreReward uint16
HomeLimitedShopBuy uint16
HomeCoinCollect uint16
}
func InitActionReasonConst() {
ActionReasonConst = new(ActionReason)
ActionReasonConst.None = 0
ActionReasonConst.QuestItem = 1
ActionReasonConst.QuestReward = 2
ActionReasonConst.Trifle = 3
ActionReasonConst.Shop = 4
ActionReasonConst.PlayerUpgradeReward = 5
ActionReasonConst.AddAvatar = 6
ActionReasonConst.GadgetEnvAnimal = 7
ActionReasonConst.MonsterEnvAnimal = 8
ActionReasonConst.Compound = 9
ActionReasonConst.Cook = 10
ActionReasonConst.Gather = 11
ActionReasonConst.MailAttachment = 12
ActionReasonConst.CityLevelupReturn = 15
ActionReasonConst.CityLevelupReward = 17
ActionReasonConst.AreaExploreReward = 18
ActionReasonConst.UnlockPointReward = 19
ActionReasonConst.DungeonFirstPass = 20
ActionReasonConst.DungeonPass = 21
ActionReasonConst.ChangeElemType = 23
ActionReasonConst.FetterOpen = 25
ActionReasonConst.DailyTaskScore = 26
ActionReasonConst.DailyTaskHost = 27
ActionReasonConst.RandTaskHost = 28
ActionReasonConst.Expedition = 29
ActionReasonConst.Gacha = 30
ActionReasonConst.Combine = 31
ActionReasonConst.RandTaskGuest = 32
ActionReasonConst.DailyTaskGuest = 33
ActionReasonConst.ForgeOutput = 34
ActionReasonConst.ForgeReturn = 35
ActionReasonConst.InitAvatar = 36
ActionReasonConst.MonsterDie = 37
ActionReasonConst.Gm = 38
ActionReasonConst.OpenChest = 39
ActionReasonConst.GadgetDie = 40
ActionReasonConst.MonsterChangeHp = 41
ActionReasonConst.SubfieldDrop = 42
ActionReasonConst.PushTipsReward = 43
ActionReasonConst.ActivityMonsterDrop = 44
ActionReasonConst.ActivityGather = 45
ActionReasonConst.ActivitySubfieldDrop = 46
ActionReasonConst.TowerScheduleReward = 47
ActionReasonConst.TowerFloorStarReward = 48
ActionReasonConst.TowerFirstPassReward = 49
ActionReasonConst.TowerDailyReward = 50
ActionReasonConst.HitClientTrivialEntity = 51
ActionReasonConst.OpenWorldBossChest = 52
ActionReasonConst.MaterialDeleteReturn = 53
ActionReasonConst.SignInReward = 54
ActionReasonConst.OpenBlossomChest = 55
ActionReasonConst.Recharge = 56
ActionReasonConst.BonusActivityReward = 57
ActionReasonConst.TowerCommemorativeReward = 58
ActionReasonConst.TowerSkipFloorReward = 59
ActionReasonConst.RechargeBonus = 60
ActionReasonConst.RechargeCard = 61
ActionReasonConst.RechargeCardDaily = 62
ActionReasonConst.RechargeCardReplace = 63
ActionReasonConst.RechargeCardReplaceFree = 64
ActionReasonConst.RechargePlayReplace = 65
ActionReasonConst.MpPlayTakeReward = 66
ActionReasonConst.ActivityWatcher = 67
ActionReasonConst.SalesmanDeliverItem = 68
ActionReasonConst.SalesmanReward = 69
ActionReasonConst.Rebate = 70
ActionReasonConst.McoinExchangeHcoin = 71
ActionReasonConst.DailyTaskExchangeLegendaryKey = 72
ActionReasonConst.UnlockPersonLine = 73
ActionReasonConst.FetterLevelReward = 74
ActionReasonConst.BuyResin = 75
ActionReasonConst.RechargePackage = 76
ActionReasonConst.DeliveryDailyReward = 77
ActionReasonConst.CityReputationLevel = 78
ActionReasonConst.CityReputationQuest = 79
ActionReasonConst.CityReputationRequest = 80
ActionReasonConst.CityReputationExplore = 81
ActionReasonConst.OffergingLevel = 82
ActionReasonConst.RoutineHost = 83
ActionReasonConst.RoutineGuest = 84
ActionReasonConst.TreasureMapSpotToken = 89
ActionReasonConst.TreasureMapBonusLevelReward = 90
ActionReasonConst.TreasureMapMpReward = 91
ActionReasonConst.Convert = 92
ActionReasonConst.OverflowTransform = 93
ActionReasonConst.ActivityAvatarSelectionReward = 96
ActionReasonConst.ActivityWatcherBatch = 97
ActionReasonConst.HitTreeDrop = 98
ActionReasonConst.GetHomeLevelupReward = 99
ActionReasonConst.HomeDefaultFurniture = 100
ActionReasonConst.ActivityCond = 101
ActionReasonConst.BattlePassNotify = 102
ActionReasonConst.PlayerUseItem = 1001
ActionReasonConst.DropItem = 1002
ActionReasonConst.WeaponUpgrade = 1011
ActionReasonConst.WeaponPromote = 1012
ActionReasonConst.WeaponAwaken = 1013
ActionReasonConst.RelicUpgrade = 1014
ActionReasonConst.Ability = 1015
ActionReasonConst.DungeonStatueDrop = 1016
ActionReasonConst.OfflineMsg = 1017
ActionReasonConst.AvatarUpgrade = 1018
ActionReasonConst.AvatarPromote = 1019
ActionReasonConst.QuestAction = 1021
ActionReasonConst.CityLevelup = 1022
ActionReasonConst.UpgradeSkill = 1024
ActionReasonConst.UnlockTalent = 1025
ActionReasonConst.UpgradeProudSkill = 1026
ActionReasonConst.PlayerLevelLimitUp = 1027
ActionReasonConst.DungeonDaily = 1028
ActionReasonConst.ItemGiving = 1030
ActionReasonConst.ForgeCost = 1031
ActionReasonConst.InvestigationReward = 1032
ActionReasonConst.InvestigationTargetReward = 1033
ActionReasonConst.GadgetInteract = 1034
ActionReasonConst.SeaLampCiMaterial = 1036
ActionReasonConst.SeaLampContributionReward = 1037
ActionReasonConst.SeaLampPhaseReward = 1038
ActionReasonConst.SeaLampFlyLamp = 1039
ActionReasonConst.AutoRecover = 1040
ActionReasonConst.ActivityExpireItem = 1041
ActionReasonConst.SubCoinNegative = 1042
ActionReasonConst.BargainDeduct = 1043
ActionReasonConst.BattlePassPaidReward = 1044
ActionReasonConst.BattlePassLevelReward = 1045
ActionReasonConst.TrialAvatarActivityFirstPassReward = 1046
ActionReasonConst.BuyBattlePassLevel = 1047
ActionReasonConst.GrantBirthdayBenefit = 1048
ActionReasonConst.AchievementReward = 1049
ActionReasonConst.AchievementGoalReward = 1050
ActionReasonConst.FirstShareToSocialNetwork = 1051
ActionReasonConst.DestroyMaterial = 1052
ActionReasonConst.CodexLevelupReward = 1053
ActionReasonConst.HuntingOfferReward = 1054
ActionReasonConst.UseWidgetAnchorPoint = 1055
ActionReasonConst.UseWidgetBonfire = 1056
ActionReasonConst.UngradeWeaponReturnMaterial = 1057
ActionReasonConst.UseWidgetOneoffGatherPointDetector = 1058
ActionReasonConst.UseWidgetClientCollector = 1059
ActionReasonConst.UseWidgetClientDetector = 1060
ActionReasonConst.TakeGeneralReward = 1061
ActionReasonConst.AsterTakeSpecialReward = 1062
ActionReasonConst.RemoveCodexBook = 1063
ActionReasonConst.OfferingItem = 1064
ActionReasonConst.UseWidgetGadgetBuilder = 1065
ActionReasonConst.EffigyFirstPassReward = 1066
ActionReasonConst.EffigyReward = 1067
ActionReasonConst.ReunionFirstGiftReward = 1068
ActionReasonConst.ReunionSignInReward = 1069
ActionReasonConst.ReunionWatcherReward = 1070
ActionReasonConst.SalesmanMpReward = 1071
ActionReasonConst.ActionReasionAvatarPromoteReward = 1072
ActionReasonConst.BlessingRedeemReward = 1073
ActionReasonConst.ActionMiracleRingReward = 1074
ActionReasonConst.ExpeditionReward = 1075
ActionReasonConst.TreasureMapRemoveDetector = 1076
ActionReasonConst.MechanicusDungeonTicket = 1077
ActionReasonConst.MechanicusLevelupGear = 1078
ActionReasonConst.MechanicusBattleSettle = 1079
ActionReasonConst.RegionSearchReward = 1080
ActionReasonConst.UnlockCoopChapter = 1081
ActionReasonConst.TakeCoopReward = 1082
ActionReasonConst.FleurFairDungeonReward = 1083
ActionReasonConst.ActivityScore = 1084
ActionReasonConst.ChannellerSlabOneoffDungeonReward = 1085
ActionReasonConst.FurnitureMakeStart = 1086
ActionReasonConst.FurnitureMakeTake = 1087
ActionReasonConst.FurnitureMakeCancel = 1088
ActionReasonConst.FurnitureMakeFastFinish = 1089
ActionReasonConst.ChannellerSlabLoopDungeonFirstPassReward = 1090
ActionReasonConst.ChannellerSlabLoopDungeonScoreReward = 1091
ActionReasonConst.HomeLimitedShopBuy = 1092
ActionReasonConst.HomeCoinCollect = 1093
}

View File

@@ -0,0 +1,25 @@
package constant
var ClimateTypeConst *ClimateType
type ClimateType struct {
CLIMATE_NONE uint16
CLIMATE_SUNNY uint16
CLIMATE_CLOUDY uint16
CLIMATE_RAIN uint16
CLIMATE_THUNDERSTORM uint16
CLIMATE_SNOW uint16
CLIMATE_MIST uint16
}
func InitClimateTypeConst() {
ClimateTypeConst = new(ClimateType)
ClimateTypeConst.CLIMATE_NONE = 0
ClimateTypeConst.CLIMATE_SUNNY = 1
ClimateTypeConst.CLIMATE_CLOUDY = 2
ClimateTypeConst.CLIMATE_RAIN = 3
ClimateTypeConst.CLIMATE_THUNDERSTORM = 4
ClimateTypeConst.CLIMATE_SNOW = 5
ClimateTypeConst.CLIMATE_MIST = 6
}

View File

@@ -0,0 +1,21 @@
package constant
func InitConstant() {
InitFightPropertyConst()
InitActionReasonConst()
InitClimateTypeConst()
InitElementTypeConst()
InitEnterReasonConst()
InitEntityIdTypeConst()
InitEquipTypeConst()
InitFetterStateConst()
InitGameConstant()
InitGrowCurveConst()
InitItemTypeConst()
InitLifeStateConst()
InitMaterialTypeConst()
InitOpenStateConst()
InitPlayerPropertyConst()
InitSceneTypeConst()
InitEntityTypeConst()
}

View File

@@ -0,0 +1,151 @@
package constant
import "flswld.com/common/utils/endec"
var ElementTypeConst *ElementType
type ElementTypeValue struct {
Value uint16
CurrEnergyProp uint16
MaxEnergyProp uint16
TeamResonanceId uint16
ConfigName string
ConfigHash int32
}
type ElementType struct {
None *ElementTypeValue
Fire *ElementTypeValue
Water *ElementTypeValue
Grass *ElementTypeValue
Electric *ElementTypeValue
Ice *ElementTypeValue
Frozen *ElementTypeValue
Wind *ElementTypeValue
Rock *ElementTypeValue
AntiFire *ElementTypeValue
Default *ElementTypeValue
STRING_MAP map[string]*ElementTypeValue
VALUE_MAP map[uint16]*ElementTypeValue
}
func InitElementTypeConst() {
ElementTypeConst = new(ElementType)
ElementTypeConst.None = &ElementTypeValue{
0,
FightPropertyConst.FIGHT_PROP_CUR_FIRE_ENERGY,
FightPropertyConst.FIGHT_PROP_MAX_FIRE_ENERGY,
0,
"",
endec.Hk4eAbilityHashCode(""),
}
ElementTypeConst.Fire = &ElementTypeValue{
1,
FightPropertyConst.FIGHT_PROP_CUR_FIRE_ENERGY,
FightPropertyConst.FIGHT_PROP_MAX_FIRE_ENERGY,
10101,
"TeamResonance_Fire_Lv2",
endec.Hk4eAbilityHashCode("TeamResonance_Fire_Lv2"),
}
ElementTypeConst.Water = &ElementTypeValue{
2,
FightPropertyConst.FIGHT_PROP_CUR_WATER_ENERGY,
FightPropertyConst.FIGHT_PROP_MAX_WATER_ENERGY,
10201,
"TeamResonance_Water_Lv2",
endec.Hk4eAbilityHashCode("TeamResonance_Water_Lv2"),
}
ElementTypeConst.Grass = &ElementTypeValue{
3,
FightPropertyConst.FIGHT_PROP_CUR_GRASS_ENERGY,
FightPropertyConst.FIGHT_PROP_MAX_GRASS_ENERGY,
0,
"",
endec.Hk4eAbilityHashCode(""),
}
ElementTypeConst.Electric = &ElementTypeValue{
4,
FightPropertyConst.FIGHT_PROP_CUR_ELEC_ENERGY,
FightPropertyConst.FIGHT_PROP_MAX_ELEC_ENERGY,
10401,
"TeamResonance_Electric_Lv2",
endec.Hk4eAbilityHashCode("TeamResonance_Electric_Lv2"),
}
ElementTypeConst.Ice = &ElementTypeValue{
5,
FightPropertyConst.FIGHT_PROP_CUR_ICE_ENERGY,
FightPropertyConst.FIGHT_PROP_MAX_ICE_ENERGY,
10601,
"TeamResonance_Ice_Lv2",
endec.Hk4eAbilityHashCode("TeamResonance_Ice_Lv2"),
}
ElementTypeConst.Frozen = &ElementTypeValue{
6,
FightPropertyConst.FIGHT_PROP_CUR_ICE_ENERGY,
FightPropertyConst.FIGHT_PROP_MAX_ICE_ENERGY,
0,
"",
endec.Hk4eAbilityHashCode(""),
}
ElementTypeConst.Wind = &ElementTypeValue{
7,
FightPropertyConst.FIGHT_PROP_CUR_WIND_ENERGY,
FightPropertyConst.FIGHT_PROP_MAX_WIND_ENERGY,
10301,
"TeamResonance_Wind_Lv2",
endec.Hk4eAbilityHashCode("TeamResonance_Wind_Lv2"),
}
ElementTypeConst.Rock = &ElementTypeValue{
8,
FightPropertyConst.FIGHT_PROP_CUR_ROCK_ENERGY,
FightPropertyConst.FIGHT_PROP_MAX_ROCK_ENERGY,
10701,
"TeamResonance_Rock_Lv2",
endec.Hk4eAbilityHashCode("TeamResonance_Rock_Lv2"),
}
ElementTypeConst.AntiFire = &ElementTypeValue{
9,
FightPropertyConst.FIGHT_PROP_CUR_FIRE_ENERGY,
FightPropertyConst.FIGHT_PROP_MAX_FIRE_ENERGY,
0,
"",
endec.Hk4eAbilityHashCode(""),
}
ElementTypeConst.Default = &ElementTypeValue{
255,
FightPropertyConst.FIGHT_PROP_CUR_FIRE_ENERGY,
FightPropertyConst.FIGHT_PROP_MAX_FIRE_ENERGY,
10801,
"TeamResonance_AllDifferent",
endec.Hk4eAbilityHashCode("TeamResonance_AllDifferent"),
}
ElementTypeConst.STRING_MAP = make(map[string]*ElementTypeValue)
ElementTypeConst.STRING_MAP["None"] = ElementTypeConst.None
ElementTypeConst.STRING_MAP["Fire"] = ElementTypeConst.Fire
ElementTypeConst.STRING_MAP["Water"] = ElementTypeConst.Water
ElementTypeConst.STRING_MAP["Grass"] = ElementTypeConst.Grass
ElementTypeConst.STRING_MAP["Electric"] = ElementTypeConst.Electric
ElementTypeConst.STRING_MAP["Ice"] = ElementTypeConst.Ice
ElementTypeConst.STRING_MAP["Frozen"] = ElementTypeConst.Frozen
ElementTypeConst.STRING_MAP["Wind"] = ElementTypeConst.Wind
ElementTypeConst.STRING_MAP["Rock"] = ElementTypeConst.Rock
ElementTypeConst.STRING_MAP["AntiFire"] = ElementTypeConst.AntiFire
ElementTypeConst.STRING_MAP["Default"] = ElementTypeConst.Default
ElementTypeConst.VALUE_MAP = make(map[uint16]*ElementTypeValue)
ElementTypeConst.VALUE_MAP[0] = ElementTypeConst.None
ElementTypeConst.VALUE_MAP[1] = ElementTypeConst.Fire
ElementTypeConst.VALUE_MAP[2] = ElementTypeConst.Water
ElementTypeConst.VALUE_MAP[3] = ElementTypeConst.Grass
ElementTypeConst.VALUE_MAP[4] = ElementTypeConst.Electric
ElementTypeConst.VALUE_MAP[5] = ElementTypeConst.Ice
ElementTypeConst.VALUE_MAP[6] = ElementTypeConst.Frozen
ElementTypeConst.VALUE_MAP[7] = ElementTypeConst.Wind
ElementTypeConst.VALUE_MAP[8] = ElementTypeConst.Rock
ElementTypeConst.VALUE_MAP[9] = ElementTypeConst.AntiFire
ElementTypeConst.VALUE_MAP[255] = ElementTypeConst.Default
}

View File

@@ -0,0 +1,75 @@
package constant
var EnterReasonConst *EnterReason
type EnterReason struct {
None uint16
Login uint16
DungeonReplay uint16
DungeonReviveOnWaypoint uint16
DungeonEnter uint16
DungeonQuit uint16
Gm uint16
QuestRollback uint16
Revival uint16
PersonalScene uint16
TransPoint uint16
ClientTransmit uint16
ForceDragBack uint16
TeamKick uint16
TeamJoin uint16
TeamBack uint16
Muip uint16
DungeonInviteAccept uint16
Lua uint16
ActivityLoadTerrain uint16
HostFromSingleToMp uint16
MpPlay uint16
AnchorPoint uint16
LuaSkipUi uint16
ReloadTerrain uint16
DraftTransfer uint16
EnterHome uint16
ExitHome uint16
ChangeHomeModule uint16
Gallery uint16
HomeSceneJump uint16
HideAndSeek uint16
}
func InitEnterReasonConst() {
EnterReasonConst = new(EnterReason)
EnterReasonConst.None = 0
EnterReasonConst.Login = 1
EnterReasonConst.DungeonReplay = 11
EnterReasonConst.DungeonReviveOnWaypoint = 12
EnterReasonConst.DungeonEnter = 13
EnterReasonConst.DungeonQuit = 14
EnterReasonConst.Gm = 21
EnterReasonConst.QuestRollback = 31
EnterReasonConst.Revival = 32
EnterReasonConst.PersonalScene = 41
EnterReasonConst.TransPoint = 42
EnterReasonConst.ClientTransmit = 43
EnterReasonConst.ForceDragBack = 44
EnterReasonConst.TeamKick = 51
EnterReasonConst.TeamJoin = 52
EnterReasonConst.TeamBack = 53
EnterReasonConst.Muip = 54
EnterReasonConst.DungeonInviteAccept = 55
EnterReasonConst.Lua = 56
EnterReasonConst.ActivityLoadTerrain = 57
EnterReasonConst.HostFromSingleToMp = 58
EnterReasonConst.MpPlay = 59
EnterReasonConst.AnchorPoint = 60
EnterReasonConst.LuaSkipUi = 61
EnterReasonConst.ReloadTerrain = 62
EnterReasonConst.DraftTransfer = 63
EnterReasonConst.EnterHome = 64
EnterReasonConst.ExitHome = 65
EnterReasonConst.ChangeHomeModule = 66
EnterReasonConst.Gallery = 67
EnterReasonConst.HomeSceneJump = 68
EnterReasonConst.HideAndSeek = 69
}

View File

@@ -0,0 +1,25 @@
package constant
var EntityIdTypeConst *EntityIdType
type EntityIdType struct {
AVATAR uint16
MONSTER uint16
NPC uint16
GADGET uint16
WEAPON uint16
TEAM uint16
MPLEVEL uint16
}
func InitEntityIdTypeConst() {
EntityIdTypeConst = new(EntityIdType)
EntityIdTypeConst.AVATAR = 0x01
EntityIdTypeConst.MONSTER = 0x02
EntityIdTypeConst.NPC = 0x03
EntityIdTypeConst.GADGET = 0x04
EntityIdTypeConst.WEAPON = 0x06
EntityIdTypeConst.TEAM = 0x09
EntityIdTypeConst.MPLEVEL = 0x0b
}

View File

@@ -0,0 +1,180 @@
package constant
var EntityTypeConst *EntityType
type EntityType struct {
None uint16
Avatar uint16
Monster uint16
Bullet uint16
AttackPhyisicalUnit uint16
AOE uint16
Camera uint16
EnviroArea uint16
Equip uint16
MonsterEquip uint16
Grass uint16
Level uint16
NPC uint16
TransPointFirst uint16
TransPointFirstGadget uint16
TransPointSecond uint16
TransPointSecondGadget uint16
DropItem uint16
Field uint16
Gadget uint16
Water uint16
GatherPoint uint16
GatherObject uint16
AirflowField uint16
SpeedupField uint16
Gear uint16
Chest uint16
EnergyBall uint16
ElemCrystal uint16
Timeline uint16
Worktop uint16
Team uint16
Platform uint16
AmberWind uint16
EnvAnimal uint16
SealGadget uint16
Tree uint16
Bush uint16
QuestGadget uint16
Lightning uint16
RewardPoint uint16
RewardStatue uint16
MPLevel uint16
WindSeed uint16
MpPlayRewardPoint uint16
ViewPoint uint16
RemoteAvatar uint16
GeneralRewardPoint uint16
PlayTeam uint16
OfferingGadget uint16
EyePoint uint16
MiracleRing uint16
Foundation uint16
WidgetGadget uint16
PlaceHolder uint16
STRING_MAP map[string]uint16
}
func InitEntityTypeConst() {
EntityTypeConst = new(EntityType)
EntityTypeConst.None = 0
EntityTypeConst.Avatar = 1
EntityTypeConst.Monster = 2
EntityTypeConst.Bullet = 3
EntityTypeConst.AttackPhyisicalUnit = 4
EntityTypeConst.AOE = 5
EntityTypeConst.Camera = 6
EntityTypeConst.EnviroArea = 7
EntityTypeConst.Equip = 8
EntityTypeConst.MonsterEquip = 9
EntityTypeConst.Grass = 10
EntityTypeConst.Level = 11
EntityTypeConst.NPC = 12
EntityTypeConst.TransPointFirst = 13
EntityTypeConst.TransPointFirstGadget = 14
EntityTypeConst.TransPointSecond = 15
EntityTypeConst.TransPointSecondGadget = 16
EntityTypeConst.DropItem = 17
EntityTypeConst.Field = 18
EntityTypeConst.Gadget = 19
EntityTypeConst.Water = 20
EntityTypeConst.GatherPoint = 21
EntityTypeConst.GatherObject = 22
EntityTypeConst.AirflowField = 23
EntityTypeConst.SpeedupField = 24
EntityTypeConst.Gear = 25
EntityTypeConst.Chest = 26
EntityTypeConst.EnergyBall = 27
EntityTypeConst.ElemCrystal = 28
EntityTypeConst.Timeline = 29
EntityTypeConst.Worktop = 30
EntityTypeConst.Team = 31
EntityTypeConst.Platform = 32
EntityTypeConst.AmberWind = 33
EntityTypeConst.EnvAnimal = 34
EntityTypeConst.SealGadget = 35
EntityTypeConst.Tree = 36
EntityTypeConst.Bush = 37
EntityTypeConst.QuestGadget = 38
EntityTypeConst.Lightning = 39
EntityTypeConst.RewardPoint = 40
EntityTypeConst.RewardStatue = 41
EntityTypeConst.MPLevel = 42
EntityTypeConst.WindSeed = 43
EntityTypeConst.MpPlayRewardPoint = 44
EntityTypeConst.ViewPoint = 45
EntityTypeConst.RemoteAvatar = 46
EntityTypeConst.GeneralRewardPoint = 47
EntityTypeConst.PlayTeam = 48
EntityTypeConst.OfferingGadget = 49
EntityTypeConst.EyePoint = 50
EntityTypeConst.MiracleRing = 51
EntityTypeConst.Foundation = 52
EntityTypeConst.WidgetGadget = 53
EntityTypeConst.PlaceHolder = 99
EntityTypeConst.STRING_MAP = make(map[string]uint16)
EntityTypeConst.STRING_MAP["None"] = EntityTypeConst.None
EntityTypeConst.STRING_MAP["Avatar"] = EntityTypeConst.Avatar
EntityTypeConst.STRING_MAP["Monster"] = EntityTypeConst.Monster
EntityTypeConst.STRING_MAP["Bullet"] = EntityTypeConst.Bullet
EntityTypeConst.STRING_MAP["AttackPhyisicalUnit"] = EntityTypeConst.AttackPhyisicalUnit
EntityTypeConst.STRING_MAP["AOE"] = EntityTypeConst.AOE
EntityTypeConst.STRING_MAP["Camera"] = EntityTypeConst.Camera
EntityTypeConst.STRING_MAP["EnviroArea"] = EntityTypeConst.EnviroArea
EntityTypeConst.STRING_MAP["Equip"] = EntityTypeConst.Equip
EntityTypeConst.STRING_MAP["MonsterEquip"] = EntityTypeConst.MonsterEquip
EntityTypeConst.STRING_MAP["Grass"] = EntityTypeConst.Grass
EntityTypeConst.STRING_MAP["Level"] = EntityTypeConst.Level
EntityTypeConst.STRING_MAP["NPC"] = EntityTypeConst.NPC
EntityTypeConst.STRING_MAP["TransPointFirst"] = EntityTypeConst.TransPointFirst
EntityTypeConst.STRING_MAP["TransPointFirstGadget"] = EntityTypeConst.TransPointFirstGadget
EntityTypeConst.STRING_MAP["TransPointSecond"] = EntityTypeConst.TransPointSecond
EntityTypeConst.STRING_MAP["TransPointSecondGadget"] = EntityTypeConst.TransPointSecondGadget
EntityTypeConst.STRING_MAP["DropItem"] = EntityTypeConst.DropItem
EntityTypeConst.STRING_MAP["Field"] = EntityTypeConst.Field
EntityTypeConst.STRING_MAP["Gadget"] = EntityTypeConst.Gadget
EntityTypeConst.STRING_MAP["Water"] = EntityTypeConst.Water
EntityTypeConst.STRING_MAP["GatherPoint"] = EntityTypeConst.GatherPoint
EntityTypeConst.STRING_MAP["GatherObject"] = EntityTypeConst.GatherObject
EntityTypeConst.STRING_MAP["AirflowField"] = EntityTypeConst.AirflowField
EntityTypeConst.STRING_MAP["SpeedupField"] = EntityTypeConst.SpeedupField
EntityTypeConst.STRING_MAP["Gear"] = EntityTypeConst.Gear
EntityTypeConst.STRING_MAP["Chest"] = EntityTypeConst.Chest
EntityTypeConst.STRING_MAP["EnergyBall"] = EntityTypeConst.EnergyBall
EntityTypeConst.STRING_MAP["ElemCrystal"] = EntityTypeConst.ElemCrystal
EntityTypeConst.STRING_MAP["Timeline"] = EntityTypeConst.Timeline
EntityTypeConst.STRING_MAP["Worktop"] = EntityTypeConst.Worktop
EntityTypeConst.STRING_MAP["Team"] = EntityTypeConst.Team
EntityTypeConst.STRING_MAP["Platform"] = EntityTypeConst.Platform
EntityTypeConst.STRING_MAP["AmberWind"] = EntityTypeConst.AmberWind
EntityTypeConst.STRING_MAP["EnvAnimal"] = EntityTypeConst.EnvAnimal
EntityTypeConst.STRING_MAP["SealGadget"] = EntityTypeConst.SealGadget
EntityTypeConst.STRING_MAP["Tree"] = EntityTypeConst.Tree
EntityTypeConst.STRING_MAP["Bush"] = EntityTypeConst.Bush
EntityTypeConst.STRING_MAP["QuestGadget"] = EntityTypeConst.QuestGadget
EntityTypeConst.STRING_MAP["Lightning"] = EntityTypeConst.Lightning
EntityTypeConst.STRING_MAP["RewardPoint"] = EntityTypeConst.RewardPoint
EntityTypeConst.STRING_MAP["RewardStatue"] = EntityTypeConst.RewardStatue
EntityTypeConst.STRING_MAP["MPLevel"] = EntityTypeConst.MPLevel
EntityTypeConst.STRING_MAP["WindSeed"] = EntityTypeConst.WindSeed
EntityTypeConst.STRING_MAP["MpPlayRewardPoint"] = EntityTypeConst.MpPlayRewardPoint
EntityTypeConst.STRING_MAP["ViewPoint"] = EntityTypeConst.ViewPoint
EntityTypeConst.STRING_MAP["RemoteAvatar"] = EntityTypeConst.RemoteAvatar
EntityTypeConst.STRING_MAP["GeneralRewardPoint"] = EntityTypeConst.GeneralRewardPoint
EntityTypeConst.STRING_MAP["PlayTeam"] = EntityTypeConst.PlayTeam
EntityTypeConst.STRING_MAP["OfferingGadget"] = EntityTypeConst.OfferingGadget
EntityTypeConst.STRING_MAP["EyePoint"] = EntityTypeConst.EyePoint
EntityTypeConst.STRING_MAP["MiracleRing"] = EntityTypeConst.MiracleRing
EntityTypeConst.STRING_MAP["Foundation"] = EntityTypeConst.Foundation
EntityTypeConst.STRING_MAP["WidgetGadget"] = EntityTypeConst.WidgetGadget
EntityTypeConst.STRING_MAP["PlaceHolder"] = EntityTypeConst.PlaceHolder
}

View File

@@ -0,0 +1,36 @@
package constant
var EquipTypeConst *EquipType
type EquipType struct {
EQUIP_NONE uint16
EQUIP_BRACER uint16
EQUIP_NECKLACE uint16
EQUIP_SHOES uint16
EQUIP_RING uint16
EQUIP_DRESS uint16
EQUIP_WEAPON uint16
STRING_MAP map[string]uint16
}
func InitEquipTypeConst() {
EquipTypeConst = new(EquipType)
EquipTypeConst.EQUIP_NONE = 0
EquipTypeConst.EQUIP_BRACER = 1
EquipTypeConst.EQUIP_NECKLACE = 2
EquipTypeConst.EQUIP_SHOES = 3
EquipTypeConst.EQUIP_RING = 4
EquipTypeConst.EQUIP_DRESS = 5
EquipTypeConst.EQUIP_WEAPON = 6
EquipTypeConst.STRING_MAP = make(map[string]uint16)
EquipTypeConst.STRING_MAP["EQUIP_NONE"] = 0
EquipTypeConst.STRING_MAP["EQUIP_BRACER"] = 1
EquipTypeConst.STRING_MAP["EQUIP_NECKLACE"] = 2
EquipTypeConst.STRING_MAP["EQUIP_SHOES"] = 3
EquipTypeConst.STRING_MAP["EQUIP_RING"] = 4
EquipTypeConst.STRING_MAP["EQUIP_DRESS"] = 5
EquipTypeConst.STRING_MAP["EQUIP_WEAPON"] = 6
}

View File

@@ -0,0 +1,19 @@
package constant
var FetterStateConst *FetterState
type FetterState struct {
NONE uint16
NOT_OPEN uint16
OPEN uint16
FINISH uint16
}
func InitFetterStateConst() {
FetterStateConst = new(FetterState)
FetterStateConst.NONE = 0
FetterStateConst.NOT_OPEN = 1
FetterStateConst.OPEN = 1
FetterStateConst.FINISH = 3
}

View File

@@ -0,0 +1,303 @@
package constant
var FightPropertyConst *FightProperty
type FightProperty struct {
FIGHT_PROP_NONE uint16
FIGHT_PROP_BASE_HP uint16
FIGHT_PROP_HP uint16
FIGHT_PROP_HP_PERCENT uint16
FIGHT_PROP_BASE_ATTACK uint16
FIGHT_PROP_ATTACK uint16
FIGHT_PROP_ATTACK_PERCENT uint16
FIGHT_PROP_BASE_DEFENSE uint16
FIGHT_PROP_DEFENSE uint16
FIGHT_PROP_DEFENSE_PERCENT uint16
FIGHT_PROP_BASE_SPEED uint16
FIGHT_PROP_SPEED_PERCENT uint16
FIGHT_PROP_HP_MP_PERCENT uint16
FIGHT_PROP_ATTACK_MP_PERCENT uint16
FIGHT_PROP_CRITICAL uint16
FIGHT_PROP_ANTI_CRITICAL uint16
FIGHT_PROP_CRITICAL_HURT uint16
FIGHT_PROP_CHARGE_EFFICIENCY uint16
FIGHT_PROP_ADD_HURT uint16
FIGHT_PROP_SUB_HURT uint16
FIGHT_PROP_HEAL_ADD uint16
FIGHT_PROP_HEALED_ADD uint16
FIGHT_PROP_ELEMENT_MASTERY uint16
FIGHT_PROP_PHYSICAL_SUB_HURT uint16
FIGHT_PROP_PHYSICAL_ADD_HURT uint16
FIGHT_PROP_DEFENCE_IGNORE_RATIO uint16
FIGHT_PROP_DEFENCE_IGNORE_DELTA uint16
FIGHT_PROP_FIRE_ADD_HURT uint16
FIGHT_PROP_ELEC_ADD_HURT uint16
FIGHT_PROP_WATER_ADD_HURT uint16
FIGHT_PROP_GRASS_ADD_HURT uint16
FIGHT_PROP_WIND_ADD_HURT uint16
FIGHT_PROP_ROCK_ADD_HURT uint16
FIGHT_PROP_ICE_ADD_HURT uint16
FIGHT_PROP_HIT_HEAD_ADD_HURT uint16
FIGHT_PROP_FIRE_SUB_HURT uint16
FIGHT_PROP_ELEC_SUB_HURT uint16
FIGHT_PROP_WATER_SUB_HURT uint16
FIGHT_PROP_GRASS_SUB_HURT uint16
FIGHT_PROP_WIND_SUB_HURT uint16
FIGHT_PROP_ROCK_SUB_HURT uint16
FIGHT_PROP_ICE_SUB_HURT uint16
FIGHT_PROP_EFFECT_HIT uint16
FIGHT_PROP_EFFECT_RESIST uint16
FIGHT_PROP_FREEZE_RESIST uint16
FIGHT_PROP_TORPOR_RESIST uint16
FIGHT_PROP_DIZZY_RESIST uint16
FIGHT_PROP_FREEZE_SHORTEN uint16
FIGHT_PROP_TORPOR_SHORTEN uint16
FIGHT_PROP_DIZZY_SHORTEN uint16
FIGHT_PROP_MAX_FIRE_ENERGY uint16
FIGHT_PROP_MAX_ELEC_ENERGY uint16
FIGHT_PROP_MAX_WATER_ENERGY uint16
FIGHT_PROP_MAX_GRASS_ENERGY uint16
FIGHT_PROP_MAX_WIND_ENERGY uint16
FIGHT_PROP_MAX_ICE_ENERGY uint16
FIGHT_PROP_MAX_ROCK_ENERGY uint16
FIGHT_PROP_SKILL_CD_MINUS_RATIO uint16
FIGHT_PROP_SHIELD_COST_MINUS_RATIO uint16
FIGHT_PROP_CUR_FIRE_ENERGY uint16
FIGHT_PROP_CUR_ELEC_ENERGY uint16
FIGHT_PROP_CUR_WATER_ENERGY uint16
FIGHT_PROP_CUR_GRASS_ENERGY uint16
FIGHT_PROP_CUR_WIND_ENERGY uint16
FIGHT_PROP_CUR_ICE_ENERGY uint16
FIGHT_PROP_CUR_ROCK_ENERGY uint16
FIGHT_PROP_CUR_HP uint16
FIGHT_PROP_MAX_HP uint16
FIGHT_PROP_CUR_ATTACK uint16
FIGHT_PROP_CUR_DEFENSE uint16
FIGHT_PROP_CUR_SPEED uint16
FIGHT_PROP_NONEXTRA_ATTACK uint16
FIGHT_PROP_NONEXTRA_DEFENSE uint16
FIGHT_PROP_NONEXTRA_CRITICAL uint16
FIGHT_PROP_NONEXTRA_ANTI_CRITICAL uint16
FIGHT_PROP_NONEXTRA_CRITICAL_HURT uint16
FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY uint16
FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY uint16
FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT uint16
FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT uint16
FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT uint16
FIGHT_PROP_NONEXTRA_WATER_ADD_HURT uint16
FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT uint16
FIGHT_PROP_NONEXTRA_WIND_ADD_HURT uint16
FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT uint16
FIGHT_PROP_NONEXTRA_ICE_ADD_HURT uint16
FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT uint16
FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT uint16
FIGHT_PROP_NONEXTRA_WATER_SUB_HURT uint16
FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT uint16
FIGHT_PROP_NONEXTRA_WIND_SUB_HURT uint16
FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT uint16
FIGHT_PROP_NONEXTRA_ICE_SUB_HURT uint16
FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO uint16
FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO uint16
FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT uint16
STRING_MAP map[string]uint16
}
func InitFightPropertyConst() {
FightPropertyConst = new(FightProperty)
FightPropertyConst.FIGHT_PROP_NONE = 0
FightPropertyConst.FIGHT_PROP_BASE_HP = 1
FightPropertyConst.FIGHT_PROP_HP = 2
FightPropertyConst.FIGHT_PROP_HP_PERCENT = 3
FightPropertyConst.FIGHT_PROP_BASE_ATTACK = 4
FightPropertyConst.FIGHT_PROP_ATTACK = 5
FightPropertyConst.FIGHT_PROP_ATTACK_PERCENT = 6
FightPropertyConst.FIGHT_PROP_BASE_DEFENSE = 7
FightPropertyConst.FIGHT_PROP_DEFENSE = 8
FightPropertyConst.FIGHT_PROP_DEFENSE_PERCENT = 9
FightPropertyConst.FIGHT_PROP_BASE_SPEED = 10
FightPropertyConst.FIGHT_PROP_SPEED_PERCENT = 11
FightPropertyConst.FIGHT_PROP_HP_MP_PERCENT = 12
FightPropertyConst.FIGHT_PROP_ATTACK_MP_PERCENT = 13
FightPropertyConst.FIGHT_PROP_CRITICAL = 20
FightPropertyConst.FIGHT_PROP_ANTI_CRITICAL = 21
FightPropertyConst.FIGHT_PROP_CRITICAL_HURT = 22
FightPropertyConst.FIGHT_PROP_CHARGE_EFFICIENCY = 23
FightPropertyConst.FIGHT_PROP_ADD_HURT = 24
FightPropertyConst.FIGHT_PROP_SUB_HURT = 25
FightPropertyConst.FIGHT_PROP_HEAL_ADD = 26
FightPropertyConst.FIGHT_PROP_HEALED_ADD = 27
FightPropertyConst.FIGHT_PROP_ELEMENT_MASTERY = 28
FightPropertyConst.FIGHT_PROP_PHYSICAL_SUB_HURT = 29
FightPropertyConst.FIGHT_PROP_PHYSICAL_ADD_HURT = 30
FightPropertyConst.FIGHT_PROP_DEFENCE_IGNORE_RATIO = 31
FightPropertyConst.FIGHT_PROP_DEFENCE_IGNORE_DELTA = 32
FightPropertyConst.FIGHT_PROP_FIRE_ADD_HURT = 40
FightPropertyConst.FIGHT_PROP_ELEC_ADD_HURT = 41
FightPropertyConst.FIGHT_PROP_WATER_ADD_HURT = 42
FightPropertyConst.FIGHT_PROP_GRASS_ADD_HURT = 43
FightPropertyConst.FIGHT_PROP_WIND_ADD_HURT = 44
FightPropertyConst.FIGHT_PROP_ROCK_ADD_HURT = 45
FightPropertyConst.FIGHT_PROP_ICE_ADD_HURT = 46
FightPropertyConst.FIGHT_PROP_HIT_HEAD_ADD_HURT = 47
FightPropertyConst.FIGHT_PROP_FIRE_SUB_HURT = 50
FightPropertyConst.FIGHT_PROP_ELEC_SUB_HURT = 51
FightPropertyConst.FIGHT_PROP_WATER_SUB_HURT = 52
FightPropertyConst.FIGHT_PROP_GRASS_SUB_HURT = 53
FightPropertyConst.FIGHT_PROP_WIND_SUB_HURT = 54
FightPropertyConst.FIGHT_PROP_ROCK_SUB_HURT = 55
FightPropertyConst.FIGHT_PROP_ICE_SUB_HURT = 56
FightPropertyConst.FIGHT_PROP_EFFECT_HIT = 60
FightPropertyConst.FIGHT_PROP_EFFECT_RESIST = 61
FightPropertyConst.FIGHT_PROP_FREEZE_RESIST = 62
FightPropertyConst.FIGHT_PROP_TORPOR_RESIST = 63
FightPropertyConst.FIGHT_PROP_DIZZY_RESIST = 64
FightPropertyConst.FIGHT_PROP_FREEZE_SHORTEN = 65
FightPropertyConst.FIGHT_PROP_TORPOR_SHORTEN = 66
FightPropertyConst.FIGHT_PROP_DIZZY_SHORTEN = 67
FightPropertyConst.FIGHT_PROP_MAX_FIRE_ENERGY = 70
FightPropertyConst.FIGHT_PROP_MAX_ELEC_ENERGY = 71
FightPropertyConst.FIGHT_PROP_MAX_WATER_ENERGY = 72
FightPropertyConst.FIGHT_PROP_MAX_GRASS_ENERGY = 73
FightPropertyConst.FIGHT_PROP_MAX_WIND_ENERGY = 74
FightPropertyConst.FIGHT_PROP_MAX_ICE_ENERGY = 75
FightPropertyConst.FIGHT_PROP_MAX_ROCK_ENERGY = 76
FightPropertyConst.FIGHT_PROP_SKILL_CD_MINUS_RATIO = 80
FightPropertyConst.FIGHT_PROP_SHIELD_COST_MINUS_RATIO = 81
FightPropertyConst.FIGHT_PROP_CUR_FIRE_ENERGY = 1000
FightPropertyConst.FIGHT_PROP_CUR_ELEC_ENERGY = 1001
FightPropertyConst.FIGHT_PROP_CUR_WATER_ENERGY = 1002
FightPropertyConst.FIGHT_PROP_CUR_GRASS_ENERGY = 1003
FightPropertyConst.FIGHT_PROP_CUR_WIND_ENERGY = 1004
FightPropertyConst.FIGHT_PROP_CUR_ICE_ENERGY = 1005
FightPropertyConst.FIGHT_PROP_CUR_ROCK_ENERGY = 1006
FightPropertyConst.FIGHT_PROP_CUR_HP = 1010
FightPropertyConst.FIGHT_PROP_MAX_HP = 2000
FightPropertyConst.FIGHT_PROP_CUR_ATTACK = 2001
FightPropertyConst.FIGHT_PROP_CUR_DEFENSE = 2002
FightPropertyConst.FIGHT_PROP_CUR_SPEED = 2003
FightPropertyConst.FIGHT_PROP_NONEXTRA_ATTACK = 3000
FightPropertyConst.FIGHT_PROP_NONEXTRA_DEFENSE = 3001
FightPropertyConst.FIGHT_PROP_NONEXTRA_CRITICAL = 3002
FightPropertyConst.FIGHT_PROP_NONEXTRA_ANTI_CRITICAL = 3003
FightPropertyConst.FIGHT_PROP_NONEXTRA_CRITICAL_HURT = 3004
FightPropertyConst.FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY = 3005
FightPropertyConst.FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY = 3006
FightPropertyConst.FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT = 3007
FightPropertyConst.FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT = 3008
FightPropertyConst.FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT = 3009
FightPropertyConst.FIGHT_PROP_NONEXTRA_WATER_ADD_HURT = 3010
FightPropertyConst.FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT = 3011
FightPropertyConst.FIGHT_PROP_NONEXTRA_WIND_ADD_HURT = 3012
FightPropertyConst.FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT = 3013
FightPropertyConst.FIGHT_PROP_NONEXTRA_ICE_ADD_HURT = 3014
FightPropertyConst.FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT = 3015
FightPropertyConst.FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT = 3016
FightPropertyConst.FIGHT_PROP_NONEXTRA_WATER_SUB_HURT = 3017
FightPropertyConst.FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT = 3018
FightPropertyConst.FIGHT_PROP_NONEXTRA_WIND_SUB_HURT = 3019
FightPropertyConst.FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT = 3020
FightPropertyConst.FIGHT_PROP_NONEXTRA_ICE_SUB_HURT = 3021
FightPropertyConst.FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO = 3022
FightPropertyConst.FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO = 3023
FightPropertyConst.FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT = 3024
FightPropertyConst.STRING_MAP = make(map[string]uint16)
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONE"] = 0
FightPropertyConst.STRING_MAP["FIGHT_PROP_BASE_HP"] = 1
FightPropertyConst.STRING_MAP["FIGHT_PROP_HP"] = 2
FightPropertyConst.STRING_MAP["FIGHT_PROP_HP_PERCENT"] = 3
FightPropertyConst.STRING_MAP["FIGHT_PROP_BASE_ATTACK"] = 4
FightPropertyConst.STRING_MAP["FIGHT_PROP_ATTACK"] = 5
FightPropertyConst.STRING_MAP["FIGHT_PROP_ATTACK_PERCENT"] = 6
FightPropertyConst.STRING_MAP["FIGHT_PROP_BASE_DEFENSE"] = 7
FightPropertyConst.STRING_MAP["FIGHT_PROP_DEFENSE"] = 8
FightPropertyConst.STRING_MAP["FIGHT_PROP_DEFENSE_PERCENT"] = 9
FightPropertyConst.STRING_MAP["FIGHT_PROP_BASE_SPEED"] = 10
FightPropertyConst.STRING_MAP["FIGHT_PROP_SPEED_PERCENT"] = 11
FightPropertyConst.STRING_MAP["FIGHT_PROP_HP_MP_PERCENT"] = 12
FightPropertyConst.STRING_MAP["FIGHT_PROP_ATTACK_MP_PERCENT"] = 13
FightPropertyConst.STRING_MAP["FIGHT_PROP_CRITICAL"] = 20
FightPropertyConst.STRING_MAP["FIGHT_PROP_ANTI_CRITICAL"] = 21
FightPropertyConst.STRING_MAP["FIGHT_PROP_CRITICAL_HURT"] = 22
FightPropertyConst.STRING_MAP["FIGHT_PROP_CHARGE_EFFICIENCY"] = 23
FightPropertyConst.STRING_MAP["FIGHT_PROP_ADD_HURT"] = 24
FightPropertyConst.STRING_MAP["FIGHT_PROP_SUB_HURT"] = 25
FightPropertyConst.STRING_MAP["FIGHT_PROP_HEAL_ADD"] = 26
FightPropertyConst.STRING_MAP["FIGHT_PROP_HEALED_ADD"] = 27
FightPropertyConst.STRING_MAP["FIGHT_PROP_ELEMENT_MASTERY"] = 28
FightPropertyConst.STRING_MAP["FIGHT_PROP_PHYSICAL_SUB_HURT"] = 29
FightPropertyConst.STRING_MAP["FIGHT_PROP_PHYSICAL_ADD_HURT"] = 30
FightPropertyConst.STRING_MAP["FIGHT_PROP_DEFENCE_IGNORE_RATIO"] = 31
FightPropertyConst.STRING_MAP["FIGHT_PROP_DEFENCE_IGNORE_DELTA"] = 32
FightPropertyConst.STRING_MAP["FIGHT_PROP_FIRE_ADD_HURT"] = 40
FightPropertyConst.STRING_MAP["FIGHT_PROP_ELEC_ADD_HURT"] = 41
FightPropertyConst.STRING_MAP["FIGHT_PROP_WATER_ADD_HURT"] = 42
FightPropertyConst.STRING_MAP["FIGHT_PROP_GRASS_ADD_HURT"] = 43
FightPropertyConst.STRING_MAP["FIGHT_PROP_WIND_ADD_HURT"] = 44
FightPropertyConst.STRING_MAP["FIGHT_PROP_ROCK_ADD_HURT"] = 45
FightPropertyConst.STRING_MAP["FIGHT_PROP_ICE_ADD_HURT"] = 46
FightPropertyConst.STRING_MAP["FIGHT_PROP_HIT_HEAD_ADD_HURT"] = 47
FightPropertyConst.STRING_MAP["FIGHT_PROP_FIRE_SUB_HURT"] = 50
FightPropertyConst.STRING_MAP["FIGHT_PROP_ELEC_SUB_HURT"] = 51
FightPropertyConst.STRING_MAP["FIGHT_PROP_WATER_SUB_HURT"] = 52
FightPropertyConst.STRING_MAP["FIGHT_PROP_GRASS_SUB_HURT"] = 53
FightPropertyConst.STRING_MAP["FIGHT_PROP_WIND_SUB_HURT"] = 54
FightPropertyConst.STRING_MAP["FIGHT_PROP_ROCK_SUB_HURT"] = 55
FightPropertyConst.STRING_MAP["FIGHT_PROP_ICE_SUB_HURT"] = 56
FightPropertyConst.STRING_MAP["FIGHT_PROP_EFFECT_HIT"] = 60
FightPropertyConst.STRING_MAP["FIGHT_PROP_EFFECT_RESIST"] = 61
FightPropertyConst.STRING_MAP["FIGHT_PROP_FREEZE_RESIST"] = 62
FightPropertyConst.STRING_MAP["FIGHT_PROP_TORPOR_RESIST"] = 63
FightPropertyConst.STRING_MAP["FIGHT_PROP_DIZZY_RESIST"] = 64
FightPropertyConst.STRING_MAP["FIGHT_PROP_FREEZE_SHORTEN"] = 65
FightPropertyConst.STRING_MAP["FIGHT_PROP_TORPOR_SHORTEN"] = 66
FightPropertyConst.STRING_MAP["FIGHT_PROP_DIZZY_SHORTEN"] = 67
FightPropertyConst.STRING_MAP["FIGHT_PROP_MAX_FIRE_ENERGY"] = 70
FightPropertyConst.STRING_MAP["FIGHT_PROP_MAX_ELEC_ENERGY"] = 71
FightPropertyConst.STRING_MAP["FIGHT_PROP_MAX_WATER_ENERGY"] = 72
FightPropertyConst.STRING_MAP["FIGHT_PROP_MAX_GRASS_ENERGY"] = 73
FightPropertyConst.STRING_MAP["FIGHT_PROP_MAX_WIND_ENERGY"] = 74
FightPropertyConst.STRING_MAP["FIGHT_PROP_MAX_ICE_ENERGY"] = 75
FightPropertyConst.STRING_MAP["FIGHT_PROP_MAX_ROCK_ENERGY"] = 76
FightPropertyConst.STRING_MAP["FIGHT_PROP_SKILL_CD_MINUS_RATIO"] = 80
FightPropertyConst.STRING_MAP["FIGHT_PROP_SHIELD_COST_MINUS_RATIO"] = 81
FightPropertyConst.STRING_MAP["FIGHT_PROP_CUR_FIRE_ENERGY"] = 1000
FightPropertyConst.STRING_MAP["FIGHT_PROP_CUR_ELEC_ENERGY"] = 1001
FightPropertyConst.STRING_MAP["FIGHT_PROP_CUR_WATER_ENERGY"] = 1002
FightPropertyConst.STRING_MAP["FIGHT_PROP_CUR_GRASS_ENERGY"] = 1003
FightPropertyConst.STRING_MAP["FIGHT_PROP_CUR_WIND_ENERGY"] = 1004
FightPropertyConst.STRING_MAP["FIGHT_PROP_CUR_ICE_ENERGY"] = 1005
FightPropertyConst.STRING_MAP["FIGHT_PROP_CUR_ROCK_ENERGY"] = 1006
FightPropertyConst.STRING_MAP["FIGHT_PROP_CUR_HP"] = 1010
FightPropertyConst.STRING_MAP["FIGHT_PROP_MAX_HP"] = 2000
FightPropertyConst.STRING_MAP["FIGHT_PROP_CUR_ATTACK"] = 2001
FightPropertyConst.STRING_MAP["FIGHT_PROP_CUR_DEFENSE"] = 2002
FightPropertyConst.STRING_MAP["FIGHT_PROP_CUR_SPEED"] = 2003
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_ATTACK"] = 3000
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_DEFENSE"] = 3001
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_CRITICAL"] = 3002
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_ANTI_CRITICAL"] = 3003
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_CRITICAL_HURT"] = 3004
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY"] = 3005
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY"] = 3006
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT"] = 3007
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT"] = 3008
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT"] = 3009
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_WATER_ADD_HURT"] = 3010
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT"] = 3011
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_WIND_ADD_HURT"] = 3012
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT"] = 3013
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_ICE_ADD_HURT"] = 3014
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT"] = 3015
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT"] = 3016
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_WATER_SUB_HURT"] = 3017
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT"] = 3018
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_WIND_SUB_HURT"] = 3019
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT"] = 3020
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_ICE_SUB_HURT"] = 3021
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO"] = 3022
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO"] = 3023
FightPropertyConst.STRING_MAP["FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT"] = 3024
}

View File

@@ -0,0 +1,32 @@
package constant
import "flswld.com/common/utils/endec"
var GameConstantConst *GameConstant
type GameConstant struct {
DEFAULT_ABILITY_STRINGS []string
DEFAULT_ABILITY_HASHES []int32
DEFAULT_ABILITY_NAME int32
}
func InitGameConstant() {
GameConstantConst = new(GameConstant)
GameConstantConst.DEFAULT_ABILITY_STRINGS = []string{
"Avatar_DefaultAbility_VisionReplaceDieInvincible",
"Avatar_DefaultAbility_AvartarInShaderChange",
"Avatar_SprintBS_Invincible",
"Avatar_Freeze_Duration_Reducer",
"Avatar_Attack_ReviveEnergy",
"Avatar_Component_Initializer",
"Avatar_FallAnthem_Achievement_Listener",
}
GameConstantConst.DEFAULT_ABILITY_HASHES = make([]int32, 0)
for _, v := range GameConstantConst.DEFAULT_ABILITY_STRINGS {
GameConstantConst.DEFAULT_ABILITY_HASHES = append(GameConstantConst.DEFAULT_ABILITY_HASHES, endec.Hk4eAbilityHashCode(v))
}
GameConstantConst.DEFAULT_ABILITY_NAME = endec.Hk4eAbilityHashCode("Default")
}

View File

@@ -0,0 +1,131 @@
package constant
var GrowCurveConst *GrowCurve
type GrowCurve struct {
GROW_CURVE_NONE uint16
GROW_CURVE_HP uint16
GROW_CURVE_ATTACK uint16
GROW_CURVE_STAMINA uint16
GROW_CURVE_STRIKE uint16
GROW_CURVE_ANTI_STRIKE uint16
GROW_CURVE_ANTI_STRIKE1 uint16
GROW_CURVE_ANTI_STRIKE2 uint16
GROW_CURVE_ANTI_STRIKE3 uint16
GROW_CURVE_STRIKE_HURT uint16
GROW_CURVE_ELEMENT uint16
GROW_CURVE_KILL_EXP uint16
GROW_CURVE_DEFENSE uint16
GROW_CURVE_ATTACK_BOMB uint16
GROW_CURVE_HP_LITTLEMONSTER uint16
GROW_CURVE_ELEMENT_MASTERY uint16
GROW_CURVE_PROGRESSION uint16
GROW_CURVE_DEFENDING uint16
GROW_CURVE_MHP uint16
GROW_CURVE_MATK uint16
GROW_CURVE_TOWERATK uint16
GROW_CURVE_HP_S5 uint16
GROW_CURVE_HP_S4 uint16
GROW_CURVE_HP_2 uint16
GROW_CURVE_ATTACK_S5 uint16
GROW_CURVE_ATTACK_S4 uint16
GROW_CURVE_ATTACK_S3 uint16
GROW_CURVE_STRIKE_S5 uint16
GROW_CURVE_DEFENSE_S5 uint16
GROW_CURVE_DEFENSE_S4 uint16
GROW_CURVE_ATTACK_101 uint16
GROW_CURVE_ATTACK_102 uint16
GROW_CURVE_ATTACK_103 uint16
GROW_CURVE_ATTACK_104 uint16
GROW_CURVE_ATTACK_105 uint16
GROW_CURVE_ATTACK_201 uint16
GROW_CURVE_ATTACK_202 uint16
GROW_CURVE_ATTACK_203 uint16
GROW_CURVE_ATTACK_204 uint16
GROW_CURVE_ATTACK_205 uint16
GROW_CURVE_ATTACK_301 uint16
GROW_CURVE_ATTACK_302 uint16
GROW_CURVE_ATTACK_303 uint16
GROW_CURVE_ATTACK_304 uint16
GROW_CURVE_ATTACK_305 uint16
GROW_CURVE_CRITICAL_101 uint16
GROW_CURVE_CRITICAL_102 uint16
GROW_CURVE_CRITICAL_103 uint16
GROW_CURVE_CRITICAL_104 uint16
GROW_CURVE_CRITICAL_105 uint16
GROW_CURVE_CRITICAL_201 uint16
GROW_CURVE_CRITICAL_202 uint16
GROW_CURVE_CRITICAL_203 uint16
GROW_CURVE_CRITICAL_204 uint16
GROW_CURVE_CRITICAL_205 uint16
GROW_CURVE_CRITICAL_301 uint16
GROW_CURVE_CRITICAL_302 uint16
GROW_CURVE_CRITICAL_303 uint16
GROW_CURVE_CRITICAL_304 uint16
GROW_CURVE_CRITICAL_305 uint16
}
func InitGrowCurveConst() {
GrowCurveConst = new(GrowCurve)
GrowCurveConst.GROW_CURVE_NONE = 0
GrowCurveConst.GROW_CURVE_HP = 1
GrowCurveConst.GROW_CURVE_ATTACK = 2
GrowCurveConst.GROW_CURVE_STAMINA = 3
GrowCurveConst.GROW_CURVE_STRIKE = 4
GrowCurveConst.GROW_CURVE_ANTI_STRIKE = 5
GrowCurveConst.GROW_CURVE_ANTI_STRIKE1 = 6
GrowCurveConst.GROW_CURVE_ANTI_STRIKE2 = 7
GrowCurveConst.GROW_CURVE_ANTI_STRIKE3 = 8
GrowCurveConst.GROW_CURVE_STRIKE_HURT = 9
GrowCurveConst.GROW_CURVE_ELEMENT = 10
GrowCurveConst.GROW_CURVE_KILL_EXP = 11
GrowCurveConst.GROW_CURVE_DEFENSE = 12
GrowCurveConst.GROW_CURVE_ATTACK_BOMB = 13
GrowCurveConst.GROW_CURVE_HP_LITTLEMONSTER = 14
GrowCurveConst.GROW_CURVE_ELEMENT_MASTERY = 15
GrowCurveConst.GROW_CURVE_PROGRESSION = 16
GrowCurveConst.GROW_CURVE_DEFENDING = 17
GrowCurveConst.GROW_CURVE_MHP = 18
GrowCurveConst.GROW_CURVE_MATK = 19
GrowCurveConst.GROW_CURVE_TOWERATK = 20
GrowCurveConst.GROW_CURVE_HP_S5 = 21
GrowCurveConst.GROW_CURVE_HP_S4 = 22
GrowCurveConst.GROW_CURVE_HP_2 = 23
GrowCurveConst.GROW_CURVE_ATTACK_S5 = 31
GrowCurveConst.GROW_CURVE_ATTACK_S4 = 32
GrowCurveConst.GROW_CURVE_ATTACK_S3 = 33
GrowCurveConst.GROW_CURVE_STRIKE_S5 = 34
GrowCurveConst.GROW_CURVE_DEFENSE_S5 = 41
GrowCurveConst.GROW_CURVE_DEFENSE_S4 = 42
GrowCurveConst.GROW_CURVE_ATTACK_101 = 1101
GrowCurveConst.GROW_CURVE_ATTACK_102 = 1102
GrowCurveConst.GROW_CURVE_ATTACK_103 = 1103
GrowCurveConst.GROW_CURVE_ATTACK_104 = 1104
GrowCurveConst.GROW_CURVE_ATTACK_105 = 1105
GrowCurveConst.GROW_CURVE_ATTACK_201 = 1201
GrowCurveConst.GROW_CURVE_ATTACK_202 = 1202
GrowCurveConst.GROW_CURVE_ATTACK_203 = 1203
GrowCurveConst.GROW_CURVE_ATTACK_204 = 1204
GrowCurveConst.GROW_CURVE_ATTACK_205 = 1205
GrowCurveConst.GROW_CURVE_ATTACK_301 = 1301
GrowCurveConst.GROW_CURVE_ATTACK_302 = 1302
GrowCurveConst.GROW_CURVE_ATTACK_303 = 1303
GrowCurveConst.GROW_CURVE_ATTACK_304 = 1304
GrowCurveConst.GROW_CURVE_ATTACK_305 = 1305
GrowCurveConst.GROW_CURVE_CRITICAL_101 = 2101
GrowCurveConst.GROW_CURVE_CRITICAL_102 = 2102
GrowCurveConst.GROW_CURVE_CRITICAL_103 = 2103
GrowCurveConst.GROW_CURVE_CRITICAL_104 = 2104
GrowCurveConst.GROW_CURVE_CRITICAL_105 = 2105
GrowCurveConst.GROW_CURVE_CRITICAL_201 = 2201
GrowCurveConst.GROW_CURVE_CRITICAL_202 = 2202
GrowCurveConst.GROW_CURVE_CRITICAL_203 = 2203
GrowCurveConst.GROW_CURVE_CRITICAL_204 = 2204
GrowCurveConst.GROW_CURVE_CRITICAL_205 = 2205
GrowCurveConst.GROW_CURVE_CRITICAL_301 = 2301
GrowCurveConst.GROW_CURVE_CRITICAL_302 = 2302
GrowCurveConst.GROW_CURVE_CRITICAL_303 = 2303
GrowCurveConst.GROW_CURVE_CRITICAL_304 = 2304
GrowCurveConst.GROW_CURVE_CRITICAL_305 = 2305
}

View File

@@ -0,0 +1,36 @@
package constant
var ItemTypeConst *ItemType
type ItemType struct {
ITEM_NONE uint16
ITEM_VIRTUAL uint16
ITEM_MATERIAL uint16
ITEM_RELIQUARY uint16
ITEM_WEAPON uint16
ITEM_DISPLAY uint16
ITEM_FURNITURE uint16
STRING_MAP map[string]uint16
}
func InitItemTypeConst() {
ItemTypeConst = new(ItemType)
ItemTypeConst.ITEM_NONE = 0
ItemTypeConst.ITEM_VIRTUAL = 1
ItemTypeConst.ITEM_MATERIAL = 2
ItemTypeConst.ITEM_RELIQUARY = 3
ItemTypeConst.ITEM_WEAPON = 4
ItemTypeConst.ITEM_DISPLAY = 5
ItemTypeConst.ITEM_FURNITURE = 6
ItemTypeConst.STRING_MAP = make(map[string]uint16)
ItemTypeConst.STRING_MAP["ITEM_NONE"] = 0
ItemTypeConst.STRING_MAP["ITEM_VIRTUAL"] = 1
ItemTypeConst.STRING_MAP["ITEM_MATERIAL"] = 2
ItemTypeConst.STRING_MAP["ITEM_RELIQUARY"] = 3
ItemTypeConst.STRING_MAP["ITEM_WEAPON"] = 4
ItemTypeConst.STRING_MAP["ITEM_DISPLAY"] = 5
ItemTypeConst.STRING_MAP["ITEM_FURNITURE"] = 6
}

View File

@@ -0,0 +1,19 @@
package constant
var LifeStateConst *LifeState
type LifeState struct {
LIFE_NONE uint16
LIFE_ALIVE uint16
LIFE_DEAD uint16
LIFE_REVIVE uint16
}
func InitLifeStateConst() {
LifeStateConst = new(LifeState)
LifeStateConst.LIFE_NONE = 0
LifeStateConst.LIFE_ALIVE = 1
LifeStateConst.LIFE_DEAD = 2
LifeStateConst.LIFE_REVIVE = 3
}

View File

@@ -0,0 +1,102 @@
package constant
var MaterialTypeConst *MaterialType
type MaterialType struct {
MATERIAL_NONE uint16
MATERIAL_FOOD uint16
MATERIAL_QUEST uint16
MATERIAL_EXCHANGE uint16
MATERIAL_CONSUME uint16
MATERIAL_EXP_FRUIT uint16
MATERIAL_AVATAR uint16
MATERIAL_ADSORBATE uint16
MATERIAL_CRICKET uint16
MATERIAL_ELEM_CRYSTAL uint16
MATERIAL_WEAPON_EXP_STONE uint16
MATERIAL_CHEST uint16
MATERIAL_RELIQUARY_MATERIAL uint16
MATERIAL_AVATAR_MATERIAL uint16
MATERIAL_NOTICE_ADD_HP uint16
MATERIAL_SEA_LAMP uint16
MATERIAL_SELECTABLE_CHEST uint16
MATERIAL_FLYCLOAK uint16
MATERIAL_NAMECARD uint16
MATERIAL_TALENT uint16
MATERIAL_WIDGET uint16
MATERIAL_CHEST_BATCH_USE uint16
MATERIAL_FAKE_ABSORBATE uint16
MATERIAL_CONSUME_BATCH_USE uint16
MATERIAL_WOOD uint16
MATERIAL_FURNITURE_FORMULA uint16
MATERIAL_CHANNELLER_SLAB_BUFF uint16
MATERIAL_FURNITURE_SUITE_FORMULA uint16
MATERIAL_COSTUME uint16
STRING_MAP map[string]uint16
}
func InitMaterialTypeConst() {
MaterialTypeConst = new(MaterialType)
MaterialTypeConst.MATERIAL_NONE = 0
MaterialTypeConst.MATERIAL_FOOD = 1
MaterialTypeConst.MATERIAL_QUEST = 2
MaterialTypeConst.MATERIAL_EXCHANGE = 4
MaterialTypeConst.MATERIAL_CONSUME = 5
MaterialTypeConst.MATERIAL_EXP_FRUIT = 6
MaterialTypeConst.MATERIAL_AVATAR = 7
MaterialTypeConst.MATERIAL_ADSORBATE = 8
MaterialTypeConst.MATERIAL_CRICKET = 9
MaterialTypeConst.MATERIAL_ELEM_CRYSTAL = 10
MaterialTypeConst.MATERIAL_WEAPON_EXP_STONE = 11
MaterialTypeConst.MATERIAL_CHEST = 12
MaterialTypeConst.MATERIAL_RELIQUARY_MATERIAL = 13
MaterialTypeConst.MATERIAL_AVATAR_MATERIAL = 14
MaterialTypeConst.MATERIAL_NOTICE_ADD_HP = 15
MaterialTypeConst.MATERIAL_SEA_LAMP = 16
MaterialTypeConst.MATERIAL_SELECTABLE_CHEST = 17
MaterialTypeConst.MATERIAL_FLYCLOAK = 18
MaterialTypeConst.MATERIAL_NAMECARD = 19
MaterialTypeConst.MATERIAL_TALENT = 20
MaterialTypeConst.MATERIAL_WIDGET = 21
MaterialTypeConst.MATERIAL_CHEST_BATCH_USE = 22
MaterialTypeConst.MATERIAL_FAKE_ABSORBATE = 23
MaterialTypeConst.MATERIAL_CONSUME_BATCH_USE = 24
MaterialTypeConst.MATERIAL_WOOD = 25
MaterialTypeConst.MATERIAL_FURNITURE_FORMULA = 27
MaterialTypeConst.MATERIAL_CHANNELLER_SLAB_BUFF = 28
MaterialTypeConst.MATERIAL_FURNITURE_SUITE_FORMULA = 29
MaterialTypeConst.MATERIAL_COSTUME = 30
MaterialTypeConst.STRING_MAP = make(map[string]uint16)
MaterialTypeConst.STRING_MAP["MATERIAL_NONE"] = 0
MaterialTypeConst.STRING_MAP["MATERIAL_FOOD"] = 1
MaterialTypeConst.STRING_MAP["MATERIAL_QUEST"] = 2
MaterialTypeConst.STRING_MAP["MATERIAL_EXCHANGE"] = 4
MaterialTypeConst.STRING_MAP["MATERIAL_CONSUME"] = 5
MaterialTypeConst.STRING_MAP["MATERIAL_EXP_FRUIT"] = 6
MaterialTypeConst.STRING_MAP["MATERIAL_AVATAR"] = 7
MaterialTypeConst.STRING_MAP["MATERIAL_ADSORBATE"] = 8
MaterialTypeConst.STRING_MAP["MATERIAL_CRICKET"] = 9
MaterialTypeConst.STRING_MAP["MATERIAL_ELEM_CRYSTAL"] = 10
MaterialTypeConst.STRING_MAP["MATERIAL_WEAPON_EXP_STONE"] = 11
MaterialTypeConst.STRING_MAP["MATERIAL_CHEST"] = 12
MaterialTypeConst.STRING_MAP["MATERIAL_RELIQUARY_MATERIAL"] = 13
MaterialTypeConst.STRING_MAP["MATERIAL_AVATAR_MATERIAL"] = 14
MaterialTypeConst.STRING_MAP["MATERIAL_NOTICE_ADD_HP"] = 15
MaterialTypeConst.STRING_MAP["MATERIAL_SEA_LAMP"] = 16
MaterialTypeConst.STRING_MAP["MATERIAL_SELECTABLE_CHEST"] = 17
MaterialTypeConst.STRING_MAP["MATERIAL_FLYCLOAK"] = 18
MaterialTypeConst.STRING_MAP["MATERIAL_NAMECARD"] = 19
MaterialTypeConst.STRING_MAP["MATERIAL_TALENT"] = 20
MaterialTypeConst.STRING_MAP["MATERIAL_WIDGET"] = 21
MaterialTypeConst.STRING_MAP["MATERIAL_CHEST_BATCH_USE"] = 22
MaterialTypeConst.STRING_MAP["MATERIAL_FAKE_ABSORBATE"] = 23
MaterialTypeConst.STRING_MAP["MATERIAL_CONSUME_BATCH_USE"] = 24
MaterialTypeConst.STRING_MAP["MATERIAL_WOOD"] = 25
MaterialTypeConst.STRING_MAP["MATERIAL_FURNITURE_FORMULA"] = 27
MaterialTypeConst.STRING_MAP["MATERIAL_CHANNELLER_SLAB_BUFF"] = 28
MaterialTypeConst.STRING_MAP["MATERIAL_FURNITURE_SUITE_FORMULA"] = 29
MaterialTypeConst.STRING_MAP["MATERIAL_COSTUME"] = 30
}

View File

@@ -0,0 +1,343 @@
package constant
var OpenStateConst *OpenState
type OpenState struct {
OPEN_STATE_NONE uint16
OPEN_STATE_PAIMON uint16
OPEN_STATE_PAIMON_NAVIGATION uint16
OPEN_STATE_AVATAR_PROMOTE uint16
OPEN_STATE_AVATAR_TALENT uint16
OPEN_STATE_WEAPON_PROMOTE uint16
OPEN_STATE_WEAPON_AWAKEN uint16
OPEN_STATE_QUEST_REMIND uint16
OPEN_STATE_GAME_GUIDE uint16
OPEN_STATE_COOK uint16
OPEN_STATE_WEAPON_UPGRADE uint16
OPEN_STATE_RELIQUARY_UPGRADE uint16
OPEN_STATE_RELIQUARY_PROMOTE uint16
OPEN_STATE_WEAPON_PROMOTE_GUIDE uint16
OPEN_STATE_WEAPON_CHANGE_GUIDE uint16
OPEN_STATE_PLAYER_LVUP_GUIDE uint16
OPEN_STATE_FRESHMAN_GUIDE uint16
OPEN_STATE_SKIP_FRESHMAN_GUIDE uint16
OPEN_STATE_GUIDE_MOVE_CAMERA uint16
OPEN_STATE_GUIDE_SCALE_CAMERA uint16
OPEN_STATE_GUIDE_KEYBOARD uint16
OPEN_STATE_GUIDE_MOVE uint16
OPEN_STATE_GUIDE_JUMP uint16
OPEN_STATE_GUIDE_SPRINT uint16
OPEN_STATE_GUIDE_MAP uint16
OPEN_STATE_GUIDE_ATTACK uint16
OPEN_STATE_GUIDE_FLY uint16
OPEN_STATE_GUIDE_TALENT uint16
OPEN_STATE_GUIDE_RELIC uint16
OPEN_STATE_GUIDE_RELIC_PROM uint16
OPEN_STATE_COMBINE uint16
OPEN_STATE_GACHA uint16
OPEN_STATE_GUIDE_GACHA uint16
OPEN_STATE_GUIDE_TEAM uint16
OPEN_STATE_GUIDE_PROUD uint16
OPEN_STATE_GUIDE_AVATAR_PROMOTE uint16
OPEN_STATE_GUIDE_ADVENTURE_CARD uint16
OPEN_STATE_FORGE uint16
OPEN_STATE_GUIDE_BAG uint16
OPEN_STATE_EXPEDITION uint16
OPEN_STATE_GUIDE_ADVENTURE_DAILYTASK uint16
OPEN_STATE_GUIDE_ADVENTURE_DUNGEON uint16
OPEN_STATE_TOWER uint16
OPEN_STATE_WORLD_STAMINA uint16
OPEN_STATE_TOWER_FIRST_ENTER uint16
OPEN_STATE_RESIN uint16
OPEN_STATE_LIMIT_REGION_FRESHMEAT uint16
OPEN_STATE_LIMIT_REGION_GLOBAL uint16
OPEN_STATE_MULTIPLAYER uint16
OPEN_STATE_GUIDE_MOUSEPC uint16
OPEN_STATE_GUIDE_MULTIPLAYER uint16
OPEN_STATE_GUIDE_DUNGEONREWARD uint16
OPEN_STATE_GUIDE_BLOSSOM uint16
OPEN_STATE_AVATAR_FASHION uint16
OPEN_STATE_PHOTOGRAPH uint16
OPEN_STATE_GUIDE_KSLQUEST uint16
OPEN_STATE_PERSONAL_LINE uint16
OPEN_STATE_GUIDE_PERSONAL_LINE uint16
OPEN_STATE_GUIDE_APPEARANCE uint16
OPEN_STATE_GUIDE_PROCESS uint16
OPEN_STATE_GUIDE_PERSONAL_LINE_KEY uint16
OPEN_STATE_GUIDE_WIDGET uint16
OPEN_STATE_GUIDE_ACTIVITY_SKILL_ASTER uint16
OPEN_STATE_GUIDE_COLDCLIMATE uint16
OPEN_STATE_DERIVATIVE_MALL uint16
OPEN_STATE_GUIDE_EXITMULTIPLAYER uint16
OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD uint16
OPEN_STATE_GUIDE_THEATREMACHANICUS_REBUILD uint16
OPEN_STATE_GUIDE_THEATREMACHANICUS_CARD uint16
OPEN_STATE_GUIDE_THEATREMACHANICUS_MONSTER uint16
OPEN_STATE_GUIDE_THEATREMACHANICUS_MISSION_CHECK uint16
OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD_SELECT uint16
OPEN_STATE_GUIDE_THEATREMACHANICUS_CHALLENGE_START uint16
OPEN_STATE_GUIDE_CONVERT uint16
OPEN_STATE_GUIDE_THEATREMACHANICUS_MULTIPLAYER uint16
OPEN_STATE_GUIDE_COOP_TASK uint16
OPEN_STATE_GUIDE_HOMEWORLD_ADEPTIABODE uint16
OPEN_STATE_GUIDE_HOMEWORLD_DEPLOY uint16
OPEN_STATE_GUIDE_CHANNELLERSLAB_EQUIP uint16
OPEN_STATE_GUIDE_CHANNELLERSLAB_MP_SOLUTION uint16
OPEN_STATE_GUIDE_CHANNELLERSLAB_POWER uint16
OPEN_STATE_GUIDE_HIDEANDSEEK_SKILL uint16
OPEN_STATE_GUIDE_HOMEWORLD_MAPLIST uint16
OPEN_STATE_GUIDE_RELICRESOLVE uint16
OPEN_STATE_GUIDE_GGUIDE uint16
OPEN_STATE_GUIDE_GGUIDE_HINT uint16
OPEN_STATE_CITY_REPUATION_MENGDE uint16
OPEN_STATE_CITY_REPUATION_LIYUE uint16
OPEN_STATE_CITY_REPUATION_UI_HINT uint16
OPEN_STATE_CITY_REPUATION_INAZUMA uint16
OPEN_STATE_SHOP_TYPE_MALL uint16
OPEN_STATE_SHOP_TYPE_RECOMMANDED uint16
OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL uint16
OPEN_STATE_SHOP_TYPE_GIFTPACKAGE uint16
OPEN_STATE_SHOP_TYPE_PAIMON uint16
OPEN_STATE_SHOP_TYPE_CITY uint16
OPEN_STATE_SHOP_TYPE_BLACKSMITH uint16
OPEN_STATE_SHOP_TYPE_GROCERY uint16
OPEN_STATE_SHOP_TYPE_FOOD uint16
OPEN_STATE_SHOP_TYPE_SEA_LAMP uint16
OPEN_STATE_SHOP_TYPE_VIRTUAL_SHOP uint16
OPEN_STATE_SHOP_TYPE_LIYUE_GROCERY uint16
OPEN_STATE_SHOP_TYPE_LIYUE_SOUVENIR uint16
OPEN_STATE_SHOP_TYPE_LIYUE_RESTAURANT uint16
OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR uint16
OPEN_STATE_SHOP_TYPE_NPC_TOMOKI uint16
OPEN_ADVENTURE_MANUAL uint16
OPEN_ADVENTURE_MANUAL_CITY_MENGDE uint16
OPEN_ADVENTURE_MANUAL_CITY_LIYUE uint16
OPEN_ADVENTURE_MANUAL_MONSTER uint16
OPEN_ADVENTURE_MANUAL_BOSS_DUNGEON uint16
OPEN_STATE_ACTIVITY_SEALAMP uint16
OPEN_STATE_ACTIVITY_SEALAMP_TAB2 uint16
OPEN_STATE_ACTIVITY_SEALAMP_TAB3 uint16
OPEN_STATE_BATTLE_PASS uint16
OPEN_STATE_BATTLE_PASS_ENTRY uint16
OPEN_STATE_ACTIVITY_CRUCIBLE uint16
OPEN_STATE_ACTIVITY_NEWBEEBOUNS_OPEN uint16
OPEN_STATE_ACTIVITY_NEWBEEBOUNS_CLOSE uint16
OPEN_STATE_ACTIVITY_ENTRY_OPEN uint16
OPEN_STATE_MENGDE_INFUSEDCRYSTAL uint16
OPEN_STATE_LIYUE_INFUSEDCRYSTAL uint16
OPEN_STATE_SNOW_MOUNTAIN_ELDER_TREE uint16
OPEN_STATE_MIRACLE_RING uint16
OPEN_STATE_COOP_LINE uint16
OPEN_STATE_INAZUMA_INFUSEDCRYSTAL uint16
OPEN_STATE_FISH uint16
OPEN_STATE_GUIDE_SUMO_TEAM_SKILL uint16
OPEN_STATE_GUIDE_FISH_RECIPE uint16
OPEN_STATE_HOME uint16
OPEN_STATE_ACTIVITY_HOMEWORLD uint16
OPEN_STATE_ADEPTIABODE uint16
OPEN_STATE_HOME_AVATAR uint16
OPEN_STATE_HOME_EDIT uint16
OPEN_STATE_HOME_EDIT_TIPS uint16
OPEN_STATE_RELIQUARY_DECOMPOSE uint16
OPEN_STATE_ACTIVITY_H5 uint16
OPEN_STATE_ORAIONOKAMI uint16
OPEN_STATE_GUIDE_CHESS_MISSION_CHECK uint16
OPEN_STATE_GUIDE_CHESS_BUILD uint16
OPEN_STATE_GUIDE_CHESS_WIND_TOWER_CIRCLE uint16
OPEN_STATE_GUIDE_CHESS_CARD_SELECT uint16
OPEN_STATE_INAZUMA_MAINQUEST_FINISHED uint16
OPEN_STATE_PAIMON_LVINFO uint16
OPEN_STATE_TELEPORT_HUD uint16
OPEN_STATE_GUIDE_MAP_UNLOCK uint16
OPEN_STATE_GUIDE_PAIMON_LVINFO uint16
OPEN_STATE_GUIDE_AMBORTRANSPORT uint16
OPEN_STATE_GUIDE_FLY_SECOND uint16
OPEN_STATE_GUIDE_KAEYA_CLUE uint16
OPEN_STATE_CAPTURE_CODEX uint16
OPEN_STATE_ACTIVITY_FISH_OPEN uint16
OPEN_STATE_ACTIVITY_FISH_CLOSE uint16
OPEN_STATE_GUIDE_ROGUE_MAP uint16
OPEN_STATE_GUIDE_ROGUE_RUNE uint16
OPEN_STATE_GUIDE_BARTENDER_FORMULA uint16
OPEN_STATE_GUIDE_BARTENDER_MIX uint16
OPEN_STATE_GUIDE_BARTENDER_CUP uint16
OPEN_STATE_GUIDE_MAIL_FAVORITES uint16
OPEN_STATE_GUIDE_POTION_CONFIGURE uint16
OPEN_STATE_GUIDE_LANV2_FIREWORK uint16
OPEN_STATE_LOADINGTIPS_ENKANOMIYA uint16
OPEN_STATE_MICHIAE_CASKET uint16
OPEN_STATE_MAIL_COLLECT_UNLOCK_RED_POINT uint16
OPEN_STATE_LUMEN_STONE uint16
OPEN_STATE_GUIDE_CRYSTALLINK_BUFF uint16
}
func InitOpenStateConst() {
OpenStateConst = new(OpenState)
OpenStateConst.OPEN_STATE_NONE = 0
OpenStateConst.OPEN_STATE_PAIMON = 1
OpenStateConst.OPEN_STATE_PAIMON_NAVIGATION = 2
OpenStateConst.OPEN_STATE_AVATAR_PROMOTE = 3
OpenStateConst.OPEN_STATE_AVATAR_TALENT = 4
OpenStateConst.OPEN_STATE_WEAPON_PROMOTE = 5
OpenStateConst.OPEN_STATE_WEAPON_AWAKEN = 6
OpenStateConst.OPEN_STATE_QUEST_REMIND = 7
OpenStateConst.OPEN_STATE_GAME_GUIDE = 8
OpenStateConst.OPEN_STATE_COOK = 9
OpenStateConst.OPEN_STATE_WEAPON_UPGRADE = 10
OpenStateConst.OPEN_STATE_RELIQUARY_UPGRADE = 11
OpenStateConst.OPEN_STATE_RELIQUARY_PROMOTE = 12
OpenStateConst.OPEN_STATE_WEAPON_PROMOTE_GUIDE = 13
OpenStateConst.OPEN_STATE_WEAPON_CHANGE_GUIDE = 14
OpenStateConst.OPEN_STATE_PLAYER_LVUP_GUIDE = 15
OpenStateConst.OPEN_STATE_FRESHMAN_GUIDE = 16
OpenStateConst.OPEN_STATE_SKIP_FRESHMAN_GUIDE = 17
OpenStateConst.OPEN_STATE_GUIDE_MOVE_CAMERA = 18
OpenStateConst.OPEN_STATE_GUIDE_SCALE_CAMERA = 19
OpenStateConst.OPEN_STATE_GUIDE_KEYBOARD = 20
OpenStateConst.OPEN_STATE_GUIDE_MOVE = 21
OpenStateConst.OPEN_STATE_GUIDE_JUMP = 22
OpenStateConst.OPEN_STATE_GUIDE_SPRINT = 23
OpenStateConst.OPEN_STATE_GUIDE_MAP = 24
OpenStateConst.OPEN_STATE_GUIDE_ATTACK = 25
OpenStateConst.OPEN_STATE_GUIDE_FLY = 26
OpenStateConst.OPEN_STATE_GUIDE_TALENT = 27
OpenStateConst.OPEN_STATE_GUIDE_RELIC = 28
OpenStateConst.OPEN_STATE_GUIDE_RELIC_PROM = 29
OpenStateConst.OPEN_STATE_COMBINE = 30
OpenStateConst.OPEN_STATE_GACHA = 31
OpenStateConst.OPEN_STATE_GUIDE_GACHA = 32
OpenStateConst.OPEN_STATE_GUIDE_TEAM = 33
OpenStateConst.OPEN_STATE_GUIDE_PROUD = 34
OpenStateConst.OPEN_STATE_GUIDE_AVATAR_PROMOTE = 35
OpenStateConst.OPEN_STATE_GUIDE_ADVENTURE_CARD = 36
OpenStateConst.OPEN_STATE_FORGE = 37
OpenStateConst.OPEN_STATE_GUIDE_BAG = 38
OpenStateConst.OPEN_STATE_EXPEDITION = 39
OpenStateConst.OPEN_STATE_GUIDE_ADVENTURE_DAILYTASK = 40
OpenStateConst.OPEN_STATE_GUIDE_ADVENTURE_DUNGEON = 41
OpenStateConst.OPEN_STATE_TOWER = 42
OpenStateConst.OPEN_STATE_WORLD_STAMINA = 43
OpenStateConst.OPEN_STATE_TOWER_FIRST_ENTER = 44
OpenStateConst.OPEN_STATE_RESIN = 45
OpenStateConst.OPEN_STATE_LIMIT_REGION_FRESHMEAT = 47
OpenStateConst.OPEN_STATE_LIMIT_REGION_GLOBAL = 48
OpenStateConst.OPEN_STATE_MULTIPLAYER = 49
OpenStateConst.OPEN_STATE_GUIDE_MOUSEPC = 50
OpenStateConst.OPEN_STATE_GUIDE_MULTIPLAYER = 51
OpenStateConst.OPEN_STATE_GUIDE_DUNGEONREWARD = 52
OpenStateConst.OPEN_STATE_GUIDE_BLOSSOM = 53
OpenStateConst.OPEN_STATE_AVATAR_FASHION = 54
OpenStateConst.OPEN_STATE_PHOTOGRAPH = 55
OpenStateConst.OPEN_STATE_GUIDE_KSLQUEST = 56
OpenStateConst.OPEN_STATE_PERSONAL_LINE = 57
OpenStateConst.OPEN_STATE_GUIDE_PERSONAL_LINE = 58
OpenStateConst.OPEN_STATE_GUIDE_APPEARANCE = 59
OpenStateConst.OPEN_STATE_GUIDE_PROCESS = 60
OpenStateConst.OPEN_STATE_GUIDE_PERSONAL_LINE_KEY = 61
OpenStateConst.OPEN_STATE_GUIDE_WIDGET = 62
OpenStateConst.OPEN_STATE_GUIDE_ACTIVITY_SKILL_ASTER = 63
OpenStateConst.OPEN_STATE_GUIDE_COLDCLIMATE = 64
OpenStateConst.OPEN_STATE_DERIVATIVE_MALL = 65
OpenStateConst.OPEN_STATE_GUIDE_EXITMULTIPLAYER = 66
OpenStateConst.OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD = 67
OpenStateConst.OPEN_STATE_GUIDE_THEATREMACHANICUS_REBUILD = 68
OpenStateConst.OPEN_STATE_GUIDE_THEATREMACHANICUS_CARD = 69
OpenStateConst.OPEN_STATE_GUIDE_THEATREMACHANICUS_MONSTER = 70
OpenStateConst.OPEN_STATE_GUIDE_THEATREMACHANICUS_MISSION_CHECK = 71
OpenStateConst.OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD_SELECT = 72
OpenStateConst.OPEN_STATE_GUIDE_THEATREMACHANICUS_CHALLENGE_START = 73
OpenStateConst.OPEN_STATE_GUIDE_CONVERT = 74
OpenStateConst.OPEN_STATE_GUIDE_THEATREMACHANICUS_MULTIPLAYER = 75
OpenStateConst.OPEN_STATE_GUIDE_COOP_TASK = 76
OpenStateConst.OPEN_STATE_GUIDE_HOMEWORLD_ADEPTIABODE = 77
OpenStateConst.OPEN_STATE_GUIDE_HOMEWORLD_DEPLOY = 78
OpenStateConst.OPEN_STATE_GUIDE_CHANNELLERSLAB_EQUIP = 79
OpenStateConst.OPEN_STATE_GUIDE_CHANNELLERSLAB_MP_SOLUTION = 80
OpenStateConst.OPEN_STATE_GUIDE_CHANNELLERSLAB_POWER = 81
OpenStateConst.OPEN_STATE_GUIDE_HIDEANDSEEK_SKILL = 82
OpenStateConst.OPEN_STATE_GUIDE_HOMEWORLD_MAPLIST = 83
OpenStateConst.OPEN_STATE_GUIDE_RELICRESOLVE = 84
OpenStateConst.OPEN_STATE_GUIDE_GGUIDE = 85
OpenStateConst.OPEN_STATE_GUIDE_GGUIDE_HINT = 86
OpenStateConst.OPEN_STATE_CITY_REPUATION_MENGDE = 800
OpenStateConst.OPEN_STATE_CITY_REPUATION_LIYUE = 801
OpenStateConst.OPEN_STATE_CITY_REPUATION_UI_HINT = 802
OpenStateConst.OPEN_STATE_CITY_REPUATION_INAZUMA = 803
OpenStateConst.OPEN_STATE_SHOP_TYPE_MALL = 900
OpenStateConst.OPEN_STATE_SHOP_TYPE_RECOMMANDED = 901
OpenStateConst.OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL = 902
OpenStateConst.OPEN_STATE_SHOP_TYPE_GIFTPACKAGE = 903
OpenStateConst.OPEN_STATE_SHOP_TYPE_PAIMON = 1001
OpenStateConst.OPEN_STATE_SHOP_TYPE_CITY = 1002
OpenStateConst.OPEN_STATE_SHOP_TYPE_BLACKSMITH = 1003
OpenStateConst.OPEN_STATE_SHOP_TYPE_GROCERY = 1004
OpenStateConst.OPEN_STATE_SHOP_TYPE_FOOD = 1005
OpenStateConst.OPEN_STATE_SHOP_TYPE_SEA_LAMP = 1006
OpenStateConst.OPEN_STATE_SHOP_TYPE_VIRTUAL_SHOP = 1007
OpenStateConst.OPEN_STATE_SHOP_TYPE_LIYUE_GROCERY = 1008
OpenStateConst.OPEN_STATE_SHOP_TYPE_LIYUE_SOUVENIR = 1009
OpenStateConst.OPEN_STATE_SHOP_TYPE_LIYUE_RESTAURANT = 1010
OpenStateConst.OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR = 1011
OpenStateConst.OPEN_STATE_SHOP_TYPE_NPC_TOMOKI = 1012
OpenStateConst.OPEN_ADVENTURE_MANUAL = 1100
OpenStateConst.OPEN_ADVENTURE_MANUAL_CITY_MENGDE = 1101
OpenStateConst.OPEN_ADVENTURE_MANUAL_CITY_LIYUE = 1102
OpenStateConst.OPEN_ADVENTURE_MANUAL_MONSTER = 1103
OpenStateConst.OPEN_ADVENTURE_MANUAL_BOSS_DUNGEON = 1104
OpenStateConst.OPEN_STATE_ACTIVITY_SEALAMP = 1200
OpenStateConst.OPEN_STATE_ACTIVITY_SEALAMP_TAB2 = 1201
OpenStateConst.OPEN_STATE_ACTIVITY_SEALAMP_TAB3 = 1202
OpenStateConst.OPEN_STATE_BATTLE_PASS = 1300
OpenStateConst.OPEN_STATE_BATTLE_PASS_ENTRY = 1301
OpenStateConst.OPEN_STATE_ACTIVITY_CRUCIBLE = 1400
OpenStateConst.OPEN_STATE_ACTIVITY_NEWBEEBOUNS_OPEN = 1401
OpenStateConst.OPEN_STATE_ACTIVITY_NEWBEEBOUNS_CLOSE = 1402
OpenStateConst.OPEN_STATE_ACTIVITY_ENTRY_OPEN = 1403
OpenStateConst.OPEN_STATE_MENGDE_INFUSEDCRYSTAL = 1404
OpenStateConst.OPEN_STATE_LIYUE_INFUSEDCRYSTAL = 1405
OpenStateConst.OPEN_STATE_SNOW_MOUNTAIN_ELDER_TREE = 1406
OpenStateConst.OPEN_STATE_MIRACLE_RING = 1407
OpenStateConst.OPEN_STATE_COOP_LINE = 1408
OpenStateConst.OPEN_STATE_INAZUMA_INFUSEDCRYSTAL = 1409
OpenStateConst.OPEN_STATE_FISH = 1410
OpenStateConst.OPEN_STATE_GUIDE_SUMO_TEAM_SKILL = 1411
OpenStateConst.OPEN_STATE_GUIDE_FISH_RECIPE = 1412
OpenStateConst.OPEN_STATE_HOME = 1500
OpenStateConst.OPEN_STATE_ACTIVITY_HOMEWORLD = 1501
OpenStateConst.OPEN_STATE_ADEPTIABODE = 1502
OpenStateConst.OPEN_STATE_HOME_AVATAR = 1503
OpenStateConst.OPEN_STATE_HOME_EDIT = 1504
OpenStateConst.OPEN_STATE_HOME_EDIT_TIPS = 1505
OpenStateConst.OPEN_STATE_RELIQUARY_DECOMPOSE = 1600
OpenStateConst.OPEN_STATE_ACTIVITY_H5 = 1700
OpenStateConst.OPEN_STATE_ORAIONOKAMI = 2000
OpenStateConst.OPEN_STATE_GUIDE_CHESS_MISSION_CHECK = 2001
OpenStateConst.OPEN_STATE_GUIDE_CHESS_BUILD = 2002
OpenStateConst.OPEN_STATE_GUIDE_CHESS_WIND_TOWER_CIRCLE = 2003
OpenStateConst.OPEN_STATE_GUIDE_CHESS_CARD_SELECT = 2004
OpenStateConst.OPEN_STATE_INAZUMA_MAINQUEST_FINISHED = 2005
OpenStateConst.OPEN_STATE_PAIMON_LVINFO = 2100
OpenStateConst.OPEN_STATE_TELEPORT_HUD = 2101
OpenStateConst.OPEN_STATE_GUIDE_MAP_UNLOCK = 2102
OpenStateConst.OPEN_STATE_GUIDE_PAIMON_LVINFO = 2103
OpenStateConst.OPEN_STATE_GUIDE_AMBORTRANSPORT = 2104
OpenStateConst.OPEN_STATE_GUIDE_FLY_SECOND = 2105
OpenStateConst.OPEN_STATE_GUIDE_KAEYA_CLUE = 2106
OpenStateConst.OPEN_STATE_CAPTURE_CODEX = 2107
OpenStateConst.OPEN_STATE_ACTIVITY_FISH_OPEN = 2200
OpenStateConst.OPEN_STATE_ACTIVITY_FISH_CLOSE = 2201
OpenStateConst.OPEN_STATE_GUIDE_ROGUE_MAP = 2205
OpenStateConst.OPEN_STATE_GUIDE_ROGUE_RUNE = 2206
OpenStateConst.OPEN_STATE_GUIDE_BARTENDER_FORMULA = 2210
OpenStateConst.OPEN_STATE_GUIDE_BARTENDER_MIX = 2211
OpenStateConst.OPEN_STATE_GUIDE_BARTENDER_CUP = 2212
OpenStateConst.OPEN_STATE_GUIDE_MAIL_FAVORITES = 2400
OpenStateConst.OPEN_STATE_GUIDE_POTION_CONFIGURE = 2401
OpenStateConst.OPEN_STATE_GUIDE_LANV2_FIREWORK = 2402
OpenStateConst.OPEN_STATE_LOADINGTIPS_ENKANOMIYA = 2403
OpenStateConst.OPEN_STATE_MICHIAE_CASKET = 2500
OpenStateConst.OPEN_STATE_MAIL_COLLECT_UNLOCK_RED_POINT = 2501
OpenStateConst.OPEN_STATE_LUMEN_STONE = 2600
OpenStateConst.OPEN_STATE_GUIDE_CRYSTALLINK_BUFF = 2601
}

View File

@@ -0,0 +1,95 @@
package constant
var PlayerPropertyConst *PlayerProperty
type PlayerProperty struct {
PROP_EXP uint16 // 角色经验
PROP_BREAK_LEVEL uint16 // 角色突破等阶
PROP_SATIATION_VAL uint16 // 角色饱食度
PROP_SATIATION_PENALTY_TIME uint16 // 角色饱食度溢出
PROP_LEVEL uint16 // 角色等级
PROP_LAST_CHANGE_AVATAR_TIME uint16 // 上一次改变角色的时间 暂不确定
PROP_MAX_SPRING_VOLUME uint16 // 七天神像最大恢复血量 0-8500000
PROP_CUR_SPRING_VOLUME uint16 // 七天神像当前血量 0-PROP_MAX_SPRING_VOLUME
PROP_IS_SPRING_AUTO_USE uint16 // 是否开启靠近自动回血 0 1
PROP_SPRING_AUTO_USE_PERCENT uint16 // 自动回血百分比 0-100
PROP_IS_FLYABLE uint16 // 禁止使用风之翼 0 1
PROP_IS_WEATHER_LOCKED uint16 // 游戏内天气锁定 暂不确定
PROP_IS_GAME_TIME_LOCKED uint16 // 游戏内时间锁定 暂不确定
PROP_IS_TRANSFERABLE uint16 // 是否禁止传送 0 1
PROP_MAX_STAMINA uint16 // 最大体力 0-24000
PROP_CUR_PERSIST_STAMINA uint16 // 当前体力 0-PROP_MAX_STAMINA
PROP_CUR_TEMPORARY_STAMINA uint16 // 当前临时体力 暂不确定
PROP_PLAYER_LEVEL uint16 // 冒险等级
PROP_PLAYER_EXP uint16 // 冒险经验
PROP_PLAYER_HCOIN uint16 // 原石 可以为负数
PROP_PLAYER_SCOIN uint16 // 摩拉
PROP_PLAYER_MP_SETTING_TYPE uint16 // 多人游戏世界权限 0禁止加入 1直接加入 2需要申请
PROP_IS_MP_MODE_AVAILABLE uint16 // 玩家当前的世界是否可加入 0 1 例如任务中就不可加入
PROP_PLAYER_WORLD_LEVEL uint16 // 世界等级 0-8
PROP_PLAYER_RESIN uint16 // 树脂 0-2000
PROP_PLAYER_WAIT_SUB_HCOIN uint16 // 暂存的原石 暂不确定
PROP_PLAYER_WAIT_SUB_SCOIN uint16 // 暂存的摩拉 暂不确定
PROP_IS_ONLY_MP_WITH_PS_PLAYER uint16 // 当前玩家多人世界里是否有PS主机玩家 0 1
PROP_PLAYER_MCOIN uint16 // 创世结晶 可以为负数
PROP_PLAYER_WAIT_SUB_MCOIN uint16 // 暂存的创世结晶 暂不确定
PROP_PLAYER_LEGENDARY_KEY uint16 // 传说任务钥匙
PROP_IS_HAS_FIRST_SHARE uint16 // 是否拥有抽卡结果首次分享奖励 暂不确定
PROP_PLAYER_FORGE_POINT uint16 // 锻造相关
PROP_CUR_CLIMATE_METER uint16 // 天气相关
PROP_CUR_CLIMATE_TYPE uint16 // 天气相关
PROP_CUR_CLIMATE_AREA_ID uint16 // 天气相关
PROP_CUR_CLIMATE_AREA_CLIMATE_TYPE uint16 // 天气相关
PROP_PLAYER_WORLD_LEVEL_LIMIT uint16 // 降低世界等级到此等级 暂不确定
PROP_PLAYER_WORLD_LEVEL_ADJUST_CD uint16 // 降低世界等级的CD
PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM uint16 // 传说每日任务数量 暂不确定
PROP_PLAYER_HOME_COIN uint16 // 洞天宝钱
PROP_PLAYER_WAIT_SUB_HOME_COIN uint16 // 暂存的洞天宝钱 暂不确定
}
func InitPlayerPropertyConst() {
PlayerPropertyConst = new(PlayerProperty)
PlayerPropertyConst.PROP_EXP = 1001
PlayerPropertyConst.PROP_BREAK_LEVEL = 1002
PlayerPropertyConst.PROP_SATIATION_VAL = 1003
PlayerPropertyConst.PROP_SATIATION_PENALTY_TIME = 1004
PlayerPropertyConst.PROP_LEVEL = 4001
PlayerPropertyConst.PROP_LAST_CHANGE_AVATAR_TIME = 10001
PlayerPropertyConst.PROP_MAX_SPRING_VOLUME = 10002
PlayerPropertyConst.PROP_CUR_SPRING_VOLUME = 10003
PlayerPropertyConst.PROP_IS_SPRING_AUTO_USE = 10004
PlayerPropertyConst.PROP_SPRING_AUTO_USE_PERCENT = 10005
PlayerPropertyConst.PROP_IS_FLYABLE = 10006
PlayerPropertyConst.PROP_IS_WEATHER_LOCKED = 10007
PlayerPropertyConst.PROP_IS_GAME_TIME_LOCKED = 10008
PlayerPropertyConst.PROP_IS_TRANSFERABLE = 10009
PlayerPropertyConst.PROP_MAX_STAMINA = 10010
PlayerPropertyConst.PROP_CUR_PERSIST_STAMINA = 10011
PlayerPropertyConst.PROP_CUR_TEMPORARY_STAMINA = 10012
PlayerPropertyConst.PROP_PLAYER_LEVEL = 10013
PlayerPropertyConst.PROP_PLAYER_EXP = 10014
PlayerPropertyConst.PROP_PLAYER_HCOIN = 10015
PlayerPropertyConst.PROP_PLAYER_SCOIN = 10016
PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE = 10017
PlayerPropertyConst.PROP_IS_MP_MODE_AVAILABLE = 10018
PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL = 10019
PlayerPropertyConst.PROP_PLAYER_RESIN = 10020
PlayerPropertyConst.PROP_PLAYER_WAIT_SUB_HCOIN = 10022
PlayerPropertyConst.PROP_PLAYER_WAIT_SUB_SCOIN = 10023
PlayerPropertyConst.PROP_IS_ONLY_MP_WITH_PS_PLAYER = 10024
PlayerPropertyConst.PROP_PLAYER_MCOIN = 10025
PlayerPropertyConst.PROP_PLAYER_WAIT_SUB_MCOIN = 10026
PlayerPropertyConst.PROP_PLAYER_LEGENDARY_KEY = 10027
PlayerPropertyConst.PROP_IS_HAS_FIRST_SHARE = 10028
PlayerPropertyConst.PROP_PLAYER_FORGE_POINT = 10029
PlayerPropertyConst.PROP_CUR_CLIMATE_METER = 10035
PlayerPropertyConst.PROP_CUR_CLIMATE_TYPE = 10036
PlayerPropertyConst.PROP_CUR_CLIMATE_AREA_ID = 10037
PlayerPropertyConst.PROP_CUR_CLIMATE_AREA_CLIMATE_TYPE = 10038
PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL_LIMIT = 10039
PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL_ADJUST_CD = 10040
PlayerPropertyConst.PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM = 10041
PlayerPropertyConst.PROP_PLAYER_HOME_COIN = 10042
PlayerPropertyConst.PROP_PLAYER_WAIT_SUB_HOME_COIN = 10043
}

View File

@@ -0,0 +1,25 @@
package constant
var SceneTypeConst *SceneType
type SceneType struct {
SCENE_NONE uint16
SCENE_WORLD uint16
SCENE_DUNGEON uint16
SCENE_ROOM uint16
SCENE_HOME_WORLD uint16
SCENE_HOME_ROOM uint16
SCENE_ACTIVITY uint16
}
func InitSceneTypeConst() {
SceneTypeConst = new(SceneType)
SceneTypeConst.SCENE_NONE = 0
SceneTypeConst.SCENE_WORLD = 1
SceneTypeConst.SCENE_DUNGEON = 2
SceneTypeConst.SCENE_ROOM = 3
SceneTypeConst.SCENE_HOME_WORLD = 4
SceneTypeConst.SCENE_HOME_ROOM = 5
SceneTypeConst.SCENE_ACTIVITY = 6
}

View File

@@ -0,0 +1,34 @@
package dao
import (
"context"
"flswld.com/common/config"
"flswld.com/logger"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type Dao struct {
client *mongo.Client
db *mongo.Database
}
func NewDao() (r *Dao) {
r = new(Dao)
clientOptions := options.Client().ApplyURI(config.CONF.Database.Url)
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
logger.LOG.Error("mongo connect error: %v", err)
return nil
}
r.client = client
r.db = client.Database("game_hk4e")
return r
}
func (d *Dao) CloseDao() {
err := d.client.Disconnect(context.TODO())
if err != nil {
logger.LOG.Error("mongo close error: %v", err)
}
}

View File

@@ -0,0 +1,107 @@
package dao
import (
"context"
"game-hk4e/model"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
func (d *Dao) InsertPlayer(player *model.Player) error {
db := d.db.Collection("player")
_, err := db.InsertOne(context.TODO(), player)
return err
}
func (d *Dao) InsertPlayerList(playerList []*model.Player) error {
if len(playerList) == 0 {
return nil
}
db := d.db.Collection("player")
modelOperateList := make([]mongo.WriteModel, 0)
for _, player := range playerList {
modelOperate := mongo.NewInsertOneModel().SetDocument(player)
modelOperateList = append(modelOperateList, modelOperate)
}
_, err := db.BulkWrite(context.TODO(), modelOperateList)
return err
}
func (d *Dao) DeletePlayer(playerID uint32) error {
db := d.db.Collection("player")
_, err := db.DeleteOne(context.TODO(), bson.D{{"playerID", playerID}})
return err
}
func (d *Dao) DeletePlayerList(playerIDList []uint32) error {
if len(playerIDList) == 0 {
return nil
}
db := d.db.Collection("player")
modelOperateList := make([]mongo.WriteModel, 0)
for _, playerID := range playerIDList {
modelOperate := mongo.NewDeleteOneModel().SetFilter(bson.D{{"playerID", playerID}})
modelOperateList = append(modelOperateList, modelOperate)
}
_, err := db.BulkWrite(context.TODO(), modelOperateList)
return err
}
func (d *Dao) UpdatePlayer(player *model.Player) error {
db := d.db.Collection("player")
_, err := db.UpdateOne(
context.TODO(),
bson.D{{"playerID", player.PlayerID}},
bson.D{{"$set", player}},
)
return err
}
func (d *Dao) UpdatePlayerList(playerList []*model.Player) error {
if len(playerList) == 0 {
return nil
}
db := d.db.Collection("player")
modelOperateList := make([]mongo.WriteModel, 0)
for _, player := range playerList {
modelOperate := mongo.NewUpdateOneModel().SetFilter(bson.D{{"playerID", player.PlayerID}}).SetUpdate(bson.D{{"$set", player}})
modelOperateList = append(modelOperateList, modelOperate)
}
_, err := db.BulkWrite(context.TODO(), modelOperateList)
return err
}
func (d *Dao) QueryPlayerByID(playerID uint32) (*model.Player, error) {
db := d.db.Collection("player")
result := db.FindOne(
context.TODO(),
bson.D{{"playerID", playerID}},
)
item := new(model.Player)
err := result.Decode(item)
if err != nil {
return nil, err
}
return item, nil
}
func (d *Dao) QueryPlayerList() ([]*model.Player, error) {
db := d.db.Collection("player")
find, err := db.Find(
context.TODO(),
bson.D{},
)
if err != nil {
return nil, err
}
result := make([]*model.Player, 0)
for find.Next(context.TODO()) {
item := new(model.Player)
err = find.Decode(item)
if err != nil {
return nil, err
}
result = append(result, item)
}
return result, nil
}

View File

@@ -0,0 +1,211 @@
package aoi
import (
"flswld.com/logger"
"fmt"
)
// aoi管理模块
type AoiManager struct {
// 区域边界坐标
minX int16
maxX int16
minY int16
maxY int16
minZ int16
maxZ int16
numX int16 // x方向格子的数量
numY int16 // y方向的格子数量
numZ int16 // z方向的格子数量
gridMap map[uint32]*Grid // 当前区域中都有哪些格子 key:gid value:格子对象
}
// 初始化aoi区域
func NewAoiManager(minX, maxX, numX, minY, maxY, numY, minZ, maxZ, numZ int16) (r *AoiManager) {
r = new(AoiManager)
r.minX = minX
r.maxX = maxX
r.minY = minY
r.maxY = maxY
r.numX = numX
r.numY = numY
r.minZ = minZ
r.maxZ = maxZ
r.numZ = numZ
r.gridMap = make(map[uint32]*Grid)
logger.LOG.Info("start init aoi area grid, num: %v", uint32(numX)*uint32(numY)*uint32(numZ))
// 初始化aoi区域中所有的格子
for x := int16(0); x < numX; x++ {
for y := int16(0); y < numY; y++ {
for z := int16(0); z < numZ; z++ {
// 利用格子坐标得到格子id gid从0开始按xzy的顺序增长
gid := uint32(y)*(uint32(numX)*uint32(numZ)) + uint32(z)*uint32(numX) + uint32(x)
// 初始化一个格子放在aoi中的map里 key是当前格子的id
grid := NewGrid(
gid,
r.minX+x*r.GridXLen(),
r.minX+(x+1)*r.GridXLen(),
r.minY+y*r.GridYLen(),
r.minY+(y+1)*r.GridYLen(),
r.minZ+z*r.GridZLen(),
r.minZ+(z+1)*r.GridZLen(),
)
r.gridMap[gid] = grid
}
}
}
logger.LOG.Info("init aoi area grid finish")
return r
}
// 每个格子在x轴方向的长度
func (a *AoiManager) GridXLen() int16 {
return (a.maxX - a.minX) / a.numX
}
// 每个格子在y轴方向的长度
func (a *AoiManager) GridYLen() int16 {
return (a.maxY - a.minY) / a.numY
}
// 每个格子在z轴方向的长度
func (a *AoiManager) GridZLen() int16 {
return (a.maxZ - a.minZ) / a.numZ
}
// 通过坐标获取对应的格子id
func (a *AoiManager) GetGidByPos(x, y, z float32) uint32 {
gx := (int16(x) - a.minX) / a.GridXLen()
gy := (int16(y) - a.minY) / a.GridYLen()
gz := (int16(z) - a.minZ) / a.GridZLen()
return uint32(gy)*(uint32(a.numX)*uint32(a.numZ)) + uint32(gz)*uint32(a.numX) + uint32(gx)
}
// 判断坐标是否存在于aoi区域内
func (a *AoiManager) IsValidAoiPos(x, y, z float32) bool {
if (int16(x) > a.minX && int16(x) < a.maxX) &&
(int16(y) > a.minY && int16(y) < a.maxY) &&
(int16(z) > a.minZ && int16(z) < a.maxZ) {
return true
} else {
return false
}
}
// 打印信息方法
func (a *AoiManager) DebugString() string {
s := fmt.Sprintf("AoiMgr: minX: %d, maxX: %d, numX: %d, minY: %d, maxY: %d, numY: %d, minZ: %d, maxZ: %d, numZ: %d\n",
a.minX, a.maxX, a.numX, a.minY, a.maxY, a.numY, a.minZ, a.maxZ, a.numZ)
s += "gridList in AoiMgr:\n"
for _, grid := range a.gridMap {
s += fmt.Sprintln(grid.DebugString())
}
return s
}
// 根据格子的gid得到当前周边的格子信息
func (a *AoiManager) GetSurrGridListByGid(gid uint32) (gridList []*Grid) {
gridList = make([]*Grid, 0)
// 判断grid是否存在
grid, exist := a.gridMap[gid]
if !exist {
return gridList
}
// 添加自己
gridList = append(gridList, grid)
// 根据gid得到当前格子所在的x轴编号
idx := int16(gid % (uint32(a.numX) * uint32(a.numZ)) % uint32(a.numX))
// 判断当前格子左边是否还有格子
if idx > 0 {
gridList = append(gridList, a.gridMap[gid-1])
}
// 判断当前格子右边是否还有格子
if idx < a.numX-1 {
gridList = append(gridList, a.gridMap[gid+1])
}
// 将x轴当前的格子都取出进行遍历 再分别得到每个格子的平面上下是否有格子
// 得到当前x轴的格子id集合
gidListX := make([]uint32, 0)
for _, v := range gridList {
gidListX = append(gidListX, v.gid)
}
// 遍历x轴格子
for _, v := range gidListX {
// 计算该格子的idz
idz := int16(v % (uint32(a.numX) * uint32(a.numZ)) / uint32(a.numX))
// 判断当前格子平面上方是否还有格子
if idz > 0 {
gridList = append(gridList, a.gridMap[v-uint32(a.numX)])
}
// 判断当前格子平面下方是否还有格子
if idz < a.numZ-1 {
gridList = append(gridList, a.gridMap[v+uint32(a.numX)])
}
}
// 将xoz平面当前的格子都取出进行遍历 再分别得到每个格子的空间上下是否有格子
// 得到当前xoz平面的格子id集合
gidListXOZ := make([]uint32, 0)
for _, v := range gridList {
gidListXOZ = append(gidListXOZ, v.gid)
}
// 遍历xoz平面格子
for _, v := range gidListXOZ {
// 计算该格子的idy
idy := int16(v / (uint32(a.numX) * uint32(a.numZ)))
// 判断当前格子空间上方是否还有格子
if idy > 0 {
gridList = append(gridList, a.gridMap[v-uint32(a.numX)*uint32(a.numZ)])
}
// 判断当前格子空间下方是否还有格子
if idy < a.numY-1 {
gridList = append(gridList, a.gridMap[v+uint32(a.numX)*uint32(a.numZ)])
}
}
return gridList
}
// 通过坐标得到周边格子内的全部entityId
func (a *AoiManager) GetEntityIdListByPos(x, y, z float32) (entityIdList []uint32) {
// 根据坐标得到当前坐标属于哪个格子id
gid := a.GetGidByPos(x, y, z)
// 根据格子id得到周边格子的信息
gridList := a.GetSurrGridListByGid(gid)
entityIdList = make([]uint32, 0)
for _, v := range gridList {
tmp := v.GetEntityIdList()
entityIdList = append(entityIdList, tmp...)
//logger.LOG.Debug("Grid: gid: %d, tmp len: %v", v.gid, len(tmp))
}
return entityIdList
}
// 通过gid获取当前格子的全部entityId
func (a *AoiManager) GetEntityIdListByGid(gid uint32) (entityIdList []uint32) {
grid := a.gridMap[gid]
entityIdList = grid.GetEntityIdList()
return entityIdList
}
// 添加一个entityId到一个格子中
func (a *AoiManager) AddEntityIdToGrid(entityId uint32, gid uint32) {
grid := a.gridMap[gid]
grid.AddEntityId(entityId)
}
// 移除一个格子中的entityId
func (a *AoiManager) RemoveEntityIdFromGrid(entityId uint32, gid uint32) {
grid := a.gridMap[gid]
grid.RemoveEntityId(entityId)
}
// 通过坐标添加一个entityId到一个格子中
func (a *AoiManager) AddEntityIdToGridByPos(entityId uint32, x, y, z float32) {
gid := a.GetGidByPos(x, y, z)
a.AddEntityIdToGrid(entityId, gid)
}
// 通过坐标把一个entityId从对应的格子中删除
func (a *AoiManager) RemoveEntityIdFromGridByPos(entityId uint32, x, y, z float32) {
gid := a.GetGidByPos(x, y, z)
a.RemoveEntityIdFromGrid(entityId, gid)
}

View File

@@ -0,0 +1,30 @@
package aoi
import (
"flswld.com/common/config"
"flswld.com/logger"
"testing"
)
func TestAoiManagerGetSurrGridListByGid(t *testing.T) {
filePath := "./application.toml"
config.InitConfig(filePath)
logger.InitLogger()
aoiManager := NewAoiManager(
-150, 150, 3,
-150, 150, 3,
-150, 150, 3,
)
logger.LOG.Debug("aoiManager: %s", aoiManager.DebugString())
for k := range aoiManager.gridMap {
// 得到当前格子周边的九宫格
gridList := aoiManager.GetSurrGridListByGid(k)
// 得到九宫格所有的id
logger.LOG.Debug("gid: %d gridList len: %d", k, len(gridList))
gidList := make([]uint32, 0, len(gridList))
for _, grid := range gridList {
gidList = append(gidList, grid.gid)
}
logger.LOG.Debug("Grid: gid: %d, surr grid gid list: %v", k, gidList)
}
}

View File

@@ -0,0 +1,63 @@
package aoi
import (
"flswld.com/logger"
"fmt"
)
// 地图格子
type Grid struct {
gid uint32 // 格子id
// 格子边界坐标
minX int16
maxX int16
minY int16
maxY int16
minZ int16
maxZ int16
entityIdMap map[uint32]bool // k:entityId v:是否存在
}
// 初始化格子
func NewGrid(gid uint32, minX, maxX, minY, maxY, minZ, maxZ int16) (r *Grid) {
r = new(Grid)
r.gid = gid
r.minX = minX
r.maxX = maxX
r.minY = minY
r.maxY = maxY
r.minZ = minZ
r.maxZ = maxZ
r.entityIdMap = make(map[uint32]bool)
return r
}
// 向格子中添加一个实体id
func (g *Grid) AddEntityId(entityId uint32) {
g.entityIdMap[entityId] = true
}
// 从格子中删除一个实体id
func (g *Grid) RemoveEntityId(entityId uint32) {
_, exist := g.entityIdMap[entityId]
if exist {
delete(g.entityIdMap, entityId)
} else {
logger.LOG.Error("remove entity id but it not exist, entityId: %v", entityId)
}
}
// 获取格子中所有实体id
func (g *Grid) GetEntityIdList() (entityIdList []uint32) {
entityIdList = make([]uint32, 0)
for k := range g.entityIdMap {
entityIdList = append(entityIdList, k)
}
return entityIdList
}
// 打印信息方法
func (g *Grid) DebugString() string {
return fmt.Sprintf("Grid: gid: %d, minX: %d, maxX: %d, minY: %d, maxY: %d, minZ: %d, maxZ: %d, entityIdMap: %v",
g.gid, g.minX, g.maxX, g.minY, g.maxY, g.minZ, g.maxZ, g.entityIdMap)
}

View File

@@ -0,0 +1,112 @@
package game
import (
"flswld.com/common/utils/alg"
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
"game-hk4e/dao"
"game-hk4e/model"
"game-hk4e/rpc"
pb "google.golang.org/protobuf/proto"
)
type GameManager struct {
dao *dao.Dao
rpcManager *rpc.RpcManager
netMsgInput chan *proto.NetMsg
netMsgOutput chan *proto.NetMsg
snowflake *alg.SnowflakeWorker
// 本地事件队列管理器
localEventManager *LocalEventManager
// 接口路由管理器
routeManager *RouteManager
// 用户管理器
userManager *UserManager
// 世界管理器
worldManager *WorldManager
// 游戏服务器tick
tickManager *TickManager
}
func NewGameManager(dao *dao.Dao, rpcManager *rpc.RpcManager, netMsgInput chan *proto.NetMsg, netMsgOutput chan *proto.NetMsg) (r *GameManager) {
r = new(GameManager)
r.dao = dao
r.rpcManager = rpcManager
r.netMsgInput = netMsgInput
r.netMsgOutput = netMsgOutput
r.snowflake = alg.NewSnowflakeWorker(1)
r.localEventManager = NewLocalEventManager(r)
r.routeManager = NewRouteManager(r)
r.userManager = NewUserManager(dao, r.localEventManager.localEventChan)
r.worldManager = NewWorldManager(r.snowflake)
r.tickManager = NewTickManager(r)
r.worldManager.worldStatic.InitTerrain()
r.worldManager.worldStatic.Pathfinding()
r.worldManager.worldStatic.ConvPathVectorListToAiMoveVectorList()
// 大世界的主人
r.OnRegOk(false, &proto.SetPlayerBornDataReq{AvatarId: 10000007, NickName: "大世界的主人"}, 1, 0)
bigWorldOwner := r.userManager.GetOnlineUser(1)
bigWorldOwner.SceneLoadState = model.SceneEnterDone
bigWorldOwner.DbState = model.DbNormal
r.worldManager.InitBigWorld(bigWorldOwner)
return r
}
func (g *GameManager) Start() {
g.routeManager.InitRoute()
g.userManager.StartAutoSaveUser()
go func() {
for {
select {
case netMsg := <-g.netMsgOutput:
// 接收客户端消息
g.routeManager.RouteHandle(netMsg)
case <-g.tickManager.ticker.C:
// 游戏服务器定时帧
g.tickManager.OnGameServerTick()
case localEvent := <-g.localEventManager.localEventChan:
// 处理本地事件
g.localEventManager.LocalEventHandle(localEvent)
}
}
}()
}
func (g *GameManager) Stop() {
g.worldManager.worldStatic.SaveTerrain()
}
// 发送消息给客户端
func (g *GameManager) SendMsg(apiId uint16, userId uint32, clientSeq uint32, payloadMsg pb.Message) {
if userId < 100000000 {
return
}
netMsg := new(proto.NetMsg)
netMsg.UserId = userId
netMsg.EventId = proto.NormalMsg
netMsg.ApiId = apiId
netMsg.ClientSeq = clientSeq
// 在这里直接序列化成二进制数据 防止发送的消息内包含各种游戏数据指针 而造成并发读写的问题
payloadMessageData, err := pb.Marshal(payloadMsg)
if err != nil {
logger.LOG.Error("parse payload msg to bin error: %v", err)
return
}
netMsg.PayloadMessageData = payloadMessageData
g.netMsgInput <- netMsg
}
func (g *GameManager) ReconnectPlayer(userId uint32) {
g.SendMsg(proto.ApiClientReconnectNotify, userId, 0, new(proto.ClientReconnectNotify))
}
func (g *GameManager) DisconnectPlayer(userId uint32) {
g.SendMsg(proto.ApiServerDisconnectClientNotify, userId, 0, new(proto.ServerDisconnectClientNotify))
}
func (g *GameManager) KickPlayer(userId uint32) {
g.rpcManager.SendKickPlayerToHk4eGateway(userId)
}

View File

@@ -0,0 +1,34 @@
package game
const (
LoadLoginUserFromDbFinish = iota
CheckUserExistOnRegFromDbFinish
)
type LocalEvent struct {
EventId int
Msg any
}
type LocalEventManager struct {
localEventChan chan *LocalEvent
gameManager *GameManager
}
func NewLocalEventManager(gameManager *GameManager) (r *LocalEventManager) {
r = new(LocalEventManager)
r.localEventChan = make(chan *LocalEvent, 1000)
r.gameManager = gameManager
return r
}
func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
switch localEvent.EventId {
case LoadLoginUserFromDbFinish:
playerLoginInfo := localEvent.Msg.(*PlayerLoginInfo)
l.gameManager.OnLoginOk(playerLoginInfo.UserId, playerLoginInfo.Player, playerLoginInfo.ClientSeq)
case CheckUserExistOnRegFromDbFinish:
playerRegInfo := localEvent.Msg.(*PlayerRegInfo)
l.gameManager.OnRegOk(playerRegInfo.Exist, playerRegInfo.Req, playerRegInfo.UserId, playerRegInfo.ClientSeq)
}
}

View File

@@ -0,0 +1,103 @@
package game
import (
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
"time"
)
func (g *GameManager) PlayerSetPauseReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user pause, user id: %v", userId)
req := payloadMsg.(*proto.PlayerSetPauseReq)
isPaused := req.IsPaused
player.Pause = isPaused
// PacketPlayerSetPauseRsp
playerSetPauseRsp := new(proto.PlayerSetPauseRsp)
g.SendMsg(proto.ApiPlayerSetPauseRsp, userId, player.ClientSeq, playerSetPauseRsp)
}
func (g *GameManager) TowerAllDataReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get tower all data, user id: %v", userId)
// PacketTowerAllDataRsp
towerAllDataRsp := new(proto.TowerAllDataRsp)
towerAllDataRsp.TowerScheduleId = 29
towerAllDataRsp.TowerFloorRecordList = []*proto.TowerFloorRecord{{FloorId: 1001}}
towerAllDataRsp.CurLevelRecord = &proto.TowerCurLevelRecord{IsEmpty: true}
towerAllDataRsp.NextScheduleChangeTime = 4294967295
towerAllDataRsp.FloorOpenTimeMap = make(map[uint32]uint32)
towerAllDataRsp.FloorOpenTimeMap[1024] = 1630486800
towerAllDataRsp.FloorOpenTimeMap[1025] = 1630486800
towerAllDataRsp.FloorOpenTimeMap[1026] = 1630486800
towerAllDataRsp.FloorOpenTimeMap[1027] = 1630486800
towerAllDataRsp.ScheduleStartTime = 1630486800
g.SendMsg(proto.ApiTowerAllDataRsp, userId, player.ClientSeq, towerAllDataRsp)
}
func (g *GameManager) EntityAiSyncNotify(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user entity ai sync, user id: %v", userId)
req := payloadMsg.(*proto.EntityAiSyncNotify)
if len(req.LocalAvatarAlertedMonsterList) == 0 {
return
}
// PacketEntityAiSyncNotify
entityAiSyncNotify := new(proto.EntityAiSyncNotify)
entityAiSyncNotify.InfoList = make([]*proto.AiSyncInfo, 0)
for _, monsterId := range req.LocalAvatarAlertedMonsterList {
entityAiSyncNotify.InfoList = append(entityAiSyncNotify.InfoList, &proto.AiSyncInfo{
EntityId: monsterId,
HasPathToTarget: true,
IsSelfKilling: false,
})
}
g.SendMsg(proto.ApiEntityAiSyncNotify, userId, player.ClientSeq, entityAiSyncNotify)
}
func (g *GameManager) ClientTimeNotify(userId uint32, clientTime uint32) {
player := g.userManager.GetOnlineUser(userId)
if player == nil {
logger.LOG.Error("player is nil, userId: %v", userId)
return
}
logger.LOG.Debug("client time notify, user id: %v, time: %v", userId, clientTime)
player.ClientTime = clientTime
}
func (g *GameManager) ClientRttNotify(userId uint32, clientRtt uint32) {
player := g.userManager.GetOnlineUser(userId)
if player == nil {
logger.LOG.Error("player is nil, userId: %v", userId)
return
}
logger.LOG.Debug("client rtt notify, user id: %v, rtt: %v", userId, clientRtt)
player.ClientRTT = clientRtt
}
func (g *GameManager) ServerAnnounceNotify(announceId uint32, announceMsg string) {
for _, onlinePlayer := range g.userManager.GetAllOnlineUserList() {
serverAnnounceNotify := new(proto.ServerAnnounceNotify)
now := uint32(time.Now().Unix())
serverAnnounceNotify.AnnounceDataList = []*proto.AnnounceData{{
ConfigId: announceId,
BeginTime: now + 1,
EndTime: now + 2,
CenterSystemText: announceMsg,
CenterSystemFrequency: 1,
}}
g.SendMsg(proto.ApiServerAnnounceNotify, onlinePlayer.PlayerID, 0, serverAnnounceNotify)
}
}
func (g *GameManager) ServerAnnounceRevokeNotify(announceId uint32) {
for _, onlinePlayer := range g.userManager.GetAllOnlineUserList() {
serverAnnounceRevokeNotify := new(proto.ServerAnnounceRevokeNotify)
serverAnnounceRevokeNotify.ConfigIdList = []uint32{announceId}
g.SendMsg(proto.ApiServerAnnounceRevokeNotify, onlinePlayer.PlayerID, 0, serverAnnounceRevokeNotify)
}
}

View File

@@ -0,0 +1,116 @@
package game
import (
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
)
type HandlerFunc func(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message)
type RouteManager struct {
gameManager *GameManager
// k:apiId v:HandlerFunc
handlerFuncRouteMap map[uint16]HandlerFunc
}
func NewRouteManager(gameManager *GameManager) (r *RouteManager) {
r = new(RouteManager)
r.gameManager = gameManager
r.handlerFuncRouteMap = make(map[uint16]HandlerFunc)
return r
}
func (r *RouteManager) registerRouter(apiId uint16, handlerFunc HandlerFunc) {
r.handlerFuncRouteMap[apiId] = handlerFunc
}
func (r *RouteManager) doRoute(apiId uint16, userId uint32, clientSeq uint32, payloadMsg pb.Message) {
handlerFunc, ok := r.handlerFuncRouteMap[apiId]
if !ok {
logger.LOG.Error("no route for msg, apiId: %v", apiId)
return
}
player := r.gameManager.userManager.GetOnlineUser(userId)
if player == nil {
logger.LOG.Error("player is nil, userId: %v", userId)
return
}
player.ClientSeq = clientSeq
handlerFunc(userId, player, clientSeq, payloadMsg)
}
func (r *RouteManager) InitRoute() {
r.registerRouter(proto.ApiPlayerSetPauseReq, r.gameManager.PlayerSetPauseReq)
r.registerRouter(proto.ApiEnterSceneReadyReq, r.gameManager.EnterSceneReadyReq)
r.registerRouter(proto.ApiPathfindingEnterSceneReq, r.gameManager.PathfindingEnterSceneReq)
r.registerRouter(proto.ApiGetScenePointReq, r.gameManager.GetScenePointReq)
r.registerRouter(proto.ApiGetSceneAreaReq, r.gameManager.GetSceneAreaReq)
r.registerRouter(proto.ApiSceneInitFinishReq, r.gameManager.SceneInitFinishReq)
r.registerRouter(proto.ApiEnterSceneDoneReq, r.gameManager.EnterSceneDoneReq)
r.registerRouter(proto.ApiEnterWorldAreaReq, r.gameManager.EnterWorldAreaReq)
r.registerRouter(proto.ApiPostEnterSceneReq, r.gameManager.PostEnterSceneReq)
r.registerRouter(proto.ApiTowerAllDataReq, r.gameManager.TowerAllDataReq)
r.registerRouter(proto.ApiSceneTransToPointReq, r.gameManager.SceneTransToPointReq)
r.registerRouter(proto.ApiMarkMapReq, r.gameManager.MarkMapReq)
r.registerRouter(proto.ApiChangeAvatarReq, r.gameManager.ChangeAvatarReq)
r.registerRouter(proto.ApiSetUpAvatarTeamReq, r.gameManager.SetUpAvatarTeamReq)
r.registerRouter(proto.ApiChooseCurAvatarTeamReq, r.gameManager.ChooseCurAvatarTeamReq)
r.registerRouter(proto.ApiGetGachaInfoReq, r.gameManager.GetGachaInfoReq)
r.registerRouter(proto.ApiDoGachaReq, r.gameManager.DoGachaReq)
r.registerRouter(proto.ApiQueryPathReq, r.gameManager.QueryPathReq)
r.registerRouter(proto.ApiCombatInvocationsNotify, r.gameManager.CombatInvocationsNotify)
r.registerRouter(proto.ApiAbilityInvocationsNotify, r.gameManager.AbilityInvocationsNotify)
r.registerRouter(proto.ApiClientAbilityInitFinishNotify, r.gameManager.ClientAbilityInitFinishNotify)
r.registerRouter(proto.ApiEntityAiSyncNotify, r.gameManager.EntityAiSyncNotify)
r.registerRouter(proto.ApiWearEquipReq, r.gameManager.WearEquipReq)
r.registerRouter(proto.ApiChangeGameTimeReq, r.gameManager.ChangeGameTimeReq)
r.registerRouter(proto.ApiGetPlayerSocialDetailReq, r.gameManager.GetPlayerSocialDetailReq)
r.registerRouter(proto.ApiSetPlayerBirthdayReq, r.gameManager.SetPlayerBirthdayReq)
r.registerRouter(proto.ApiSetNameCardReq, r.gameManager.SetNameCardReq)
r.registerRouter(proto.ApiSetPlayerSignatureReq, r.gameManager.SetPlayerSignatureReq)
r.registerRouter(proto.ApiSetPlayerNameReq, r.gameManager.SetPlayerNameReq)
r.registerRouter(proto.ApiSetPlayerHeadImageReq, r.gameManager.SetPlayerHeadImageReq)
r.registerRouter(proto.ApiGetAllUnlockNameCardReq, r.gameManager.GetAllUnlockNameCardReq)
r.registerRouter(proto.ApiGetPlayerFriendListReq, r.gameManager.GetPlayerFriendListReq)
r.registerRouter(proto.ApiGetPlayerAskFriendListReq, r.gameManager.GetPlayerAskFriendListReq)
r.registerRouter(proto.ApiAskAddFriendReq, r.gameManager.AskAddFriendReq)
r.registerRouter(proto.ApiDealAddFriendReq, r.gameManager.DealAddFriendReq)
r.registerRouter(proto.ApiGetOnlinePlayerListReq, r.gameManager.GetOnlinePlayerListReq)
r.registerRouter(proto.ApiPlayerApplyEnterMpReq, r.gameManager.PlayerApplyEnterMpReq)
r.registerRouter(proto.ApiPlayerApplyEnterMpResultReq, r.gameManager.PlayerApplyEnterMpResultReq)
r.registerRouter(proto.ApiPlayerGetForceQuitBanInfoReq, r.gameManager.PlayerGetForceQuitBanInfoReq)
r.registerRouter(proto.ApiGetShopmallDataReq, r.gameManager.GetShopmallDataReq)
r.registerRouter(proto.ApiGetShopReq, r.gameManager.GetShopReq)
r.registerRouter(proto.ApiBuyGoodsReq, r.gameManager.BuyGoodsReq)
r.registerRouter(proto.ApiMcoinExchangeHcoinReq, r.gameManager.McoinExchangeHcoinReq)
r.registerRouter(proto.ApiAvatarChangeCostumeReq, r.gameManager.AvatarChangeCostumeReq)
r.registerRouter(proto.ApiAvatarWearFlycloakReq, r.gameManager.AvatarWearFlycloakReq)
r.registerRouter(proto.ApiPullRecentChatReq, r.gameManager.PullRecentChatReq)
r.registerRouter(proto.ApiPullPrivateChatReq, r.gameManager.PullPrivateChatReq)
r.registerRouter(proto.ApiPrivateChatReq, r.gameManager.PrivateChatReq)
r.registerRouter(proto.ApiReadPrivateChatReq, r.gameManager.ReadPrivateChatReq)
r.registerRouter(proto.ApiPlayerChatReq, r.gameManager.PlayerChatReq)
r.registerRouter(proto.ApiBackMyWorldReq, r.gameManager.BackMyWorldReq)
r.registerRouter(proto.ApiChangeWorldToSingleModeReq, r.gameManager.ChangeWorldToSingleModeReq)
r.registerRouter(proto.ApiSceneKickPlayerReq, r.gameManager.SceneKickPlayerReq)
r.registerRouter(proto.ApiChangeMpTeamAvatarReq, r.gameManager.ChangeMpTeamAvatarReq)
}
func (r *RouteManager) RouteHandle(netMsg *proto.NetMsg) {
switch netMsg.EventId {
case proto.NormalMsg:
r.doRoute(netMsg.ApiId, netMsg.UserId, netMsg.ClientSeq, netMsg.PayloadMessage)
case proto.UserRegNotify:
r.gameManager.OnReg(netMsg.UserId, netMsg.ClientSeq, netMsg.PayloadMessage)
case proto.UserLoginNotify:
r.gameManager.OnLogin(netMsg.UserId, netMsg.ClientSeq)
case proto.UserOfflineNotify:
r.gameManager.OnUserOffline(netMsg.UserId)
case proto.ClientRttNotify:
r.gameManager.ClientRttNotify(netMsg.UserId, netMsg.ClientRtt)
case proto.ClientTimeNotify:
r.gameManager.ClientTimeNotify(netMsg.UserId, netMsg.ClientTime)
}
}

View File

@@ -0,0 +1,312 @@
package game
import (
"flswld.com/common/utils/random"
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
"game-hk4e/constant"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
"math"
"time"
)
type TickManager struct {
ticker *time.Ticker
tickCount uint64
gameManager *GameManager
}
func NewTickManager(gameManager *GameManager) (r *TickManager) {
r = new(TickManager)
r.ticker = time.NewTicker(time.Millisecond * 100)
logger.LOG.Info("game server tick start at: %v", time.Now().UnixMilli())
r.gameManager = gameManager
return r
}
func (t *TickManager) OnGameServerTick() {
t.tickCount++
now := time.Now().UnixMilli()
t.onTick100MilliSecond(now)
if t.tickCount%(10*1) == 0 {
t.onTickSecond(now)
}
if t.tickCount%(10*5) == 0 {
t.onTick5Second(now)
}
if t.tickCount%(10*10) == 0 {
t.onTick10Second(now)
}
if t.tickCount%(10*60) == 0 {
t.onTickMinute(now)
}
if t.tickCount%(10*60*10) == 0 {
t.onTick10Minute(now)
}
if t.tickCount%(10*3600) == 0 {
t.onTickHour(now)
}
if t.tickCount%(10*3600*24) == 0 {
t.onTickDay(now)
}
if t.tickCount%(10*3600*24*7) == 0 {
t.onTickWeek(now)
}
}
func (t *TickManager) onTickWeek(now int64) {
logger.LOG.Info("on tick week, time: %v", now)
}
func (t *TickManager) onTickDay(now int64) {
logger.LOG.Info("on tick day, time: %v", now)
}
func (t *TickManager) onTickHour(now int64) {
logger.LOG.Info("on tick hour, time: %v", now)
}
func (t *TickManager) onTick10Minute(now int64) {
for _, world := range t.gameManager.worldManager.worldMap {
for _, player := range world.playerMap {
// 蓝球粉球
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 223, ChangeCount: 1}}, true, 0)
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 224, ChangeCount: 1}}, true, 0)
}
}
}
func (t *TickManager) onTickMinute(now int64) {
t.gameManager.ServerAnnounceNotify(100, "test123")
for _, world := range t.gameManager.worldManager.worldMap {
for _, player := range world.playerMap {
// 随机物品
allItemDataConfig := t.gameManager.GetAllItemDataConfig()
count := random.GetRandomInt32(0, 4)
i := int32(0)
for itemId := range allItemDataConfig {
itemDataConfig := allItemDataConfig[itemId]
// TODO 3.0.0REL版本中 发送某些无效家具 可能会导致客户端背包家具界面卡死
if itemDataConfig.ItemEnumType == constant.ItemTypeConst.ITEM_FURNITURE {
continue
}
num := random.GetRandomInt32(1, 9)
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: uint32(itemId), ChangeCount: uint32(num)}}, true, 0)
i++
if i > count {
break
}
}
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 102, ChangeCount: 30}}, true, 0)
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 201, ChangeCount: 10}}, true, 0)
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 202, ChangeCount: 100}}, true, 0)
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 203, ChangeCount: 10}}, true, 0)
}
}
}
func (t *TickManager) onTick10Second(now int64) {
for _, world := range t.gameManager.worldManager.worldMap {
if !world.IsBigWorld() && (world.multiplayer || !world.owner.Pause) {
// 刷怪
scene := world.GetSceneById(3)
monsterEntityCount := 0
for _, entity := range scene.entityMap {
if entity.entityType == uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER) {
monsterEntityCount++
}
}
if monsterEntityCount < 30 {
monsterEntityId := t.createMonster(scene)
bigWorldOwner := t.gameManager.userManager.GetOnlineUser(1)
t.gameManager.AddSceneEntityNotify(bigWorldOwner, proto.VisionType_VISION_TYPE_BORN, []uint32{monsterEntityId}, true)
}
}
for _, player := range world.playerMap {
if world.multiplayer || !world.owner.Pause {
// 改面板
team := player.TeamConfig.GetActiveTeam()
for _, avatarId := range team.AvatarIdList {
if avatarId == 0 {
break
}
avatar := player.AvatarMap[avatarId]
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK)] = 1000000
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL)] = 1.0
t.gameManager.UpdateUserAvatarFightProp(player.PlayerID, avatarId)
}
}
}
}
}
func (t *TickManager) onTick5Second(now int64) {
for _, world := range t.gameManager.worldManager.worldMap {
if world.IsBigWorld() {
for applyUid := range world.owner.CoopApplyMap {
t.gameManager.UserDealEnterWorld(world.owner, applyUid, true)
}
}
for _, player := range world.playerMap {
if world.multiplayer {
// PacketWorldPlayerLocationNotify
worldPlayerLocationNotify := new(proto.WorldPlayerLocationNotify)
for _, worldPlayer := range world.playerMap {
playerWorldLocationInfo := &proto.PlayerWorldLocationInfo{
SceneId: worldPlayer.SceneId,
PlayerLoc: &proto.PlayerLocationInfo{
Uid: worldPlayer.PlayerID,
Pos: &proto.Vector{
X: float32(worldPlayer.Pos.X),
Y: float32(worldPlayer.Pos.Y),
Z: float32(worldPlayer.Pos.Z),
},
Rot: &proto.Vector{
X: float32(worldPlayer.Rot.X),
Y: float32(worldPlayer.Rot.Y),
Z: float32(worldPlayer.Rot.Z),
},
},
}
worldPlayerLocationNotify.PlayerWorldLocList = append(worldPlayerLocationNotify.PlayerWorldLocList, playerWorldLocationInfo)
}
t.gameManager.SendMsg(proto.ApiWorldPlayerLocationNotify, player.PlayerID, 0, worldPlayerLocationNotify)
// PacketScenePlayerLocationNotify
scene := world.GetSceneById(player.SceneId)
scenePlayerLocationNotify := new(proto.ScenePlayerLocationNotify)
scenePlayerLocationNotify.SceneId = player.SceneId
for _, scenePlayer := range scene.playerMap {
playerLocationInfo := &proto.PlayerLocationInfo{
Uid: scenePlayer.PlayerID,
Pos: &proto.Vector{
X: float32(scenePlayer.Pos.X),
Y: float32(scenePlayer.Pos.Y),
Z: float32(scenePlayer.Pos.Z),
},
Rot: &proto.Vector{
X: float32(scenePlayer.Rot.X),
Y: float32(scenePlayer.Rot.Y),
Z: float32(scenePlayer.Rot.Z),
},
}
scenePlayerLocationNotify.PlayerLocList = append(scenePlayerLocationNotify.PlayerLocList, playerLocationInfo)
}
t.gameManager.SendMsg(proto.ApiScenePlayerLocationNotify, player.PlayerID, 0, scenePlayerLocationNotify)
}
}
}
}
func (t *TickManager) onTickSecond(now int64) {
for _, world := range t.gameManager.worldManager.worldMap {
for _, player := range world.playerMap {
// PacketWorldPlayerRTTNotify
worldPlayerRTTNotify := new(proto.WorldPlayerRTTNotify)
worldPlayerRTTNotify.PlayerRttList = make([]*proto.PlayerRTTInfo, 0)
for _, worldPlayer := range world.playerMap {
playerRTTInfo := &proto.PlayerRTTInfo{Uid: worldPlayer.PlayerID, Rtt: worldPlayer.ClientRTT}
worldPlayerRTTNotify.PlayerRttList = append(worldPlayerRTTNotify.PlayerRttList, playerRTTInfo)
}
t.gameManager.SendMsg(proto.ApiWorldPlayerRTTNotify, player.PlayerID, 0, worldPlayerRTTNotify)
}
}
}
func (t *TickManager) onTick100MilliSecond(now int64) {
// AttackHandler
for _, world := range t.gameManager.worldManager.worldMap {
for _, scene := range world.sceneMap {
scene.AttackHandler(t.gameManager)
}
}
bigWorldOwner := t.gameManager.userManager.GetOnlineUser(1)
bigWorld := t.gameManager.worldManager.GetBigWorld()
bigWorldScene := bigWorld.GetSceneById(3)
if len(bigWorldScene.playerMap) < 2 {
return
}
if t.gameManager.worldManager.worldStatic.aiMoveCurrIndex >= len(t.gameManager.worldManager.worldStatic.aiMoveVectorList)-1 {
return
}
t.gameManager.worldManager.worldStatic.aiMoveCurrIndex++
entityMoveInfo := new(proto.EntityMoveInfo)
activeAvatarId := bigWorldOwner.TeamConfig.GetActiveAvatarId()
playerTeamEntity := bigWorldScene.GetPlayerTeamEntity(bigWorldOwner.PlayerID)
entityMoveInfo.EntityId = playerTeamEntity.avatarEntityMap[activeAvatarId]
entityMoveInfo.SceneTime = uint32(bigWorldScene.GetSceneTime())
entityMoveInfo.ReliableSeq = uint32(bigWorldScene.GetSceneTime() / 100 * 100)
entityMoveInfo.IsReliable = true
oldPos := model.Vector{
X: bigWorldOwner.Pos.X,
Y: bigWorldOwner.Pos.Y,
Z: bigWorldOwner.Pos.Z,
}
newPos := t.gameManager.worldManager.worldStatic.aiMoveVectorList[t.gameManager.worldManager.worldStatic.aiMoveCurrIndex]
rotY := math.Atan2(newPos.X-oldPos.X, newPos.Z-oldPos.Z) / math.Pi * 180.0
if rotY < 0.0 {
rotY += 360.0
}
entityMoveInfo.MotionInfo = &proto.MotionInfo{
Pos: &proto.Vector{
X: float32(newPos.X),
Y: float32(newPos.Y),
Z: float32(newPos.Z),
},
Rot: &proto.Vector{
X: 0.0,
Y: float32(rotY),
Z: 0.0,
},
Speed: &proto.Vector{
X: float32((newPos.X - oldPos.X) * 10.0),
Y: float32((newPos.Y - oldPos.Y) * 10.0),
Z: float32((newPos.Z - oldPos.Z) * 10.0),
},
State: proto.MotionState_MOTION_STATE_RUN,
RefPos: new(proto.Vector),
}
data, err := pb.Marshal(entityMoveInfo)
if err != nil {
logger.LOG.Error("build combat invocations entity move info error: %v", err)
return
}
combatInvocationsNotify := new(proto.CombatInvocationsNotify)
combatInvocationsNotify.InvokeList = []*proto.CombatInvokeEntry{{
CombatData: data,
ForwardType: proto.ForwardType_FORWARD_TYPE_TO_ALL_EXCEPT_CUR,
ArgumentType: proto.CombatTypeArgument_COMBAT_TYPE_ARGUMENT_ENTITY_MOVE,
}}
t.gameManager.CombatInvocationsNotify(bigWorldOwner.PlayerID, bigWorldOwner, 0, combatInvocationsNotify)
}
func (t *TickManager) createMonster(scene *Scene) uint32 {
pos := &model.Vector{
X: 2747,
Y: 194,
Z: -1719,
}
fpm := map[uint32]float32{
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP): float32(72.91699),
uint32(constant.FightPropertyConst.FIGHT_PROP_PHYSICAL_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_DEFENSE): float32(505.0),
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK): float32(45.679916),
uint32(constant.FightPropertyConst.FIGHT_PROP_ICE_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_ATTACK): float32(45.679916),
uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP): float32(72.91699),
uint32(constant.FightPropertyConst.FIGHT_PROP_FIRE_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_ELEC_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_WIND_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_ROCK_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_GRASS_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_WATER_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_HP): float32(72.91699),
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_DEFENSE): float32(505.0),
}
entityId := scene.CreateEntityMonster(pos, 1, fpm)
return entityId
}

View File

@@ -0,0 +1,322 @@
package game
import (
"flswld.com/common/utils/object"
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
gdc "game-hk4e/config"
"game-hk4e/constant"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
)
func (g *GameManager) GetAllAvatarDataConfig() map[int32]*gdc.AvatarData {
allAvatarDataConfig := make(map[int32]*gdc.AvatarData)
for avatarId, avatarData := range gdc.CONF.AvatarDataMap {
if avatarId < 10000002 || avatarId >= 11000000 {
// 跳过无效角色
continue
}
if avatarId == 10000005 || avatarId == 10000007 {
// 跳过主角
continue
}
allAvatarDataConfig[avatarId] = avatarData
}
return allAvatarDataConfig
}
func (g *GameManager) AddUserAvatar(userId uint32, avatarId uint32) {
player := g.userManager.GetOnlineUser(userId)
if player == nil {
logger.LOG.Error("player is nil, userId: %v", userId)
return
}
player.AddAvatar(avatarId)
// 添加初始武器
avatarDataConfig := gdc.CONF.AvatarDataMap[int32(avatarId)]
weaponId := g.AddUserWeapon(player.PlayerID, uint32(avatarDataConfig.InitialWeapon))
// 角色装上初始武器
g.WearUserAvatarEquip(player.PlayerID, avatarId, weaponId)
// TODO 真的有必要存在吗
g.UpdateUserAvatarFightProp(player.PlayerID, avatarId)
// PacketAvatarAddNotify
avatar := player.AvatarMap[avatarId]
avatarAddNotify := new(proto.AvatarAddNotify)
avatarAddNotify.Avatar = g.PacketAvatarInfo(avatar)
avatarAddNotify.IsInTeam = false
g.SendMsg(proto.ApiAvatarAddNotify, userId, player.ClientSeq, avatarAddNotify)
}
func (g *GameManager) WearEquipReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user wear equip, user id: %v", userId)
req := payloadMsg.(*proto.WearEquipReq)
avatarGuid := req.AvatarGuid
equipGuid := req.EquipGuid
avatar := player.GameObjectGuidMap[avatarGuid].(*model.Avatar)
weapon := player.GameObjectGuidMap[equipGuid].(*model.Weapon)
g.WearUserAvatarEquip(player.PlayerID, avatar.AvatarId, weapon.WeaponId)
// PacketWearEquipRsp
wearEquipRsp := new(proto.WearEquipRsp)
wearEquipRsp.AvatarGuid = avatarGuid
wearEquipRsp.EquipGuid = equipGuid
g.SendMsg(proto.ApiWearEquipRsp, userId, player.ClientSeq, wearEquipRsp)
}
func (g *GameManager) WearUserAvatarEquip(userId uint32, avatarId uint32, weaponId uint64) {
player := g.userManager.GetOnlineUser(userId)
if player == nil {
logger.LOG.Error("player is nil, userId: %v", userId)
return
}
avatar := player.AvatarMap[avatarId]
weapon := player.WeaponMap[weaponId]
world := g.worldManager.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId)
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
team := player.TeamConfig.GetActiveTeam()
if weapon.AvatarId != 0 {
// 武器在别的角色身上
weakAvatarId := weapon.AvatarId
weakWeaponId := weaponId
strongAvatarId := avatarId
strongWeaponId := avatar.EquipWeapon.WeaponId
player.TakeOffWeapon(weakAvatarId, weakWeaponId)
player.TakeOffWeapon(strongAvatarId, strongWeaponId)
player.WearWeapon(weakAvatarId, strongWeaponId)
player.WearWeapon(strongAvatarId, weakWeaponId)
weakAvatar := player.AvatarMap[weakAvatarId]
weakWeapon := player.WeaponMap[weakAvatar.EquipWeapon.WeaponId]
for _, aid := range team.AvatarIdList {
if aid == 0 {
break
}
if aid == weakAvatar.AvatarId {
playerTeamEntity.weaponEntityMap[weakWeapon.WeaponId] = scene.CreateEntityWeapon()
}
}
// PacketAvatarEquipChangeNotify
avatarEquipChangeNotify := g.PacketAvatarEquipChangeNotify(weakAvatar, weakWeapon, playerTeamEntity.weaponEntityMap[weakWeapon.WeaponId])
g.SendMsg(proto.ApiAvatarEquipChangeNotify, userId, player.ClientSeq, avatarEquipChangeNotify)
} else if avatar.EquipWeapon != nil {
// 角色当前有武器
player.TakeOffWeapon(avatarId, avatar.EquipWeapon.WeaponId)
player.WearWeapon(avatarId, weaponId)
} else {
// 是新角色还没有武器
player.WearWeapon(avatarId, weaponId)
}
for _, aid := range team.AvatarIdList {
if aid == 0 {
break
}
if aid == avatarId {
playerTeamEntity.weaponEntityMap[weaponId] = scene.CreateEntityWeapon()
}
}
// PacketAvatarEquipChangeNotify
avatarEquipChangeNotify := g.PacketAvatarEquipChangeNotify(avatar, weapon, playerTeamEntity.weaponEntityMap[weaponId])
g.SendMsg(proto.ApiAvatarEquipChangeNotify, userId, player.ClientSeq, avatarEquipChangeNotify)
}
func (g *GameManager) AvatarChangeCostumeReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user change avatar costume, user id: %v", userId)
req := payloadMsg.(*proto.AvatarChangeCostumeReq)
avatarGuid := req.AvatarGuid
costumeId := req.CostumeId
exist := false
for _, v := range player.CostumeList {
if v == costumeId {
exist = true
}
}
if costumeId == 0 {
exist = true
}
if !exist {
return
}
avatar := player.GameObjectGuidMap[avatarGuid].(*model.Avatar)
avatar.Costume = req.CostumeId
world := g.worldManager.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId)
// PacketAvatarChangeCostumeNotify
avatarChangeCostumeNotify := new(proto.AvatarChangeCostumeNotify)
avatarChangeCostumeNotify.EntityInfo = g.PacketSceneEntityInfoAvatar(scene, player, avatar.AvatarId)
for _, scenePlayer := range scene.playerMap {
g.SendMsg(proto.ApiAvatarChangeCostumeNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, avatarChangeCostumeNotify)
}
// PacketAvatarChangeCostumeRsp
avatarChangeCostumeRsp := new(proto.AvatarChangeCostumeRsp)
avatarChangeCostumeRsp.AvatarGuid = req.AvatarGuid
avatarChangeCostumeRsp.CostumeId = req.CostumeId
g.SendMsg(proto.ApiAvatarChangeCostumeRsp, userId, player.ClientSeq, avatarChangeCostumeRsp)
}
func (g *GameManager) AvatarWearFlycloakReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user change avatar fly cloak, user id: %v", userId)
req := payloadMsg.(*proto.AvatarWearFlycloakReq)
avatarGuid := req.AvatarGuid
flycloakId := req.FlycloakId
exist := false
for _, v := range player.FlyCloakList {
if v == flycloakId {
exist = true
}
}
if !exist {
return
}
avatar := player.GameObjectGuidMap[avatarGuid].(*model.Avatar)
avatar.FlyCloak = req.FlycloakId
world := g.worldManager.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId)
// PacketAvatarFlycloakChangeNotify
avatarFlycloakChangeNotify := new(proto.AvatarFlycloakChangeNotify)
avatarFlycloakChangeNotify.AvatarGuid = avatarGuid
avatarFlycloakChangeNotify.FlycloakId = flycloakId
for _, scenePlayer := range scene.playerMap {
g.SendMsg(proto.ApiAvatarFlycloakChangeNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, avatarFlycloakChangeNotify)
}
// PacketAvatarWearFlycloakRsp
avatarWearFlycloakRsp := new(proto.AvatarWearFlycloakRsp)
avatarWearFlycloakRsp.AvatarGuid = req.AvatarGuid
avatarWearFlycloakRsp.FlycloakId = req.FlycloakId
g.SendMsg(proto.ApiAvatarWearFlycloakRsp, userId, player.ClientSeq, avatarWearFlycloakRsp)
}
func (g *GameManager) PacketAvatarEquipChangeNotify(avatar *model.Avatar, weapon *model.Weapon, entityId uint32) *proto.AvatarEquipChangeNotify {
itemDataConfig := gdc.CONF.ItemDataMap[int32(weapon.ItemId)]
avatarEquipChangeNotify := new(proto.AvatarEquipChangeNotify)
avatarEquipChangeNotify.AvatarGuid = avatar.Guid
avatarEquipChangeNotify.EquipType = uint32(itemDataConfig.EquipEnumType)
avatarEquipChangeNotify.ItemId = weapon.ItemId
avatarEquipChangeNotify.EquipGuid = weapon.Guid
avatarEquipChangeNotify.Weapon = &proto.SceneWeaponInfo{
EntityId: entityId,
GadgetId: uint32(gdc.CONF.ItemDataMap[int32(weapon.ItemId)].GadgetId),
ItemId: weapon.ItemId,
Guid: weapon.Guid,
Level: uint32(weapon.Level),
AbilityInfo: new(proto.AbilitySyncStateInfo),
}
return avatarEquipChangeNotify
}
func (g *GameManager) PacketAvatarEquipTakeOffNotify(avatar *model.Avatar, weapon *model.Weapon) *proto.AvatarEquipChangeNotify {
itemDataConfig := gdc.CONF.ItemDataMap[int32(weapon.ItemId)]
avatarEquipChangeNotify := new(proto.AvatarEquipChangeNotify)
avatarEquipChangeNotify.AvatarGuid = avatar.Guid
avatarEquipChangeNotify.EquipType = uint32(itemDataConfig.EquipEnumType)
return avatarEquipChangeNotify
}
func (g *GameManager) UpdateUserAvatarFightProp(userId uint32, avatarId uint32) {
player := g.userManager.GetOnlineUser(userId)
if player == nil {
logger.LOG.Error("player is nil, userId: %v", userId)
return
}
avatarFightPropNotify := new(proto.AvatarFightPropNotify)
avatar := player.AvatarMap[avatarId]
avatarFightPropNotify.AvatarGuid = avatar.Guid
avatarFightPropNotify.FightPropMap = avatar.FightPropMap
g.SendMsg(proto.ApiAvatarFightPropNotify, userId, player.ClientSeq, avatarFightPropNotify)
}
func (g *GameManager) PacketAvatarInfo(avatar *model.Avatar) *proto.AvatarInfo {
isFocus := false
//if avatar.AvatarId == 10000005 || avatar.AvatarId == 10000007 {
// isFocus = true
//}
pbAvatar := &proto.AvatarInfo{
IsFocus: isFocus,
AvatarId: avatar.AvatarId,
Guid: avatar.Guid,
PropMap: map[uint32]*proto.PropValue{
uint32(constant.PlayerPropertyConst.PROP_LEVEL): {
Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL),
Val: int64(avatar.Level),
Value: &proto.PropValue_Ival{Ival: int64(avatar.Level)},
},
uint32(constant.PlayerPropertyConst.PROP_EXP): {
Type: uint32(constant.PlayerPropertyConst.PROP_EXP),
Val: int64(avatar.Exp),
Value: &proto.PropValue_Ival{Ival: int64(avatar.Exp)},
},
uint32(constant.PlayerPropertyConst.PROP_BREAK_LEVEL): {
Type: uint32(constant.PlayerPropertyConst.PROP_BREAK_LEVEL),
Val: int64(avatar.Promote),
Value: &proto.PropValue_Ival{Ival: int64(avatar.Promote)},
},
uint32(constant.PlayerPropertyConst.PROP_SATIATION_VAL): {
Type: uint32(constant.PlayerPropertyConst.PROP_SATIATION_VAL),
Val: 0,
Value: &proto.PropValue_Ival{Ival: 0},
},
uint32(constant.PlayerPropertyConst.PROP_SATIATION_PENALTY_TIME): {
Type: uint32(constant.PlayerPropertyConst.PROP_SATIATION_PENALTY_TIME),
Val: 0,
Value: &proto.PropValue_Ival{Ival: 0},
},
},
LifeState: 1,
EquipGuidList: object.ConvMapToList(avatar.EquipGuidList),
FightPropMap: nil,
SkillDepotId: avatar.SkillDepotId,
FetterInfo: &proto.AvatarFetterInfo{
ExpLevel: uint32(avatar.FetterLevel),
ExpNumber: avatar.FetterExp,
// FetterList 不知道是啥 该角色在配置表里的所有FetterId
// TODO 资料解锁条目
FetterList: nil,
RewardedFetterLevelList: []uint32{10},
},
SkillLevelMap: nil,
AvatarType: 1,
WearingFlycloakId: avatar.FlyCloak,
CostumeId: avatar.Costume,
BornTime: uint32(avatar.BornTime),
}
pbAvatar.FightPropMap = avatar.FightPropMap
for _, v := range avatar.FetterList {
pbAvatar.FetterInfo.FetterList = append(pbAvatar.FetterInfo.FetterList, &proto.FetterData{
FetterId: v,
FetterState: uint32(constant.FetterStateConst.FINISH),
})
}
// 解锁全部资料
for _, v := range gdc.CONF.AvatarFetterDataMap[int32(avatar.AvatarId)] {
pbAvatar.FetterInfo.FetterList = append(pbAvatar.FetterInfo.FetterList, &proto.FetterData{
FetterId: uint32(v),
FetterState: uint32(constant.FetterStateConst.FINISH),
})
}
pbAvatar.SkillLevelMap = make(map[uint32]uint32)
for k, v := range avatar.SkillLevelMap {
pbAvatar.SkillLevelMap[k] = v
}
return pbAvatar
}

View File

@@ -0,0 +1,254 @@
package game
import (
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
"time"
)
func (g *GameManager) PullRecentChatReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user pull recent chat, user id: %v", userId)
req := payloadMsg.(*proto.PullRecentChatReq)
// 经研究发现 原神现网环境 客户端仅拉取最新的5条未读聊天消息 所以人太多的话小姐姐不回你消息是有原因的
// 因此 阿米你这样做真的合适吗 不过现在代码到了我手上我想怎么写就怎么写 我才不会重蹈覆辙
_ = req.PullNum
retMsgList := make([]*proto.ChatInfo, 0)
for _, msgList := range player.ChatMsgMap {
for _, chatMsg := range msgList {
// 反手就是一个遍历
if chatMsg.IsRead {
continue
}
retMsgList = append(retMsgList, g.ConvChatMsgToChatInfo(chatMsg))
}
}
world := g.worldManager.GetWorldByID(player.WorldId)
if world.multiplayer {
chatList := world.GetChatList()
count := len(chatList)
if count > 10 {
count = 10
}
for i := len(chatList) - count; i < len(chatList); i++ {
// PacketPlayerChatNotify
playerChatNotify := new(proto.PlayerChatNotify)
playerChatNotify.ChannelId = 0
playerChatNotify.ChatInfo = chatList[i]
g.SendMsg(proto.ApiPlayerChatNotify, player.PlayerID, 0, playerChatNotify)
}
}
// PacketPullRecentChatRsp
pullRecentChatRsp := new(proto.PullRecentChatRsp)
pullRecentChatRsp.ChatInfo = retMsgList
g.SendMsg(proto.ApiPullRecentChatRsp, player.PlayerID, 0, pullRecentChatRsp)
}
func (g *GameManager) PullPrivateChatReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user pull private chat, user id: %v", userId)
req := payloadMsg.(*proto.PullPrivateChatReq)
targetUid := req.TargetUid
pullNum := req.PullNum
fromSequence := req.FromSequence
msgList, exist := player.ChatMsgMap[targetUid]
if !exist {
return
}
if pullNum+fromSequence > uint32(len(msgList)) {
pullNum = uint32(len(msgList)) - fromSequence
}
recentMsgList := msgList[fromSequence : fromSequence+pullNum]
retMsgList := make([]*proto.ChatInfo, 0)
for _, chatMsg := range recentMsgList {
retMsgList = append(retMsgList, g.ConvChatMsgToChatInfo(chatMsg))
}
// PacketPullPrivateChatRsp
pullPrivateChatRsp := new(proto.PullPrivateChatRsp)
pullPrivateChatRsp.ChatInfo = retMsgList
g.SendMsg(proto.ApiPullPrivateChatRsp, player.PlayerID, 0, pullPrivateChatRsp)
}
func (g *GameManager) PrivateChatReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user send private chat, user id: %v", userId)
req := payloadMsg.(*proto.PrivateChatReq)
targetUid := req.TargetUid
content := req.Content
// TODO 同步阻塞待优化
targetPlayer := g.userManager.LoadTempOfflineUserSync(targetUid)
if targetPlayer == nil {
return
}
chatInfo := &proto.ChatInfo{
Time: uint32(time.Now().Unix()),
Sequence: 101,
ToUid: targetPlayer.PlayerID,
Uid: player.PlayerID,
IsRead: false,
Content: nil,
}
switch content.(type) {
case *proto.PrivateChatReq_Text:
text := content.(*proto.PrivateChatReq_Text).Text
if len(text) == 0 {
return
}
chatInfo.Content = &proto.ChatInfo_Text{
Text: text,
}
case *proto.PrivateChatReq_Icon:
icon := content.(*proto.PrivateChatReq_Icon).Icon
chatInfo.Content = &proto.ChatInfo_Icon{
Icon: icon,
}
default:
return
}
// 消息加入自己的队列
msgList, exist := player.ChatMsgMap[targetPlayer.PlayerID]
if !exist {
msgList = make([]*model.ChatMsg, 0)
}
msgList = append(msgList, g.ConvChatInfoToChatMsg(chatInfo))
player.ChatMsgMap[targetPlayer.PlayerID] = msgList
// 消息加入目标玩家的队列
msgList, exist = targetPlayer.ChatMsgMap[player.PlayerID]
if !exist {
msgList = make([]*model.ChatMsg, 0)
}
msgList = append(msgList, g.ConvChatInfoToChatMsg(chatInfo))
targetPlayer.ChatMsgMap[player.PlayerID] = msgList
if targetPlayer.Online {
// PacketPrivateChatNotify
privateChatNotify := new(proto.PrivateChatNotify)
privateChatNotify.ChatInfo = chatInfo
g.SendMsg(proto.ApiPrivateChatNotify, targetPlayer.PlayerID, 0, privateChatNotify)
}
// PacketPrivateChatNotify
privateChatNotify := new(proto.PrivateChatNotify)
privateChatNotify.ChatInfo = chatInfo
g.SendMsg(proto.ApiPrivateChatNotify, player.PlayerID, 0, privateChatNotify)
// PacketPrivateChatRsp
privateChatRsp := new(proto.PrivateChatRsp)
g.SendMsg(proto.ApiPrivateChatRsp, player.PlayerID, 0, privateChatRsp)
}
func (g *GameManager) ReadPrivateChatReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user read private chat, user id: %v", userId)
req := payloadMsg.(*proto.ReadPrivateChatReq)
targetUid := req.TargetUid
msgList, exist := player.ChatMsgMap[targetUid]
if !exist {
return
}
for index, chatMsg := range msgList {
chatMsg.IsRead = true
msgList[index] = chatMsg
}
player.ChatMsgMap[targetUid] = msgList
// PacketReadPrivateChatRsp
readPrivateChatRsp := new(proto.ReadPrivateChatRsp)
g.SendMsg(proto.ApiReadPrivateChatRsp, player.PlayerID, 0, readPrivateChatRsp)
}
func (g *GameManager) PlayerChatReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user multiplayer chat, user id: %v", userId)
req := payloadMsg.(*proto.PlayerChatReq)
channelId := req.ChannelId
chatInfo := req.ChatInfo
sendChatInfo := &proto.ChatInfo{
Time: uint32(time.Now().Unix()),
Uid: player.PlayerID,
Content: nil,
}
switch chatInfo.Content.(type) {
case *proto.ChatInfo_Text:
text := chatInfo.Content.(*proto.ChatInfo_Text).Text
if len(text) == 0 {
return
}
sendChatInfo.Content = &proto.ChatInfo_Text{
Text: text,
}
case *proto.ChatInfo_Icon:
icon := chatInfo.Content.(*proto.ChatInfo_Icon).Icon
sendChatInfo.Content = &proto.ChatInfo_Icon{
Icon: icon,
}
default:
return
}
world := g.worldManager.GetWorldByID(player.WorldId)
world.AddChat(sendChatInfo)
// PacketPlayerChatNotify
playerChatNotify := new(proto.PlayerChatNotify)
playerChatNotify.ChannelId = channelId
playerChatNotify.ChatInfo = sendChatInfo
for _, worldPlayer := range world.playerMap {
g.SendMsg(proto.ApiPlayerChatNotify, worldPlayer.PlayerID, 0, playerChatNotify)
}
// PacketPlayerChatRsp
playerChatRsp := new(proto.PlayerChatRsp)
g.SendMsg(proto.ApiPlayerChatRsp, player.PlayerID, 0, playerChatRsp)
}
func (g *GameManager) ConvChatInfoToChatMsg(chatInfo *proto.ChatInfo) (chatMsg *model.ChatMsg) {
chatMsg = &model.ChatMsg{
Time: chatInfo.Time,
ToUid: chatInfo.ToUid,
Uid: chatInfo.Uid,
IsRead: chatInfo.IsRead,
MsgType: 0,
Text: "",
Icon: 0,
}
switch chatInfo.Content.(type) {
case *proto.ChatInfo_Text:
chatMsg.MsgType = model.ChatMsgTypeText
chatMsg.Text = chatInfo.Content.(*proto.ChatInfo_Text).Text
case *proto.ChatInfo_Icon:
chatMsg.MsgType = model.ChatMsgTypeIcon
chatMsg.Icon = chatInfo.Content.(*proto.ChatInfo_Icon).Icon
default:
}
return chatMsg
}
func (g *GameManager) ConvChatMsgToChatInfo(chatMsg *model.ChatMsg) (chatInfo *proto.ChatInfo) {
chatInfo = &proto.ChatInfo{
Time: chatMsg.Time,
Sequence: 0,
ToUid: chatMsg.ToUid,
Uid: chatMsg.Uid,
IsRead: chatMsg.IsRead,
Content: nil,
}
switch chatMsg.MsgType {
case model.ChatMsgTypeText:
chatInfo.Content = &proto.ChatInfo_Text{
Text: chatMsg.Text,
}
case model.ChatMsgTypeIcon:
chatInfo.Content = &proto.ChatInfo_Icon{
Icon: chatMsg.Icon,
}
default:
}
return chatInfo
}

View File

@@ -0,0 +1,402 @@
package game
import (
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
)
func (g *GameManager) CombatInvocationsNotify(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
//logger.LOG.Debug("user combat invocations, user id: %v", userId)
req := payloadMsg.(*proto.CombatInvocationsNotify)
world := g.worldManager.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
invokeHandler := NewInvokeHandler[proto.CombatInvokeEntry]()
for _, entry := range req.InvokeList {
//logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID)
switch entry.ArgumentType {
case proto.CombatTypeArgument_COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT:
scene.AddAttack(&Attack{
combatInvokeEntry: entry,
uid: player.PlayerID,
})
case proto.CombatTypeArgument_COMBAT_TYPE_ARGUMENT_ENTITY_MOVE:
entityMoveInfo := new(proto.EntityMoveInfo)
err := pb.Unmarshal(entry.CombatData, entityMoveInfo)
if err != nil {
logger.LOG.Error("parse combat invocations entity move info error: %v", err)
continue
}
motionInfo := entityMoveInfo.MotionInfo
if motionInfo.Pos == nil || motionInfo.Rot == nil {
continue
}
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
playerActiveAvatarEntityId := playerTeamEntity.avatarEntityMap[activeAvatarId]
if entityMoveInfo.EntityId == playerActiveAvatarEntityId {
// 玩家在移动
ok := world.aoiManager.IsValidAoiPos(motionInfo.Pos.X, motionInfo.Pos.Y, motionInfo.Pos.Z)
if !ok {
continue
}
// aoi
oldGid := world.aoiManager.GetGidByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
newGid := world.aoiManager.GetGidByPos(motionInfo.Pos.X, motionInfo.Pos.Y, motionInfo.Pos.Z)
if oldGid != newGid {
// 跨越了格子
oldGridList := world.aoiManager.GetSurrGridListByGid(oldGid)
oldEntityIdMap := make(map[uint32]bool)
for _, grid := range oldGridList {
tmp := grid.GetEntityIdList()
for _, v := range tmp {
oldEntityIdMap[v] = true
}
}
newGridList := world.aoiManager.GetSurrGridListByGid(newGid)
newEntityIdMap := make(map[uint32]bool)
for _, grid := range newGridList {
tmp := grid.GetEntityIdList()
for _, v := range tmp {
newEntityIdMap[v] = true
}
}
delEntityIdList := make([]uint32, 0)
delUidList := make([]uint32, 0)
for oldEntityId := range oldEntityIdMap {
_, exist := newEntityIdMap[oldEntityId]
if exist {
continue
}
delEntityIdList = append(delEntityIdList, oldEntityId)
entity := scene.GetEntity(oldEntityId)
if entity == nil {
continue
}
if entity.avatarEntity != nil {
delUidList = append(delUidList, entity.avatarEntity.uid)
}
}
addEntityIdList := make([]uint32, 0)
addUidList := make([]uint32, 0)
for newEntityId := range newEntityIdMap {
_, exist := oldEntityIdMap[newEntityId]
if exist {
continue
}
addEntityIdList = append(addEntityIdList, newEntityId)
entity := scene.GetEntity(newEntityId)
if entity == nil {
continue
}
if entity.avatarEntity != nil {
addUidList = append(addUidList, entity.avatarEntity.uid)
}
}
// 发送已消失格子里的实体消失通知
g.RemoveSceneEntityNotifyToPlayer(player, delEntityIdList)
// 发送新出现格子里的实体出现通知
g.AddSceneEntityNotify(player, proto.VisionType_VISION_TYPE_BORN, addEntityIdList, false)
// 更新玩家的位置信息
player.Pos.X = float64(motionInfo.Pos.X)
player.Pos.Y = float64(motionInfo.Pos.Y)
player.Pos.Z = float64(motionInfo.Pos.Z)
// 更新玩家所在格子
world.aoiManager.RemoveEntityIdFromGrid(playerActiveAvatarEntityId, oldGid)
world.aoiManager.AddEntityIdToGrid(playerActiveAvatarEntityId, newGid)
// 其他玩家
for _, uid := range delUidList {
otherPlayer := g.userManager.GetOnlineUser(uid)
g.RemoveSceneEntityNotifyToPlayer(otherPlayer, []uint32{playerActiveAvatarEntityId})
}
for _, uid := range addUidList {
otherPlayer := g.userManager.GetOnlineUser(uid)
g.AddSceneEntityNotify(otherPlayer, proto.VisionType_VISION_TYPE_BORN, []uint32{playerActiveAvatarEntityId}, false)
}
}
// 把队伍中的其他非活跃角色也同步进行移动
team := player.TeamConfig.GetActiveTeam()
for _, avatarId := range team.AvatarIdList {
// 跳过当前的活跃角色
if avatarId == activeAvatarId {
continue
}
entityId := playerTeamEntity.avatarEntityMap[avatarId]
entity := scene.GetEntity(entityId)
if entity == nil {
continue
}
entity.pos.X = float64(motionInfo.Pos.X)
entity.pos.Y = float64(motionInfo.Pos.Y)
entity.pos.Z = float64(motionInfo.Pos.Z)
entity.rot.X = float64(motionInfo.Rot.X)
entity.rot.Y = float64(motionInfo.Rot.Y)
entity.rot.Z = float64(motionInfo.Rot.Z)
}
// 更新玩家的位置信息
player.Pos.X = float64(motionInfo.Pos.X)
player.Pos.Y = float64(motionInfo.Pos.Y)
player.Pos.Z = float64(motionInfo.Pos.Z)
player.Rot.X = float64(motionInfo.Rot.X)
player.Rot.Y = float64(motionInfo.Rot.Y)
player.Rot.Z = float64(motionInfo.Rot.Z)
// TODO 采集大地图地形数据
if world.IsBigWorld() && scene.id == 3 && player.PlayerID != 1 {
if motionInfo.State == proto.MotionState_MOTION_STATE_WALK ||
motionInfo.State == proto.MotionState_MOTION_STATE_RUN ||
motionInfo.State == proto.MotionState_MOTION_STATE_DASH ||
motionInfo.State == proto.MotionState_MOTION_STATE_CLIMB {
logger.LOG.Debug("set terr motionInfo: %v", motionInfo)
exist := g.worldManager.worldStatic.GetTerrain(int16(motionInfo.Pos.X), int16(motionInfo.Pos.Y), int16(motionInfo.Pos.Z))
g.worldManager.worldStatic.SetTerrain(int16(motionInfo.Pos.X), int16(motionInfo.Pos.Y), int16(motionInfo.Pos.Z))
if !exist {
// TODO 薄荷标记
// 只给附近aoi区域的玩家广播消息
surrPlayerList := make([]*model.Player, 0)
entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
for _, entityId := range entityIdList {
entity := scene.GetEntity(entityId)
if entity == nil {
continue
}
if entity.avatarEntity != nil {
otherPlayer := g.userManager.GetOnlineUser(entity.avatarEntity.uid)
surrPlayerList = append(surrPlayerList, otherPlayer)
}
}
pos := &model.Vector{
X: float64(int16(motionInfo.Pos.X)),
Y: float64(int16(motionInfo.Pos.Y)),
Z: float64(int16(motionInfo.Pos.Z)),
}
gadgetEntityId := scene.CreateEntityGadget(pos, 3003009)
for _, otherPlayer := range surrPlayerList {
g.AddSceneEntityNotify(otherPlayer, proto.VisionType_VISION_TYPE_BORN, []uint32{gadgetEntityId}, false)
}
}
}
}
}
// 更新场景实体的位置信息
sceneEntity := scene.GetEntity(entityMoveInfo.EntityId)
if sceneEntity != nil {
sceneEntity.pos = &model.Vector{
X: float64(motionInfo.Pos.X),
Y: float64(motionInfo.Pos.Y),
Z: float64(motionInfo.Pos.Z),
}
sceneEntity.rot = &model.Vector{
X: float64(motionInfo.Rot.X),
Y: float64(motionInfo.Rot.Y),
Z: float64(motionInfo.Rot.Z),
}
sceneEntity.moveState = uint16(motionInfo.State)
sceneEntity.lastMoveSceneTimeMs = entityMoveInfo.SceneTime
sceneEntity.lastMoveReliableSeq = entityMoveInfo.ReliableSeq
//logger.LOG.Debug("entity move, id: %v, pos: %v, uid: %v", sceneEntity.id, sceneEntity.pos, player.PlayerID)
}
invokeHandler.addEntry(entry.ForwardType, entry)
default:
invokeHandler.addEntry(entry.ForwardType, entry)
}
}
// 只给附近aoi区域的玩家广播消息
surrPlayerList := make([]*model.Player, 0)
entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
for _, entityId := range entityIdList {
entity := scene.GetEntity(entityId)
if entity == nil {
continue
}
if entity.avatarEntity != nil {
otherPlayer := g.userManager.GetOnlineUser(entity.avatarEntity.uid)
surrPlayerList = append(surrPlayerList, otherPlayer)
}
}
// PacketCombatInvocationsNotify
if invokeHandler.AllLen() > 0 {
combatInvocationsNotify := new(proto.CombatInvocationsNotify)
combatInvocationsNotify.InvokeList = invokeHandler.entryListForwardAll
for _, v := range surrPlayerList {
g.SendMsg(proto.ApiCombatInvocationsNotify, v.PlayerID, v.ClientSeq, combatInvocationsNotify)
}
}
if invokeHandler.AllExceptCurLen() > 0 {
combatInvocationsNotify := new(proto.CombatInvocationsNotify)
combatInvocationsNotify.InvokeList = invokeHandler.entryListForwardAllExceptCur
for _, v := range surrPlayerList {
if player.PlayerID == v.PlayerID {
continue
}
g.SendMsg(proto.ApiCombatInvocationsNotify, v.PlayerID, v.ClientSeq, combatInvocationsNotify)
}
}
if invokeHandler.HostLen() > 0 {
combatInvocationsNotify := new(proto.CombatInvocationsNotify)
combatInvocationsNotify.InvokeList = invokeHandler.entryListForwardHost
g.SendMsg(proto.ApiCombatInvocationsNotify, world.owner.PlayerID, world.owner.ClientSeq, combatInvocationsNotify)
}
}
func (g *GameManager) AbilityInvocationsNotify(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
//logger.LOG.Debug("user ability invocations, user id: %v", userId)
req := payloadMsg.(*proto.AbilityInvocationsNotify)
world := g.worldManager.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
invokeHandler := NewInvokeHandler[proto.AbilityInvokeEntry]()
for _, entry := range req.Invokes {
//logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID)
invokeHandler.addEntry(entry.ForwardType, entry)
}
// 只给附近aoi区域的玩家广播消息
surrPlayerList := make([]*model.Player, 0)
entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
for _, entityId := range entityIdList {
entity := scene.GetEntity(entityId)
if entity == nil {
continue
}
if entity.avatarEntity != nil {
otherPlayer := g.userManager.GetOnlineUser(entity.avatarEntity.uid)
surrPlayerList = append(surrPlayerList, otherPlayer)
}
}
// PacketAbilityInvocationsNotify
if invokeHandler.AllLen() > 0 {
abilityInvocationsNotify := new(proto.AbilityInvocationsNotify)
abilityInvocationsNotify.Invokes = invokeHandler.entryListForwardAll
for _, v := range surrPlayerList {
g.SendMsg(proto.ApiAbilityInvocationsNotify, v.PlayerID, v.ClientSeq, abilityInvocationsNotify)
}
}
if invokeHandler.AllExceptCurLen() > 0 {
abilityInvocationsNotify := new(proto.AbilityInvocationsNotify)
abilityInvocationsNotify.Invokes = invokeHandler.entryListForwardAllExceptCur
for _, v := range surrPlayerList {
if player.PlayerID == v.PlayerID {
continue
}
g.SendMsg(proto.ApiAbilityInvocationsNotify, v.PlayerID, v.ClientSeq, abilityInvocationsNotify)
}
}
if invokeHandler.HostLen() > 0 {
abilityInvocationsNotify := new(proto.AbilityInvocationsNotify)
abilityInvocationsNotify.Invokes = invokeHandler.entryListForwardHost
g.SendMsg(proto.ApiAbilityInvocationsNotify, world.owner.PlayerID, world.owner.ClientSeq, abilityInvocationsNotify)
}
}
func (g *GameManager) ClientAbilityInitFinishNotify(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
//logger.LOG.Debug("user client ability ok, user id: %v", userId)
req := payloadMsg.(*proto.ClientAbilityInitFinishNotify)
world := g.worldManager.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
invokeHandler := NewInvokeHandler[proto.AbilityInvokeEntry]()
for _, entry := range req.Invokes {
//logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID)
invokeHandler.addEntry(entry.ForwardType, entry)
}
// 只给附近aoi区域的玩家广播消息
surrPlayerList := make([]*model.Player, 0)
entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
for _, entityId := range entityIdList {
entity := scene.GetEntity(entityId)
if entity == nil {
continue
}
if entity.avatarEntity != nil {
otherPlayer := g.userManager.GetOnlineUser(entity.avatarEntity.uid)
surrPlayerList = append(surrPlayerList, otherPlayer)
}
}
// PacketClientAbilityInitFinishNotify
if invokeHandler.AllLen() > 0 {
clientAbilityInitFinishNotify := new(proto.ClientAbilityInitFinishNotify)
clientAbilityInitFinishNotify.Invokes = invokeHandler.entryListForwardAll
for _, v := range surrPlayerList {
g.SendMsg(proto.ApiClientAbilityInitFinishNotify, v.PlayerID, v.ClientSeq, clientAbilityInitFinishNotify)
}
}
if invokeHandler.AllExceptCurLen() > 0 {
clientAbilityInitFinishNotify := new(proto.ClientAbilityInitFinishNotify)
clientAbilityInitFinishNotify.Invokes = invokeHandler.entryListForwardAllExceptCur
for _, v := range surrPlayerList {
if player.PlayerID == v.PlayerID {
continue
}
g.SendMsg(proto.ApiClientAbilityInitFinishNotify, v.PlayerID, v.ClientSeq, clientAbilityInitFinishNotify)
}
}
if invokeHandler.HostLen() > 0 {
clientAbilityInitFinishNotify := new(proto.ClientAbilityInitFinishNotify)
clientAbilityInitFinishNotify.Invokes = invokeHandler.entryListForwardHost
g.SendMsg(proto.ApiClientAbilityInitFinishNotify, world.owner.PlayerID, world.owner.ClientSeq, clientAbilityInitFinishNotify)
}
}
type InvokeType interface {
proto.AbilityInvokeEntry | proto.CombatInvokeEntry
}
type InvokeHandler[T InvokeType] struct {
entryListForwardAll []*T
entryListForwardAllExceptCur []*T
entryListForwardHost []*T
}
func NewInvokeHandler[T InvokeType]() (r *InvokeHandler[T]) {
r = new(InvokeHandler[T])
r.InitInvokeHandler()
return r
}
func (i *InvokeHandler[T]) InitInvokeHandler() {
i.entryListForwardAll = make([]*T, 0)
i.entryListForwardAllExceptCur = make([]*T, 0)
i.entryListForwardHost = make([]*T, 0)
}
func (i *InvokeHandler[T]) addEntry(forward proto.ForwardType, entry *T) {
switch forward {
case proto.ForwardType_FORWARD_TYPE_TO_ALL:
i.entryListForwardAll = append(i.entryListForwardAll, entry)
case proto.ForwardType_FORWARD_TYPE_TO_ALL_EXCEPT_CUR:
fallthrough
case proto.ForwardType_FORWARD_TYPE_TO_ALL_EXIST_EXCEPT_CUR:
i.entryListForwardAllExceptCur = append(i.entryListForwardAllExceptCur, entry)
case proto.ForwardType_FORWARD_TYPE_TO_HOST:
i.entryListForwardHost = append(i.entryListForwardHost, entry)
default:
if forward != proto.ForwardType_FORWARD_TYPE_ONLY_SERVER {
logger.LOG.Error("forward: %v, entry: %v", forward, entry)
}
}
}
func (i *InvokeHandler[T]) AllLen() int {
return len(i.entryListForwardAll)
}
func (i *InvokeHandler[T]) AllExceptCurLen() int {
return len(i.entryListForwardAllExceptCur)
}
func (i *InvokeHandler[T]) HostLen() int {
return len(i.entryListForwardHost)
}

View File

@@ -0,0 +1,610 @@
package game
import (
"flswld.com/common/config"
"flswld.com/common/utils/random"
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
gdc "game-hk4e/config"
"game-hk4e/model"
"github.com/golang-jwt/jwt/v4"
pb "google.golang.org/protobuf/proto"
"time"
)
type UserInfo struct {
UserId uint32 `json:"userId"`
jwt.RegisteredClaims
}
// 获取卡池信息
func (g *GameManager) GetGachaInfoReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get gacha info, userId: %v", userId)
serverAddr := config.CONF.Hk4e.GachaHistoryServer
getGachaInfoRsp := new(proto.GetGachaInfoRsp)
getGachaInfoRsp.GachaRandom = 12345
userInfo := &UserInfo{
UserId: userId,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour * time.Duration(1))),
IssuedAt: jwt.NewNumericDate(time.Now()),
NotBefore: jwt.NewNumericDate(time.Now()),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS512, userInfo)
jwtStr, err := token.SignedString([]byte("flswld"))
if err != nil {
logger.LOG.Error("generate jwt error: %v", err)
jwtStr = "default.jwt.token"
}
getGachaInfoRsp.GachaInfoList = []*proto.GachaInfo{
// 温迪
{
GachaType: 300,
ScheduleId: 823,
BeginTime: 0,
EndTime: 2051193600,
GachaSortId: 9998,
GachaPrefabPath: "GachaShowPanel_A019",
GachaPreviewPrefabPath: "UI_Tab_GachaShowPanel_A019",
TitleTextmap: "UI_GACHA_SHOW_PANEL_A019_TITLE",
LeftGachaTimes: 2147483647,
GachaTimesLimit: 2147483647,
CostItemId: 223,
CostItemNum: 1,
TenCostItemId: 223,
TenCostItemNum: 10,
GachaRecordUrl: serverAddr + "/gm/gacha?gachaType=300&jwt=" + jwtStr,
GachaRecordUrlOversea: serverAddr + "/gm/gacha?gachaType=300&jwt=" + jwtStr,
GachaProbUrl: serverAddr + "/gm/gacha/details?scheduleId=823&jwt=" + jwtStr,
GachaProbUrlOversea: serverAddr + "/gm/gacha/details?scheduleId=823&jwt=" + jwtStr,
GachaUpInfoList: []*proto.GachaUpInfo{
{
ItemParentType: 1,
ItemIdList: []uint32{1022},
},
{
ItemParentType: 2,
ItemIdList: []uint32{1023, 1031, 1014},
},
},
DisplayUp4ItemList: []uint32{1023},
DisplayUp5ItemList: []uint32{1022},
WishItemId: 0,
WishProgress: 0,
WishMaxProgress: 0,
IsNewWish: false,
},
// 可莉
{
GachaType: 400,
ScheduleId: 833,
BeginTime: 0,
EndTime: 2051193600,
GachaSortId: 9998,
GachaPrefabPath: "GachaShowPanel_A018",
GachaPreviewPrefabPath: "UI_Tab_GachaShowPanel_A018",
TitleTextmap: "UI_GACHA_SHOW_PANEL_A018_TITLE",
LeftGachaTimes: 2147483647,
GachaTimesLimit: 2147483647,
CostItemId: 223,
CostItemNum: 1,
TenCostItemId: 223,
TenCostItemNum: 10,
GachaRecordUrl: serverAddr + "/gm/gacha?gachaType=400&jwt=" + jwtStr,
GachaRecordUrlOversea: serverAddr + "/gm/gacha?gachaType=400&jwt=" + jwtStr,
GachaProbUrl: serverAddr + "/gm/gacha/details?scheduleId=833&jwt=" + jwtStr,
GachaProbUrlOversea: serverAddr + "/gm/gacha/details?scheduleId=833&jwt=" + jwtStr,
GachaUpInfoList: []*proto.GachaUpInfo{
{
ItemParentType: 1,
ItemIdList: []uint32{1029},
},
{
ItemParentType: 2,
ItemIdList: []uint32{1025, 1034, 1043},
},
},
DisplayUp4ItemList: []uint32{1025},
DisplayUp5ItemList: []uint32{1029},
WishItemId: 0,
WishProgress: 0,
WishMaxProgress: 0,
IsNewWish: false,
},
// 阿莫斯之弓&天空之傲
{
GachaType: 431,
ScheduleId: 1143,
BeginTime: 0,
EndTime: 2051193600,
GachaSortId: 9997,
GachaPrefabPath: "GachaShowPanel_A030",
GachaPreviewPrefabPath: "UI_Tab_GachaShowPanel_A030",
TitleTextmap: "UI_GACHA_SHOW_PANEL_A030_TITLE",
LeftGachaTimes: 2147483647,
GachaTimesLimit: 2147483647,
CostItemId: 223,
CostItemNum: 1,
TenCostItemId: 223,
TenCostItemNum: 10,
GachaRecordUrl: serverAddr + "/gm/gacha?gachaType=431&jwt=" + jwtStr,
GachaRecordUrlOversea: serverAddr + "/gm/gacha?gachaType=431&jwt=" + jwtStr,
GachaProbUrl: serverAddr + "/gm/gacha/details?scheduleId=1143&jwt=" + jwtStr,
GachaProbUrlOversea: serverAddr + "/gm/gacha/details?scheduleId=1143&jwt=" + jwtStr,
GachaUpInfoList: []*proto.GachaUpInfo{
{
ItemParentType: 1,
ItemIdList: []uint32{15502, 12501},
},
{
ItemParentType: 2,
ItemIdList: []uint32{11403, 12402, 13401, 14409, 15401},
},
},
DisplayUp4ItemList: []uint32{11403},
DisplayUp5ItemList: []uint32{15502, 12501},
WishItemId: 0,
WishProgress: 0,
WishMaxProgress: 0,
IsNewWish: false,
},
// 常驻
{
GachaType: 201,
ScheduleId: 813,
BeginTime: 0,
EndTime: 2051193600,
GachaSortId: 1000,
GachaPrefabPath: "GachaShowPanel_A017",
GachaPreviewPrefabPath: "UI_Tab_GachaShowPanel_A017",
TitleTextmap: "UI_GACHA_SHOW_PANEL_A017_TITLE",
LeftGachaTimes: 2147483647,
GachaTimesLimit: 2147483647,
CostItemId: 224,
CostItemNum: 1,
TenCostItemId: 224,
TenCostItemNum: 10,
GachaRecordUrl: serverAddr + "/gm/gacha?gachaType=201&jwt=" + jwtStr,
GachaRecordUrlOversea: serverAddr + "/gm/gacha?gachaType=201&jwt=" + jwtStr,
GachaProbUrl: serverAddr + "/gm/gacha/details?scheduleId=813&jwt=" + jwtStr,
GachaProbUrlOversea: serverAddr + "/gm/gacha/details?scheduleId=813&jwt=" + jwtStr,
GachaUpInfoList: []*proto.GachaUpInfo{
{
ItemParentType: 1,
ItemIdList: []uint32{1003, 1016},
},
{
ItemParentType: 2,
ItemIdList: []uint32{1021, 1006, 1015},
},
},
DisplayUp4ItemList: []uint32{1021},
DisplayUp5ItemList: []uint32{1003, 1016},
WishItemId: 0,
WishProgress: 0,
WishMaxProgress: 0,
IsNewWish: false,
},
}
g.SendMsg(proto.ApiGetGachaInfoRsp, userId, player.ClientSeq, getGachaInfoRsp)
}
func (g *GameManager) DoGachaReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user do gacha, userId: %v", userId)
req := payloadMsg.(*proto.DoGachaReq)
gachaScheduleId := req.GachaScheduleId
gachaTimes := req.GachaTimes
gachaType := uint32(0)
costItemId := uint32(0)
switch gachaScheduleId {
case 823:
// 温迪
gachaType = 300
costItemId = 223
case 833:
// 可莉
gachaType = 400
costItemId = 223
case 1143:
// 阿莫斯之弓&天空之傲
gachaType = 431
costItemId = 223
case 813:
// 常驻
gachaType = 201
costItemId = 224
}
// PacketDoGachaRsp
doGachaRsp := new(proto.DoGachaRsp)
doGachaRsp.GachaType = gachaType
doGachaRsp.GachaScheduleId = gachaScheduleId
doGachaRsp.GachaTimes = gachaTimes
doGachaRsp.NewGachaRandom = 12345
doGachaRsp.LeftGachaTimes = 2147483647
doGachaRsp.GachaTimesLimit = 2147483647
doGachaRsp.CostItemId = costItemId
doGachaRsp.CostItemNum = 1
doGachaRsp.TenCostItemId = costItemId
doGachaRsp.TenCostItemNum = 10
// 先扣掉粉球或蓝球再进行抽卡
g.CostUserItem(player.PlayerID, []*UserItem{
{
ItemId: costItemId,
ChangeCount: gachaTimes,
},
})
doGachaRsp.GachaItemList = make([]*proto.GachaItem, 0)
for i := uint32(0); i < gachaTimes; i++ {
var ok bool
var itemId uint32
if gachaType == 400 {
// 可莉
ok, itemId = g.doGachaKlee()
} else if gachaType == 300 {
// 角色UP池
ok, itemId = g.doGachaOnce(userId, gachaType, true, false)
} else if gachaType == 431 {
// 武器UP池
ok, itemId = g.doGachaOnce(userId, gachaType, true, true)
} else if gachaType == 201 {
// 常驻
ok, itemId = g.doGachaOnce(userId, gachaType, false, false)
} else {
ok, itemId = false, 0
}
if !ok {
itemId = 11301
}
// 添加抽卡获得的道具
if itemId > 1000 && itemId < 2000 {
avatarId := (itemId % 1000) + 10000000
_, exist := player.AvatarMap[avatarId]
if !exist {
g.AddUserAvatar(player.PlayerID, avatarId)
} else {
constellationItemId := itemId + 100
if player.GetItemCount(constellationItemId) < 6 {
g.AddUserItem(player.PlayerID, []*UserItem{{ItemId: constellationItemId, ChangeCount: 1}}, false, 0)
}
}
} else if itemId > 10000 && itemId < 20000 {
g.AddUserWeapon(player.PlayerID, itemId)
} else {
g.AddUserItem(player.PlayerID, []*UserItem{{ItemId: itemId, ChangeCount: 1}}, false, 0)
}
// 计算星尘星辉
xc := uint32(random.GetRandomInt32(0, 10))
xh := uint32(random.GetRandomInt32(0, 10))
gachaItem := new(proto.GachaItem)
gachaItem.GachaItem_ = &proto.ItemParam{
ItemId: itemId,
Count: 1,
}
// 星尘
if xc != 0 {
g.AddUserItem(player.PlayerID, []*UserItem{{
ItemId: 222,
ChangeCount: xc,
}}, false, 0)
gachaItem.TokenItemList = []*proto.ItemParam{{
ItemId: 222,
Count: xc,
}}
}
// 星辉
if xh != 0 {
g.AddUserItem(player.PlayerID, []*UserItem{{
ItemId: 221,
ChangeCount: xh,
}}, false, 0)
gachaItem.TransferItems = []*proto.GachaTransferItem{{
Item: &proto.ItemParam{
ItemId: 221,
Count: xh,
},
}}
}
doGachaRsp.GachaItemList = append(doGachaRsp.GachaItemList, gachaItem)
}
//logger.LOG.Debug("doGachaRsp: %v", doGachaRsp.String())
g.SendMsg(proto.ApiDoGachaRsp, userId, player.ClientSeq, doGachaRsp)
}
// 扣1给可莉刷烧烤酱
func (g *GameManager) doGachaKlee() (bool, uint32) {
allAvatarList := make([]uint32, 0)
allAvatarDataConfig := g.GetAllAvatarDataConfig()
for k, v := range allAvatarDataConfig {
if v.QualityType == "QUALITY_ORANGE" || v.QualityType == "QUALITY_PURPLE" {
allAvatarList = append(allAvatarList, uint32(k))
}
}
allWeaponList := make([]uint32, 0)
allWeaponDataConfig := g.GetAllWeaponDataConfig()
for k, v := range allWeaponDataConfig {
if v.RankLevel == 5 {
allWeaponList = append(allWeaponList, uint32(k))
}
}
allGoodList := make([]uint32, 0)
// 全部角色
allGoodList = append(allGoodList, allAvatarList...)
// 全部5星武器
allGoodList = append(allGoodList, allWeaponList...)
// 原石 摩拉 粉球 蓝球
allGoodList = append(allGoodList, 201, 202, 223, 224)
// 苟利国家生死以
allGoodList = append(allGoodList, 100081)
rn := random.GetRandomInt32(0, int32(len(allGoodList)-1))
itemId := allGoodList[rn]
if itemId > 10000000 {
itemId %= 1000
itemId += 1000
}
return true, itemId
}
const (
Orange = iota
Purple
Blue
Avatar
Weapon
)
const (
StandardOrangeTimesFixThreshold uint32 = 74 // 标准池触发5星概率修正阈值的抽卡次数
StandardOrangeTimesFixValue int32 = 600 // 标准池5星概率修正因子
StandardPurpleTimesFixThreshold uint32 = 9 // 标准池触发4星概率修正阈值的抽卡次数
StandardPurpleTimesFixValue int32 = 5100 // 标准池4星概率修正因子
WeaponOrangeTimesFixThreshold uint32 = 63 // 武器池触发5星概率修正阈值的抽卡次数
WeaponOrangeTimesFixValue int32 = 700 // 武器池5星概率修正因子
WeaponPurpleTimesFixThreshold uint32 = 8 // 武器池触发4星概率修正阈值的抽卡次数
WeaponPurpleTimesFixValue int32 = 6000 // 武器池4星概率修正因子
)
// 单抽一次
func (g *GameManager) doGachaOnce(userId uint32, gachaType uint32, mustGetUpEnable bool, weaponFix bool) (bool, uint32) {
player := g.userManager.GetOnlineUser(userId)
if player == nil {
logger.LOG.Error("player is nil, userId: %v", userId)
return false, 0
}
// 找到卡池对应的掉落组
dropGroupDataConfig := gdc.CONF.DropGroupDataMap[int32(gachaType)]
if dropGroupDataConfig == nil {
logger.LOG.Error("drop group not found, drop id: %v", gachaType)
return false, 0
}
// 获取用户的卡池保底信息
gachaPoolInfo := player.DropInfo.GachaPoolInfo[gachaType]
if gachaPoolInfo == nil {
logger.LOG.Error("user gacha pool info not found, gacha type: %v", gachaType)
return false, 0
}
// 保底计数+1
gachaPoolInfo.OrangeTimes++
gachaPoolInfo.PurpleTimes++
// 4星和5星概率修正
OrangeTimesFixThreshold := uint32(0)
OrangeTimesFixValue := int32(0)
PurpleTimesFixThreshold := uint32(0)
PurpleTimesFixValue := int32(0)
if !weaponFix {
OrangeTimesFixThreshold = StandardOrangeTimesFixThreshold
OrangeTimesFixValue = StandardOrangeTimesFixValue
PurpleTimesFixThreshold = StandardPurpleTimesFixThreshold
PurpleTimesFixValue = StandardPurpleTimesFixValue
} else {
OrangeTimesFixThreshold = WeaponOrangeTimesFixThreshold
OrangeTimesFixValue = WeaponOrangeTimesFixValue
PurpleTimesFixThreshold = WeaponPurpleTimesFixThreshold
PurpleTimesFixValue = WeaponPurpleTimesFixValue
}
if gachaPoolInfo.OrangeTimes >= OrangeTimesFixThreshold || gachaPoolInfo.PurpleTimes >= PurpleTimesFixThreshold {
fixDropGroupDataConfig := new(gdc.DropGroupData)
fixDropGroupDataConfig.DropId = dropGroupDataConfig.DropId
fixDropGroupDataConfig.WeightAll = dropGroupDataConfig.WeightAll
// 计算4星和5星权重修正值
addOrangeWeight := int32(gachaPoolInfo.OrangeTimes-OrangeTimesFixThreshold+1) * OrangeTimesFixValue
if addOrangeWeight < 0 {
addOrangeWeight = 0
}
addPurpleWeight := int32(gachaPoolInfo.PurpleTimes-PurpleTimesFixThreshold+1) * PurpleTimesFixValue
if addPurpleWeight < 0 {
addPurpleWeight = 0
}
for _, drop := range dropGroupDataConfig.DropConfig {
fixDrop := new(gdc.Drop)
fixDrop.Result = drop.Result
fixDrop.DropId = drop.DropId
fixDrop.IsEnd = drop.IsEnd
// 找到5/4/3星掉落组id 要求配置表的5/4/3星掉落组id规则固定为(卡池类型*10+1/2/3)
orangeDropId := int32(gachaType*10 + 1)
purpleDropId := int32(gachaType*10 + 2)
blueDropId := int32(gachaType*10 + 3)
// 权重修正
if drop.Result == orangeDropId {
fixDrop.Weight = drop.Weight + addOrangeWeight
} else if drop.Result == purpleDropId {
fixDrop.Weight = drop.Weight + addPurpleWeight
} else if drop.Result == blueDropId {
fixDrop.Weight = drop.Weight - addOrangeWeight - addPurpleWeight
} else {
logger.LOG.Error("invalid drop group id, does not match any case of orange/purple/blue, result group id: %v", drop.Result)
fixDrop.Weight = drop.Weight
}
fixDropGroupDataConfig.DropConfig = append(fixDropGroupDataConfig.DropConfig, fixDrop)
}
dropGroupDataConfig = fixDropGroupDataConfig
}
// 掉落
ok, drop := g.doFullRandDrop(dropGroupDataConfig)
if !ok {
return false, 0
}
// 分析本次掉落结果的星级和类型
itemColor := 0
itemType := 0
_ = itemType
gachaItemId := uint32(drop.Result)
if gachaItemId < 2000 {
// 抽到角色
itemType = Avatar
avatarId := (gachaItemId % 1000) + 10000000
allAvatarDataConfig := g.GetAllAvatarDataConfig()
avatarDataConfig := allAvatarDataConfig[int32(avatarId)]
if avatarDataConfig == nil {
logger.LOG.Error("avatar data config not found, avatar id: %v", avatarId)
return false, 0
}
if avatarDataConfig.QualityType == "QUALITY_ORANGE" {
itemColor = Orange
logger.LOG.Debug("[orange avatar], times: %v, gachaItemId: %v", gachaPoolInfo.OrangeTimes, gachaItemId)
if gachaPoolInfo.OrangeTimes > 90 {
logger.LOG.Error("[abnormal orange avatar], times: %v, gachaItemId: %v", gachaPoolInfo.OrangeTimes, gachaItemId)
}
} else if avatarDataConfig.QualityType == "QUALITY_PURPLE" {
itemColor = Purple
logger.LOG.Debug("[purple avatar], times: %v, gachaItemId: %v", gachaPoolInfo.PurpleTimes, gachaItemId)
if gachaPoolInfo.PurpleTimes > 10 {
logger.LOG.Error("[abnormal purple avatar], times: %v, gachaItemId: %v", gachaPoolInfo.PurpleTimes, gachaItemId)
}
} else {
itemColor = Blue
}
} else {
// 抽到武器
itemType = Weapon
allWeaponDataConfig := g.GetAllWeaponDataConfig()
weaponDataConfig := allWeaponDataConfig[int32(gachaItemId)]
if weaponDataConfig == nil {
logger.LOG.Error("weapon item data config not found, item id: %v", gachaItemId)
return false, 0
}
if weaponDataConfig.RankLevel == 5 {
itemColor = Orange
logger.LOG.Debug("[orange weapon], times: %v, gachaItemId: %v", gachaPoolInfo.OrangeTimes, gachaItemId)
if gachaPoolInfo.OrangeTimes > 90 {
logger.LOG.Error("[abnormal orange weapon], times: %v, gachaItemId: %v", gachaPoolInfo.OrangeTimes, gachaItemId)
}
} else if weaponDataConfig.RankLevel == 4 {
itemColor = Purple
logger.LOG.Debug("[purple weapon], times: %v, gachaItemId: %v", gachaPoolInfo.PurpleTimes, gachaItemId)
if gachaPoolInfo.PurpleTimes > 10 {
logger.LOG.Error("[abnormal purple weapon], times: %v, gachaItemId: %v", gachaPoolInfo.PurpleTimes, gachaItemId)
}
} else {
itemColor = Blue
}
}
// 后处理
switch itemColor {
case Orange:
// 重置5星保底计数
gachaPoolInfo.OrangeTimes = 0
if mustGetUpEnable {
// 找到UP的5星对应的掉落组id 要求配置表的UP的5星掉落组id规则固定为(卡池类型*100+12)
upOrangeDropId := int32(gachaType*100 + 12)
// 替换本次结果为5星大保底
if gachaPoolInfo.MustGetUpOrange {
logger.LOG.Debug("trigger must get up orange, user id: %v", userId)
upOrangeDropGroupDataConfig := gdc.CONF.DropGroupDataMap[upOrangeDropId]
if upOrangeDropGroupDataConfig == nil {
logger.LOG.Error("drop group not found, drop id: %v", upOrangeDropId)
return false, 0
}
upOrangeOk, upOrangeDrop := g.doFullRandDrop(upOrangeDropGroupDataConfig)
if !upOrangeOk {
return false, 0
}
gachaPoolInfo.MustGetUpOrange = false
upOrangeGachaItemId := uint32(upOrangeDrop.Result)
return upOrangeOk, upOrangeGachaItemId
}
// 触发5星大保底
if drop.DropId != upOrangeDropId {
gachaPoolInfo.MustGetUpOrange = true
}
}
case Purple:
// 重置4星保底计数
gachaPoolInfo.PurpleTimes = 0
if mustGetUpEnable {
// 找到UP的4星对应的掉落组id 要求配置表的UP的4星掉落组id规则固定为(卡池类型*100+22)
upPurpleDropId := int32(gachaType*100 + 22)
// 替换本次结果为4星大保底
if gachaPoolInfo.MustGetUpPurple {
logger.LOG.Debug("trigger must get up purple, user id: %v", userId)
upPurpleDropGroupDataConfig := gdc.CONF.DropGroupDataMap[upPurpleDropId]
if upPurpleDropGroupDataConfig == nil {
logger.LOG.Error("drop group not found, drop id: %v", upPurpleDropId)
return false, 0
}
upPurpleOk, upPurpleDrop := g.doFullRandDrop(upPurpleDropGroupDataConfig)
if !upPurpleOk {
return false, 0
}
gachaPoolInfo.MustGetUpPurple = false
upPurpleGachaItemId := uint32(upPurpleDrop.Result)
return upPurpleOk, upPurpleGachaItemId
}
// 触发4星大保底
if drop.DropId != upPurpleDropId {
gachaPoolInfo.MustGetUpPurple = true
}
}
default:
}
return ok, gachaItemId
}
// 走一次完整流程的掉落组
func (g *GameManager) doFullRandDrop(dropGroupDataConfig *gdc.DropGroupData) (bool, *gdc.Drop) {
for {
drop := g.doRandDropOnce(dropGroupDataConfig)
if drop == nil {
logger.LOG.Error("weight error, drop group config: %v", dropGroupDataConfig)
return false, nil
}
if drop.IsEnd {
// 成功抽到物品
return true, drop
}
// 进行下一步掉落流程
dropGroupDataConfig = gdc.CONF.DropGroupDataMap[drop.Result]
if dropGroupDataConfig == nil {
logger.LOG.Error("drop config tab exist error, invalid drop id: %v", drop.Result)
return false, nil
}
}
}
// 进行单次随机掉落
func (g *GameManager) doRandDropOnce(dropGroupDataConfig *gdc.DropGroupData) *gdc.Drop {
randNum := random.GetRandomInt32(0, dropGroupDataConfig.WeightAll-1)
sumWeight := int32(0)
// 轮盘选择法
for _, drop := range dropGroupDataConfig.DropConfig {
sumWeight += drop.Weight
if sumWeight > randNum {
return drop
}
}
return nil
}

View File

@@ -0,0 +1,181 @@
package game
import (
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
gdc "game-hk4e/config"
"game-hk4e/constant"
)
type UserItem struct {
ItemId uint32
ChangeCount uint32
}
func (g *GameManager) GetAllItemDataConfig() map[int32]*gdc.ItemData {
allItemDataConfig := make(map[int32]*gdc.ItemData)
for itemId, itemData := range gdc.CONF.ItemDataMap {
if itemData.ItemEnumType == constant.ItemTypeConst.ITEM_WEAPON {
// 排除武器
continue
}
if itemData.ItemEnumType == constant.ItemTypeConst.ITEM_RELIQUARY {
// 排除圣遗物
continue
}
if itemId == 100086 ||
itemId == 100087 ||
(itemId >= 100100 && itemId <= 101000) ||
(itemId >= 101106 && itemId <= 101110) ||
itemId == 101306 ||
(itemId >= 101500 && itemId <= 104000) ||
itemId == 105001 ||
itemId == 105004 ||
(itemId >= 106000 && itemId <= 107000) ||
itemId == 107011 ||
itemId == 108000 ||
(itemId >= 109000 && itemId <= 110000) ||
(itemId >= 115000 && itemId <= 130000) ||
(itemId >= 200200 && itemId <= 200899) ||
itemId == 220050 ||
itemId == 220054 {
// 排除无效道具
continue
}
allItemDataConfig[itemId] = itemData
}
return allItemDataConfig
}
func (g *GameManager) AddUserItem(userId uint32, itemList []*UserItem, isHint bool, hintReason uint16) {
player := g.userManager.GetOnlineUser(userId)
if player == nil {
logger.LOG.Error("player is nil, userId: %v", userId)
return
}
for _, userItem := range itemList {
player.AddItem(userItem.ItemId, userItem.ChangeCount)
}
// PacketStoreItemChangeNotify
storeItemChangeNotify := new(proto.StoreItemChangeNotify)
storeItemChangeNotify.StoreType = proto.StoreType_STORE_TYPE_PACK
for _, userItem := range itemList {
pbItem := &proto.Item{
ItemId: userItem.ItemId,
Guid: player.GetItemGuid(userItem.ItemId),
Detail: &proto.Item_Material{
Material: &proto.Material{
Count: player.GetItemCount(userItem.ItemId),
},
},
}
storeItemChangeNotify.ItemList = append(storeItemChangeNotify.ItemList, pbItem)
}
g.SendMsg(proto.ApiStoreItemChangeNotify, userId, player.ClientSeq, storeItemChangeNotify)
if isHint {
if hintReason == 0 {
hintReason = constant.ActionReasonConst.SubfieldDrop
}
// PacketItemAddHintNotify
itemAddHintNotify := new(proto.ItemAddHintNotify)
itemAddHintNotify.Reason = uint32(hintReason)
for _, userItem := range itemList {
itemAddHintNotify.ItemList = append(itemAddHintNotify.ItemList, &proto.ItemHint{
ItemId: userItem.ItemId,
Count: userItem.ChangeCount,
IsNew: false,
})
}
g.SendMsg(proto.ApiItemAddHintNotify, userId, player.ClientSeq, itemAddHintNotify)
}
// PacketPlayerPropNotify
playerPropNotify := new(proto.PlayerPropNotify)
playerPropNotify.PropMap = make(map[uint32]*proto.PropValue)
for _, userItem := range itemList {
isVirtualItem, prop := player.GetVirtualItemProp(userItem.ItemId)
if !isVirtualItem {
continue
}
playerPropNotify.PropMap[uint32(prop)] = &proto.PropValue{
Type: uint32(prop),
Val: int64(player.PropertiesMap[prop]),
Value: &proto.PropValue_Ival{
Ival: int64(player.PropertiesMap[prop]),
},
}
}
if len(playerPropNotify.PropMap) > 0 {
g.SendMsg(proto.ApiPlayerPropNotify, userId, player.ClientSeq, playerPropNotify)
}
}
func (g *GameManager) CostUserItem(userId uint32, itemList []*UserItem) {
player := g.userManager.GetOnlineUser(userId)
if player == nil {
logger.LOG.Error("player is nil, userId: %v", userId)
return
}
for _, userItem := range itemList {
player.CostItem(userItem.ItemId, userItem.ChangeCount)
}
// PacketStoreItemChangeNotify
storeItemChangeNotify := new(proto.StoreItemChangeNotify)
storeItemChangeNotify.StoreType = proto.StoreType_STORE_TYPE_PACK
for _, userItem := range itemList {
count := player.GetItemCount(userItem.ItemId)
if count == 0 {
continue
}
pbItem := &proto.Item{
ItemId: userItem.ItemId,
Guid: player.GetItemGuid(userItem.ItemId),
Detail: &proto.Item_Material{
Material: &proto.Material{
Count: count,
},
},
}
storeItemChangeNotify.ItemList = append(storeItemChangeNotify.ItemList, pbItem)
}
if len(storeItemChangeNotify.ItemList) > 0 {
g.SendMsg(proto.ApiStoreItemChangeNotify, userId, player.ClientSeq, storeItemChangeNotify)
}
// PacketStoreItemDelNotify
storeItemDelNotify := new(proto.StoreItemDelNotify)
storeItemDelNotify.StoreType = proto.StoreType_STORE_TYPE_PACK
for _, userItem := range itemList {
count := player.GetItemCount(userItem.ItemId)
if count > 0 {
continue
}
storeItemDelNotify.GuidList = append(storeItemDelNotify.GuidList, player.GetItemGuid(userItem.ItemId))
}
if len(storeItemDelNotify.GuidList) > 0 {
g.SendMsg(proto.ApiStoreItemDelNotify, userId, player.ClientSeq, storeItemDelNotify)
}
// PacketPlayerPropNotify
playerPropNotify := new(proto.PlayerPropNotify)
playerPropNotify.PropMap = make(map[uint32]*proto.PropValue)
for _, userItem := range itemList {
isVirtualItem, prop := player.GetVirtualItemProp(userItem.ItemId)
if !isVirtualItem {
continue
}
playerPropNotify.PropMap[uint32(prop)] = &proto.PropValue{
Type: uint32(prop),
Val: int64(player.PropertiesMap[prop]),
Value: &proto.PropValue_Ival{
Ival: int64(player.PropertiesMap[prop]),
},
}
}
if len(playerPropNotify.PropMap) > 0 {
g.SendMsg(proto.ApiPlayerPropNotify, userId, player.ClientSeq, playerPropNotify)
}
}

View File

@@ -0,0 +1,375 @@
package game
import (
"flswld.com/common/utils/reflection"
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
gdc "game-hk4e/config"
"game-hk4e/constant"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
"time"
)
func (g *GameManager) OnLogin(userId uint32, clientSeq uint32) {
logger.LOG.Info("user login, user id: %v", userId)
player, asyncWait := g.userManager.OnlineUser(userId, clientSeq)
if !asyncWait {
g.OnLoginOk(userId, player, clientSeq)
}
}
func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq uint32) {
if player == nil {
g.SendMsg(proto.ApiDoSetPlayerBornDataNotify, userId, clientSeq, new(proto.DoSetPlayerBornDataNotify))
return
}
player.OnlineTime = uint32(time.Now().UnixMilli())
player.Online = true
// TODO 3.0.0REL版本 目前存在当前队伍活跃角色非主角时 登录进不去场景的情况 所以暂时先把四号队伍作为仅存在主角的保留队伍
team := player.TeamConfig.GetTeamByIndex(3)
team.AvatarIdList = []uint32{player.MainCharAvatarId, 0, 0, 0}
player.TeamConfig.CurrTeamIndex = 3
player.TeamConfig.CurrAvatarIndex = 0
// 初始化
player.InitAll()
player.TeamConfig.UpdateTeam()
// 创建世界
world := g.worldManager.CreateWorld(player, false)
world.AddPlayer(player, player.SceneId)
player.WorldId = world.id
// TODO 薄荷标记
if world.IsBigWorld() {
bigWorld := world.GetSceneById(3)
for pos := range g.worldManager.worldStatic.terrain {
bigWorld.CreateEntityGadget(&model.Vector{
X: float64(pos.X),
Y: float64(pos.Y),
Z: float64(pos.Z),
}, 3003009)
}
}
// PacketPlayerDataNotify
playerDataNotify := new(proto.PlayerDataNotify)
playerDataNotify.NickName = player.NickName
playerDataNotify.ServerTime = uint64(time.Now().UnixMilli())
playerDataNotify.IsFirstLoginToday = true
playerDataNotify.RegionId = player.RegionId
playerDataNotify.PropMap = make(map[uint32]*proto.PropValue)
for k, v := range player.PropertiesMap {
propValue := new(proto.PropValue)
propValue.Type = uint32(k)
propValue.Value = &proto.PropValue_Ival{Ival: int64(v)}
propValue.Val = int64(v)
playerDataNotify.PropMap[uint32(k)] = propValue
}
g.SendMsg(proto.ApiPlayerDataNotify, userId, clientSeq, playerDataNotify)
// PacketStoreWeightLimitNotify
storeWeightLimitNotify := new(proto.StoreWeightLimitNotify)
storeWeightLimitNotify.StoreType = proto.StoreType_STORE_TYPE_PACK
// TODO 原神背包容量限制 写到配置文件
storeWeightLimitNotify.WeightLimit = 30000
storeWeightLimitNotify.WeaponCountLimit = 2000
storeWeightLimitNotify.ReliquaryCountLimit = 1500
storeWeightLimitNotify.MaterialCountLimit = 2000
storeWeightLimitNotify.FurnitureCountLimit = 2000
g.SendMsg(proto.ApiStoreWeightLimitNotify, userId, clientSeq, storeWeightLimitNotify)
// PacketPlayerStoreNotify
playerStoreNotify := new(proto.PlayerStoreNotify)
playerStoreNotify.StoreType = proto.StoreType_STORE_TYPE_PACK
playerStoreNotify.WeightLimit = 30000
itemDataMapConfig := gdc.CONF.ItemDataMap
for _, weapon := range player.WeaponMap {
pbItem := &proto.Item{
ItemId: weapon.ItemId,
Guid: weapon.Guid,
Detail: nil,
}
if itemDataMapConfig[int32(weapon.ItemId)].ItemEnumType != constant.ItemTypeConst.ITEM_WEAPON {
continue
}
affixMap := make(map[uint32]uint32)
for _, affixId := range weapon.AffixIdList {
affixMap[affixId] = uint32(weapon.Refinement)
}
pbItem.Detail = &proto.Item_Equip{
Equip: &proto.Equip{
Detail: &proto.Equip_Weapon{
Weapon: &proto.Weapon{
Level: uint32(weapon.Level),
Exp: weapon.Exp,
PromoteLevel: uint32(weapon.Promote),
AffixMap: affixMap,
},
},
IsLocked: weapon.Lock,
},
}
playerStoreNotify.ItemList = append(playerStoreNotify.ItemList, pbItem)
}
for _, reliquary := range player.ReliquaryMap {
pbItem := &proto.Item{
ItemId: reliquary.ItemId,
Guid: reliquary.Guid,
Detail: nil,
}
if itemDataMapConfig[int32(reliquary.ItemId)].ItemEnumType != constant.ItemTypeConst.ITEM_RELIQUARY {
continue
}
pbItem.Detail = &proto.Item_Equip{
Equip: &proto.Equip{
Detail: &proto.Equip_Reliquary{
Reliquary: &proto.Reliquary{
Level: uint32(reliquary.Level),
Exp: reliquary.Exp,
PromoteLevel: uint32(reliquary.Promote),
MainPropId: reliquary.MainPropId,
// TODO 圣遗物副词条
AppendPropIdList: nil,
},
},
IsLocked: reliquary.Lock,
},
}
playerStoreNotify.ItemList = append(playerStoreNotify.ItemList, pbItem)
}
for _, item := range player.ItemMap {
pbItem := &proto.Item{
ItemId: item.ItemId,
Guid: item.Guid,
Detail: nil,
}
itemDataConfig := itemDataMapConfig[int32(item.ItemId)]
if itemDataConfig != nil && itemDataConfig.ItemEnumType == constant.ItemTypeConst.ITEM_FURNITURE {
pbItem.Detail = &proto.Item_Furniture{
Furniture: &proto.Furniture{
Count: item.Count,
},
}
} else {
pbItem.Detail = &proto.Item_Material{
Material: &proto.Material{
Count: item.Count,
DeleteInfo: nil,
},
}
}
playerStoreNotify.ItemList = append(playerStoreNotify.ItemList, pbItem)
}
g.SendMsg(proto.ApiPlayerStoreNotify, userId, clientSeq, playerStoreNotify)
// PacketAvatarDataNotify
avatarDataNotify := new(proto.AvatarDataNotify)
chooseAvatarId := player.TeamConfig.GetActiveAvatarId()
avatarDataNotify.CurAvatarTeamId = uint32(player.TeamConfig.GetActiveTeamId())
avatarDataNotify.ChooseAvatarGuid = player.AvatarMap[chooseAvatarId].Guid
avatarDataNotify.OwnedFlycloakList = player.FlyCloakList
// 角色衣装
avatarDataNotify.OwnedCostumeList = player.CostumeList
for _, avatar := range player.AvatarMap {
pbAvatar := g.PacketAvatarInfo(avatar)
avatarDataNotify.AvatarList = append(avatarDataNotify.AvatarList, pbAvatar)
}
avatarDataNotify.AvatarTeamMap = make(map[uint32]*proto.AvatarTeam)
for teamIndex, team := range player.TeamConfig.TeamList {
var teamAvatarGuidList []uint64 = nil
for _, avatarId := range team.AvatarIdList {
if avatarId == 0 {
break
}
teamAvatarGuidList = append(teamAvatarGuidList, player.AvatarMap[avatarId].Guid)
}
avatarDataNotify.AvatarTeamMap[uint32(teamIndex)+1] = &proto.AvatarTeam{
AvatarGuidList: teamAvatarGuidList,
TeamName: team.Name,
}
}
g.SendMsg(proto.ApiAvatarDataNotify, userId, clientSeq, avatarDataNotify)
player.SceneLoadState = model.SceneNone
// PacketPlayerEnterSceneNotify
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotify(player)
g.SendMsg(proto.ApiPlayerEnterSceneNotify, userId, clientSeq, playerEnterSceneNotify)
// PacketOpenStateUpdateNotify
openStateUpdateNotify := new(proto.OpenStateUpdateNotify)
openStateConstMap := reflection.ConvStructToMap(constant.OpenStateConst)
openStateUpdateNotify.OpenStateMap = make(map[uint32]uint32)
for _, v := range openStateConstMap {
openStateUpdateNotify.OpenStateMap[uint32(v.(uint16))] = 1
}
g.SendMsg(proto.ApiOpenStateUpdateNotify, userId, clientSeq, openStateUpdateNotify)
}
func (g *GameManager) OnReg(userId uint32, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user reg, user id: %v", userId)
req := payloadMsg.(*proto.SetPlayerBornDataReq)
logger.LOG.Debug("avatar id: %v, nickname: %v", req.AvatarId, req.NickName)
exist, asyncWait := g.userManager.CheckUserExistOnReg(userId, req, clientSeq)
if !asyncWait {
g.OnRegOk(exist, req, userId, clientSeq)
}
}
func (g *GameManager) OnRegOk(exist bool, req *proto.SetPlayerBornDataReq, userId uint32, clientSeq uint32) {
if exist {
logger.LOG.Error("recv reg req, but user is already exist, userId: %v", userId)
return
}
nickName := req.NickName
mainCharAvatarId := req.GetAvatarId()
if mainCharAvatarId != 10000005 && mainCharAvatarId != 10000007 {
logger.LOG.Error("invalid main char avatar id: %v", mainCharAvatarId)
return
}
player := g.CreatePlayer(userId, nickName, mainCharAvatarId)
g.userManager.AddUser(player)
g.SendMsg(proto.ApiSetPlayerBornDataRsp, userId, clientSeq, new(proto.SetPlayerBornDataRsp))
g.OnLogin(userId, clientSeq)
}
func (g *GameManager) OnUserOffline(userId uint32) {
logger.LOG.Info("user offline, user id: %v", userId)
player := g.userManager.GetOnlineUser(userId)
if player == nil {
logger.LOG.Error("player is nil, userId: %v", userId)
return
}
world := g.worldManager.GetWorldByID(player.WorldId)
if world != nil {
g.UserWorldRemovePlayer(world, player)
}
player.OfflineTime = uint32(time.Now().Unix())
player.Online = false
player.TotalOnlineTime += uint32(time.Now().UnixMilli()) - player.OnlineTime
g.userManager.OfflineUser(player)
}
func (g *GameManager) CreatePlayer(userId uint32, nickName string, mainCharAvatarId uint32) *model.Player {
player := new(model.Player)
player.PlayerID = userId
player.NickName = nickName
player.Signature = "惟愿时光记忆,一路繁花千树。"
player.MainCharAvatarId = mainCharAvatarId
player.HeadImage = mainCharAvatarId
player.NameCard = 210001
player.NameCardList = make([]uint32, 0)
player.NameCardList = append(player.NameCardList, 210001, 210042)
player.FriendList = make(map[uint32]bool)
player.FriendApplyList = make(map[uint32]bool)
player.RegionId = 1
player.SceneId = 3
player.PropertiesMap = make(map[uint16]uint32)
// 初始化所有属性
propList := reflection.ConvStructToMap(constant.PlayerPropertyConst)
for fieldName, fieldValue := range propList {
if fieldName == "PROP_EXP" ||
fieldName == "PROP_BREAK_LEVEL" ||
fieldName == "PROP_SATIATION_VAL" ||
fieldName == "PROP_SATIATION_PENALTY_TIME" ||
fieldName == "PROP_LEVEL" {
continue
}
value := fieldValue.(uint16)
player.PropertiesMap[value] = 0
}
player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL] = 1
player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL] = 0
player.PropertiesMap[constant.PlayerPropertyConst.PROP_IS_SPRING_AUTO_USE] = 1
player.PropertiesMap[constant.PlayerPropertyConst.PROP_SPRING_AUTO_USE_PERCENT] = 100
player.PropertiesMap[constant.PlayerPropertyConst.PROP_IS_FLYABLE] = 1
player.PropertiesMap[constant.PlayerPropertyConst.PROP_IS_TRANSFERABLE] = 1
player.PropertiesMap[constant.PlayerPropertyConst.PROP_MAX_STAMINA] = 24000
player.PropertiesMap[constant.PlayerPropertyConst.PROP_CUR_PERSIST_STAMINA] = 24000
player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_RESIN] = 160
player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE] = 2
player.PropertiesMap[constant.PlayerPropertyConst.PROP_IS_MP_MODE_AVAILABLE] = 1
player.FlyCloakList = make([]uint32, 0)
player.FlyCloakList = append(player.FlyCloakList, 140001)
player.FlyCloakList = append(player.FlyCloakList, 140002)
player.FlyCloakList = append(player.FlyCloakList, 140003)
player.FlyCloakList = append(player.FlyCloakList, 140004)
player.FlyCloakList = append(player.FlyCloakList, 140005)
player.FlyCloakList = append(player.FlyCloakList, 140006)
player.FlyCloakList = append(player.FlyCloakList, 140007)
player.FlyCloakList = append(player.FlyCloakList, 140008)
player.FlyCloakList = append(player.FlyCloakList, 140009)
player.FlyCloakList = append(player.FlyCloakList, 140010)
player.CostumeList = make([]uint32, 0)
player.CostumeList = append(player.CostumeList, 200301)
player.CostumeList = append(player.CostumeList, 201401)
player.CostumeList = append(player.CostumeList, 202701)
player.CostumeList = append(player.CostumeList, 204201)
player.CostumeList = append(player.CostumeList, 200302)
player.CostumeList = append(player.CostumeList, 202101)
player.CostumeList = append(player.CostumeList, 204101)
player.CostumeList = append(player.CostumeList, 204501)
player.CostumeList = append(player.CostumeList, 201601)
player.CostumeList = append(player.CostumeList, 203101)
player.Pos = &model.Vector{X: 2747, Y: 194, Z: -1719}
player.Rot = &model.Vector{X: 0, Y: 307, Z: 0}
player.ItemMap = make(map[uint32]*model.Item)
player.WeaponMap = make(map[uint64]*model.Weapon)
player.ReliquaryMap = make(map[uint64]*model.Reliquary)
player.AvatarMap = make(map[uint32]*model.Avatar)
player.GameObjectGuidMap = make(map[uint64]model.GameObject)
player.DropInfo = model.NewDropInfo()
player.ChatMsgMap = make(map[uint32][]*model.ChatMsg)
// 选哥哥的福报
if mainCharAvatarId == 10000005 {
// 添加所有角色
allAvatarDataConfig := g.GetAllAvatarDataConfig()
for avatarId, avatarDataConfig := range allAvatarDataConfig {
player.AddAvatar(uint32(avatarId))
// 添加初始武器
weaponId := uint64(g.snowflake.GenId())
player.AddWeapon(uint32(avatarDataConfig.InitialWeapon), weaponId)
// 角色装上初始武器
player.WearWeapon(uint32(avatarId), weaponId)
}
// 添加所有武器
allWeaponDataConfig := g.GetAllWeaponDataConfig()
for itemId := range allWeaponDataConfig {
weaponId := uint64(g.snowflake.GenId())
player.AddWeapon(uint32(itemId), weaponId)
}
// 添加所有道具
allItemDataConfig := g.GetAllItemDataConfig()
for itemId := range allItemDataConfig {
player.AddItem(uint32(itemId), 1)
}
}
// 添加选定的主角
player.AddAvatar(mainCharAvatarId)
// 添加初始武器
avatarDataConfig := gdc.CONF.AvatarDataMap[int32(mainCharAvatarId)]
weaponId := uint64(g.snowflake.GenId())
player.AddWeapon(uint32(avatarDataConfig.InitialWeapon), weaponId)
// 角色装上初始武器
player.WearWeapon(mainCharAvatarId, weaponId)
player.TeamConfig = model.NewTeamInfo()
player.TeamConfig.AddAvatarToTeam(mainCharAvatarId, 0)
return player
}

View File

@@ -0,0 +1,300 @@
package game
import (
"encoding/json"
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
"game-hk4e/dao"
"game-hk4e/model"
"sync"
"time"
)
type UserManager struct {
dao *dao.Dao
playerMap map[uint32]*model.Player
playerMapLock sync.RWMutex
localEventChan chan *LocalEvent
}
func NewUserManager(dao *dao.Dao, localEventChan chan *LocalEvent) (r *UserManager) {
r = new(UserManager)
r.dao = dao
r.playerMap = make(map[uint32]*model.Player)
r.localEventChan = localEventChan
return r
}
func (u *UserManager) GetUserOnlineState(userId uint32) bool {
u.playerMapLock.RLock()
player, exist := u.playerMap[userId]
u.playerMapLock.RUnlock()
if !exist {
return false
} else {
return player.Online
}
}
func (u *UserManager) GetOnlineUser(userId uint32) *model.Player {
u.playerMapLock.RLock()
player, exist := u.playerMap[userId]
u.playerMapLock.RUnlock()
if !exist {
return nil
} else {
if player.Online {
return player
} else {
return nil
}
}
}
func (u *UserManager) GetAllOnlineUserList() map[uint32]*model.Player {
onlinePlayerMap := make(map[uint32]*model.Player)
u.playerMapLock.RLock()
for userId, player := range u.playerMap {
if player.Online == false {
continue
}
onlinePlayerMap[userId] = player
}
u.playerMapLock.RUnlock()
return onlinePlayerMap
}
type PlayerRegInfo struct {
Exist bool
Req *proto.SetPlayerBornDataReq
UserId uint32
ClientSeq uint32
}
func (u *UserManager) CheckUserExistOnReg(userId uint32, req *proto.SetPlayerBornDataReq, clientSeq uint32) (exist bool, asyncWait bool) {
u.playerMapLock.RLock()
_, exist = u.playerMap[userId]
u.playerMapLock.RUnlock()
if exist {
return true, false
} else {
go func() {
player := u.loadUserFromDb(userId)
exist = false
if player != nil {
exist = true
}
u.localEventChan <- &LocalEvent{
EventId: CheckUserExistOnRegFromDbFinish,
Msg: &PlayerRegInfo{
Exist: exist,
Req: req,
UserId: userId,
ClientSeq: clientSeq,
},
}
}()
return false, true
}
}
func (u *UserManager) LoadTempOfflineUserSync(userId uint32) *model.Player {
u.playerMapLock.RLock()
player, exist := u.playerMap[userId]
u.playerMapLock.RUnlock()
if exist {
return player
} else {
player = u.loadUserFromDb(userId)
if player == nil {
return nil
}
player.DbState = model.DbOffline
u.playerMapLock.Lock()
u.playerMap[player.PlayerID] = player
u.playerMapLock.Unlock()
return player
}
}
func (u *UserManager) loadUserFromDb(userId uint32) *model.Player {
player, err := u.dao.QueryPlayerByID(userId)
if err != nil {
logger.LOG.Error("query player error: %v", err)
return nil
}
return player
}
func (u *UserManager) AddUser(player *model.Player) {
if player == nil {
return
}
u.ChangeUserDbState(player, model.DbInsert)
u.playerMapLock.Lock()
u.playerMap[player.PlayerID] = player
u.playerMapLock.Unlock()
}
func (u *UserManager) DeleteUser(player *model.Player) {
if player == nil {
return
}
u.ChangeUserDbState(player, model.DbDelete)
u.playerMapLock.Lock()
u.playerMap[player.PlayerID] = player
u.playerMapLock.Unlock()
}
func (u *UserManager) UpdateUser(player *model.Player) {
if player == nil {
return
}
u.ChangeUserDbState(player, model.DbUpdate)
u.playerMapLock.Lock()
u.playerMap[player.PlayerID] = player
u.playerMapLock.Unlock()
}
type PlayerLoginInfo struct {
UserId uint32
Player *model.Player
ClientSeq uint32
}
func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32) (*model.Player, bool) {
u.playerMapLock.RLock()
player, exist := u.playerMap[userId]
u.playerMapLock.RUnlock()
if exist {
u.ChangeUserDbState(player, model.DbNormal)
return player, false
} else {
go func() {
player = u.loadUserFromDb(userId)
if player != nil {
player.DbState = model.DbNormal
u.playerMapLock.Lock()
u.playerMap[player.PlayerID] = player
u.playerMapLock.Unlock()
}
u.localEventChan <- &LocalEvent{
EventId: LoadLoginUserFromDbFinish,
Msg: &PlayerLoginInfo{
UserId: userId,
Player: player,
ClientSeq: clientSeq,
},
}
}()
return nil, true
}
}
func (u *UserManager) OfflineUser(player *model.Player) {
if player == nil {
return
}
u.ChangeUserDbState(player, model.DbOffline)
u.playerMapLock.Lock()
u.playerMap[player.PlayerID] = player
u.playerMapLock.Unlock()
}
func (u *UserManager) ChangeUserDbState(player *model.Player, state int) {
if player == nil {
return
}
switch player.DbState {
case model.DbInsert:
if state == model.DbDelete {
player.DbState = model.DbDelete
}
case model.DbDelete:
case model.DbUpdate:
if state == model.DbDelete {
player.DbState = model.DbDelete
} else if state == model.DbOffline {
player.DbState = model.DbOffline
}
case model.DbNormal:
if state == model.DbDelete {
player.DbState = model.DbDelete
} else if state == model.DbUpdate {
player.DbState = model.DbUpdate
} else if state == model.DbOffline {
player.DbState = model.DbOffline
}
case model.DbOffline:
if state == model.DbDelete {
player.DbState = model.DbDelete
} else if state == model.DbUpdate {
player.DbState = model.DbUpdate
} else if state == model.DbNormal {
player.DbState = model.DbNormal
}
}
}
func (u *UserManager) StartAutoSaveUser() {
// 用户数据库定时同步协程
go func() {
ticker := time.NewTicker(time.Minute * 5)
for {
logger.LOG.Info("auto save user start")
playerMapTemp := make(map[uint32]*model.Player)
u.playerMapLock.RLock()
for k, v := range u.playerMap {
playerMapTemp[k] = v
}
u.playerMapLock.RUnlock()
logger.LOG.Info("copy user map finish")
insertList := make([]*model.Player, 0)
deleteList := make([]uint32, 0)
updateList := make([]*model.Player, 0)
for k, v := range playerMapTemp {
switch v.DbState {
case model.DbInsert:
insertList = append(insertList, v)
playerMapTemp[k].DbState = model.DbNormal
case model.DbDelete:
deleteList = append(deleteList, v.PlayerID)
delete(playerMapTemp, k)
case model.DbUpdate:
updateList = append(updateList, v)
playerMapTemp[k].DbState = model.DbNormal
case model.DbNormal:
continue
case model.DbOffline:
updateList = append(updateList, v)
delete(playerMapTemp, k)
}
}
insertListJson, err := json.Marshal(insertList)
logger.LOG.Debug("insertList: %v", string(insertListJson))
deleteListJson, err := json.Marshal(deleteList)
logger.LOG.Debug("deleteList: %v", string(deleteListJson))
updateListJson, err := json.Marshal(updateList)
logger.LOG.Debug("updateList: %v", string(updateListJson))
logger.LOG.Info("db state init finish")
err = u.dao.InsertPlayerList(insertList)
if err != nil {
logger.LOG.Error("insert player list error: %v", err)
}
err = u.dao.DeletePlayerList(deleteList)
if err != nil {
logger.LOG.Error("delete player error: %v", err)
}
err = u.dao.UpdatePlayerList(updateList)
if err != nil {
logger.LOG.Error("update player error: %v", err)
}
logger.LOG.Info("db write finish")
u.playerMapLock.Lock()
u.playerMap = playerMapTemp
u.playerMapLock.Unlock()
logger.LOG.Info("auto save user finish")
<-ticker.C
}
}()
}

View File

@@ -0,0 +1,191 @@
package game
import (
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
gdc "game-hk4e/config"
"game-hk4e/constant"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
"strconv"
)
func (g *GameManager) SceneTransToPointReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get scene trans to point, user id: %v", userId)
req := payloadMsg.(*proto.SceneTransToPointReq)
transPointId := strconv.Itoa(int(req.SceneId)) + "_" + strconv.Itoa(int(req.PointId))
transPointConfig, exist := gdc.CONF.ScenePointEntries[transPointId]
if !exist {
// PacketSceneTransToPointRsp
sceneTransToPointRsp := new(proto.SceneTransToPointRsp)
sceneTransToPointRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SVR_ERROR)
g.SendMsg(proto.ApiSceneTransToPointRsp, userId, player.ClientSeq, sceneTransToPointRsp)
return
}
// 传送玩家
newSceneId := req.SceneId
oldSceneId := player.SceneId
oldPos := &model.Vector{
X: player.Pos.X,
Y: player.Pos.Y,
Z: player.Pos.Z,
}
jumpScene := false
if newSceneId != oldSceneId {
jumpScene = true
}
world := g.worldManager.GetWorldByID(player.WorldId)
oldScene := world.GetSceneById(oldSceneId)
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
playerTeamEntity := oldScene.GetPlayerTeamEntity(player.PlayerID)
g.RemoveSceneEntityNotifyBroadcast(oldScene, []uint32{playerTeamEntity.avatarEntityMap[activeAvatarId]})
if jumpScene {
// PacketDelTeamEntityNotify
delTeamEntityNotify := g.PacketDelTeamEntityNotify(oldScene, player)
g.SendMsg(proto.ApiDelTeamEntityNotify, player.PlayerID, player.ClientSeq, delTeamEntityNotify)
oldScene.RemovePlayer(player)
newScene := world.GetSceneById(newSceneId)
newScene.AddPlayer(player)
} else {
oldScene.UpdatePlayerTeamEntity(player)
}
player.Pos.X = transPointConfig.PointData.TranPos.X
player.Pos.Y = transPointConfig.PointData.TranPos.Y
player.Pos.Z = transPointConfig.PointData.TranPos.Z
player.SceneId = newSceneId
player.SceneLoadState = model.SceneNone
// PacketPlayerEnterSceneNotify
var enterType proto.EnterType
if jumpScene {
logger.LOG.Debug("player jump scene, scene: %v, pos: %v", player.SceneId, player.Pos)
enterType = proto.EnterType_ENTER_TYPE_JUMP
} else {
logger.LOG.Debug("player goto scene, scene: %v, pos: %v", player.SceneId, player.Pos)
enterType = proto.EnterType_ENTER_TYPE_GOTO
}
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyTp(player, enterType, uint32(constant.EnterReasonConst.TransPoint), oldSceneId, oldPos)
g.SendMsg(proto.ApiPlayerEnterSceneNotify, userId, player.ClientSeq, playerEnterSceneNotify)
// PacketSceneTransToPointRsp
sceneTransToPointRsp := new(proto.SceneTransToPointRsp)
sceneTransToPointRsp.Retcode = 0
sceneTransToPointRsp.PointId = req.PointId
sceneTransToPointRsp.SceneId = req.SceneId
g.SendMsg(proto.ApiSceneTransToPointRsp, userId, player.ClientSeq, sceneTransToPointRsp)
}
func (g *GameManager) MarkMapReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user mark map, user id: %v", userId)
req := payloadMsg.(*proto.MarkMapReq)
operation := req.Op
if operation == proto.MarkMapReq_OPERATION_ADD {
logger.LOG.Debug("user mark type: %v", req.Mark.PointType)
if req.Mark.PointType == proto.MapMarkPointType_MAP_MARK_POINT_TYPE_NPC {
posYInt, err := strconv.ParseInt(req.Mark.Name, 10, 64)
if err != nil {
logger.LOG.Error("parse pos y error: %v", err)
posYInt = 0
}
// 传送玩家
newSceneId := req.Mark.SceneId
oldSceneId := player.SceneId
oldPos := &model.Vector{
X: player.Pos.X,
Y: player.Pos.Y,
Z: player.Pos.Z,
}
jumpScene := false
if newSceneId != oldSceneId {
jumpScene = true
}
world := g.worldManager.GetWorldByID(player.WorldId)
oldScene := world.GetSceneById(oldSceneId)
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
playerTeamEntity := oldScene.GetPlayerTeamEntity(player.PlayerID)
g.RemoveSceneEntityNotifyBroadcast(oldScene, []uint32{playerTeamEntity.avatarEntityMap[activeAvatarId]})
if jumpScene {
// PacketDelTeamEntityNotify
delTeamEntityNotify := g.PacketDelTeamEntityNotify(oldScene, player)
g.SendMsg(proto.ApiDelTeamEntityNotify, player.PlayerID, player.ClientSeq, delTeamEntityNotify)
oldScene.RemovePlayer(player)
newScene := world.GetSceneById(newSceneId)
newScene.AddPlayer(player)
} else {
oldScene.UpdatePlayerTeamEntity(player)
}
player.Pos.X = float64(req.Mark.Pos.X)
player.Pos.Y = float64(posYInt)
player.Pos.Z = float64(req.Mark.Pos.Z)
player.SceneId = newSceneId
player.SceneLoadState = model.SceneNone
// PacketPlayerEnterSceneNotify
var enterType proto.EnterType
if jumpScene {
logger.LOG.Debug("player jump scene, scene: %v, pos: %v", player.SceneId, player.Pos)
enterType = proto.EnterType_ENTER_TYPE_JUMP
} else {
logger.LOG.Debug("player goto scene, scene: %v, pos: %v", player.SceneId, player.Pos)
enterType = proto.EnterType_ENTER_TYPE_GOTO
}
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyTp(player, enterType, uint32(constant.EnterReasonConst.TransPoint), oldSceneId, oldPos)
g.SendMsg(proto.ApiPlayerEnterSceneNotify, userId, player.ClientSeq, playerEnterSceneNotify)
}
}
}
func (g *GameManager) PathfindingEnterSceneReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user pathfinding enter scene, user id: %v", userId)
g.SendMsg(proto.ApiPathfindingEnterSceneRsp, userId, player.ClientSeq, new(proto.PathfindingEnterSceneRsp))
}
func (g *GameManager) QueryPathReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
//logger.LOG.Debug("user query path, user id: %v", userId)
req := payloadMsg.(*proto.QueryPathReq)
// PacketQueryPathRsp
queryPathRsp := new(proto.QueryPathRsp)
queryPathRsp.Corners = []*proto.Vector{req.DestinationPos[0]}
queryPathRsp.QueryId = req.QueryId
queryPathRsp.QueryStatus = proto.QueryPathRsp_PATH_STATUS_TYPE_SUCC
g.SendMsg(proto.ApiQueryPathRsp, userId, player.ClientSeq, queryPathRsp)
}
func (g *GameManager) GetScenePointReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get scene point, user id: %v", userId)
req := payloadMsg.(*proto.GetScenePointReq)
// PacketGetScenePointRsp
getScenePointRsp := new(proto.GetScenePointRsp)
getScenePointRsp.SceneId = req.SceneId
getScenePointRsp.UnlockedPointList = make([]uint32, 0)
for i := uint32(1); i < 1000; i++ {
getScenePointRsp.UnlockedPointList = append(getScenePointRsp.UnlockedPointList, i)
}
getScenePointRsp.UnlockAreaList = make([]uint32, 0)
for i := uint32(1); i < 9; i++ {
getScenePointRsp.UnlockAreaList = append(getScenePointRsp.UnlockAreaList, i)
}
g.SendMsg(proto.ApiGetScenePointRsp, userId, player.ClientSeq, getScenePointRsp)
}
func (g *GameManager) GetSceneAreaReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get scene area, user id: %v", userId)
req := payloadMsg.(*proto.GetSceneAreaReq)
// PacketGetSceneAreaRsp
getSceneAreaRsp := new(proto.GetSceneAreaRsp)
getSceneAreaRsp.SceneId = req.SceneId
getSceneAreaRsp.AreaIdList = []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 100, 101, 102, 103, 200, 210, 300, 400, 401, 402, 403}
getSceneAreaRsp.CityInfoList = make([]*proto.CityInfo, 0)
getSceneAreaRsp.CityInfoList = append(getSceneAreaRsp.CityInfoList, &proto.CityInfo{CityId: 1, Level: 1})
getSceneAreaRsp.CityInfoList = append(getSceneAreaRsp.CityInfoList, &proto.CityInfo{CityId: 2, Level: 1})
getSceneAreaRsp.CityInfoList = append(getSceneAreaRsp.CityInfoList, &proto.CityInfo{CityId: 3, Level: 1})
g.SendMsg(proto.ApiGetSceneAreaRsp, userId, player.ClientSeq, getSceneAreaRsp)
}

View File

@@ -0,0 +1,416 @@
package game
import (
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
"game-hk4e/constant"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
"time"
)
func (g *GameManager) PlayerApplyEnterMpReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user apply enter world, user id: %v", userId)
req := payloadMsg.(*proto.PlayerApplyEnterMpReq)
targetUid := req.TargetUid
// PacketPlayerApplyEnterMpRsp
playerApplyEnterMpRsp := new(proto.PlayerApplyEnterMpRsp)
playerApplyEnterMpRsp.TargetUid = targetUid
g.SendMsg(proto.ApiPlayerApplyEnterMpRsp, player.PlayerID, player.ClientSeq, playerApplyEnterMpRsp)
ok := g.UserApplyEnterWorld(player, targetUid)
if !ok {
// PacketPlayerApplyEnterMpResultNotify
playerApplyEnterMpResultNotify := new(proto.PlayerApplyEnterMpResultNotify)
playerApplyEnterMpResultNotify.TargetUid = targetUid
playerApplyEnterMpResultNotify.TargetNickname = ""
playerApplyEnterMpResultNotify.IsAgreed = false
playerApplyEnterMpResultNotify.Reason = proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_CANNOT_ENTER_MP
g.SendMsg(proto.ApiPlayerApplyEnterMpResultNotify, player.PlayerID, player.ClientSeq, playerApplyEnterMpResultNotify)
}
}
func (g *GameManager) PlayerApplyEnterMpResultReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user deal world enter apply, user id: %v", userId)
req := payloadMsg.(*proto.PlayerApplyEnterMpResultReq)
applyUid := req.ApplyUid
isAgreed := req.IsAgreed
g.UserDealEnterWorld(player, applyUid, isAgreed)
// PacketPlayerApplyEnterMpResultRsp
playerApplyEnterMpResultRsp := new(proto.PlayerApplyEnterMpResultRsp)
playerApplyEnterMpResultRsp.ApplyUid = applyUid
playerApplyEnterMpResultRsp.IsAgreed = isAgreed
g.SendMsg(proto.ApiPlayerApplyEnterMpResultRsp, player.PlayerID, player.ClientSeq, playerApplyEnterMpResultRsp)
}
func (g *GameManager) PlayerGetForceQuitBanInfoReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get world exit ban info, user id: %v", userId)
result := true
world := g.worldManager.GetWorldByID(player.WorldId)
for _, worldPlayer := range world.playerMap {
if worldPlayer.SceneLoadState != model.SceneEnterDone {
result = false
}
}
// PacketPlayerGetForceQuitBanInfoRsp
playerGetForceQuitBanInfoRsp := new(proto.PlayerGetForceQuitBanInfoRsp)
if result {
playerGetForceQuitBanInfoRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SUCC)
} else {
playerGetForceQuitBanInfoRsp.Retcode = int32(proto.Retcode_RETCODE_RET_MP_TARGET_PLAYER_IN_TRANSFER)
}
g.SendMsg(proto.ApiPlayerGetForceQuitBanInfoRsp, player.PlayerID, player.ClientSeq, playerGetForceQuitBanInfoRsp)
}
func (g *GameManager) BackMyWorldReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user back world, user id: %v", userId)
// 其他玩家
ok := g.UserLeaveWorld(player)
// PacketBackMyWorldRsp
backMyWorldRsp := new(proto.BackMyWorldRsp)
if ok {
backMyWorldRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SUCC)
} else {
backMyWorldRsp.Retcode = int32(proto.Retcode_RETCODE_RET_MP_TARGET_PLAYER_IN_TRANSFER)
}
g.SendMsg(proto.ApiBackMyWorldRsp, player.PlayerID, player.ClientSeq, backMyWorldRsp)
}
func (g *GameManager) ChangeWorldToSingleModeReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user change world to single, user id: %v", userId)
// 房主
ok := g.UserLeaveWorld(player)
// PacketChangeWorldToSingleModeRsp
changeWorldToSingleModeRsp := new(proto.ChangeWorldToSingleModeRsp)
if ok {
changeWorldToSingleModeRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SUCC)
} else {
changeWorldToSingleModeRsp.Retcode = int32(proto.Retcode_RETCODE_RET_MP_TARGET_PLAYER_IN_TRANSFER)
}
g.SendMsg(proto.ApiChangeWorldToSingleModeRsp, player.PlayerID, player.ClientSeq, changeWorldToSingleModeRsp)
}
func (g *GameManager) SceneKickPlayerReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user kick player, user id: %v", userId)
req := payloadMsg.(*proto.SceneKickPlayerReq)
targetUid := req.TargetUid
targetPlayer := g.userManager.GetOnlineUser(targetUid)
ok := g.UserLeaveWorld(targetPlayer)
if ok {
// PacketSceneKickPlayerNotify
sceneKickPlayerNotify := new(proto.SceneKickPlayerNotify)
sceneKickPlayerNotify.TargetUid = targetUid
sceneKickPlayerNotify.KickerUid = player.PlayerID
world := g.worldManager.GetWorldByID(player.WorldId)
for _, worldPlayer := range world.playerMap {
g.SendMsg(proto.ApiSceneKickPlayerNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, sceneKickPlayerNotify)
}
}
// PacketSceneKickPlayerRsp
sceneKickPlayerRsp := new(proto.SceneKickPlayerRsp)
if ok {
sceneKickPlayerRsp.TargetUid = targetUid
} else {
sceneKickPlayerRsp.Retcode = int32(proto.Retcode_RETCODE_RET_MP_TARGET_PLAYER_IN_TRANSFER)
}
g.SendMsg(proto.ApiSceneKickPlayerRsp, player.PlayerID, player.ClientSeq, sceneKickPlayerRsp)
}
func (g *GameManager) UserApplyEnterWorld(player *model.Player, targetUid uint32) bool {
targetPlayer := g.userManager.GetOnlineUser(targetUid)
if targetPlayer == nil {
return false
}
world := g.worldManager.GetWorldByID(player.WorldId)
if world.multiplayer {
return false
}
applyTime, exist := targetPlayer.CoopApplyMap[player.PlayerID]
if exist && time.Now().UnixNano() < applyTime+int64(10*time.Second) {
return false
}
targetPlayer.CoopApplyMap[player.PlayerID] = time.Now().UnixNano()
targetWorld := g.worldManager.GetWorldByID(targetPlayer.WorldId)
if targetWorld.multiplayer && targetWorld.owner.PlayerID != targetPlayer.PlayerID {
return false
}
// PacketPlayerApplyEnterMpNotify
playerApplyEnterMpNotify := new(proto.PlayerApplyEnterMpNotify)
playerApplyEnterMpNotify.SrcPlayerInfo = g.PacketOnlinePlayerInfo(player)
g.SendMsg(proto.ApiPlayerApplyEnterMpNotify, targetPlayer.PlayerID, targetPlayer.ClientSeq, playerApplyEnterMpNotify)
return true
}
func (g *GameManager) UserDealEnterWorld(hostPlayer *model.Player, otherUid uint32, agree bool) {
otherPlayer := g.userManager.GetOnlineUser(otherUid)
if otherPlayer == nil {
return
}
applyTime, exist := hostPlayer.CoopApplyMap[otherUid]
if !exist || time.Now().UnixNano() > applyTime+int64(10*time.Second) {
return
}
delete(hostPlayer.CoopApplyMap, otherUid)
otherPlayerWorld := g.worldManager.GetWorldByID(otherPlayer.WorldId)
if otherPlayerWorld.multiplayer {
// PacketPlayerApplyEnterMpResultNotify
playerApplyEnterMpResultNotify := new(proto.PlayerApplyEnterMpResultNotify)
playerApplyEnterMpResultNotify.TargetUid = hostPlayer.PlayerID
playerApplyEnterMpResultNotify.TargetNickname = hostPlayer.NickName
playerApplyEnterMpResultNotify.IsAgreed = false
playerApplyEnterMpResultNotify.Reason = proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_CANNOT_ENTER_MP
g.SendMsg(proto.ApiPlayerApplyEnterMpResultNotify, otherPlayer.PlayerID, otherPlayer.ClientSeq, playerApplyEnterMpResultNotify)
return
}
// PacketPlayerApplyEnterMpResultNotify
playerApplyEnterMpResultNotify := new(proto.PlayerApplyEnterMpResultNotify)
playerApplyEnterMpResultNotify.TargetUid = hostPlayer.PlayerID
playerApplyEnterMpResultNotify.TargetNickname = hostPlayer.NickName
playerApplyEnterMpResultNotify.IsAgreed = agree
playerApplyEnterMpResultNotify.Reason = proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_JUDGE
g.SendMsg(proto.ApiPlayerApplyEnterMpResultNotify, otherPlayer.PlayerID, otherPlayer.ClientSeq, playerApplyEnterMpResultNotify)
if !agree {
return
}
hostWorld := g.worldManager.GetWorldByID(hostPlayer.WorldId)
if hostWorld.multiplayer == false {
g.UserWorldRemovePlayer(hostWorld, hostPlayer)
hostPlayer.TeamConfig.CurrTeamIndex = 3
hostPlayer.TeamConfig.CurrAvatarIndex = 0
// PacketPlayerEnterSceneNotify
hostPlayerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyMp(
hostPlayer,
hostPlayer,
proto.EnterType_ENTER_TYPE_SELF,
uint32(constant.EnterReasonConst.HostFromSingleToMp),
hostPlayer.SceneId,
hostPlayer.Pos,
)
g.SendMsg(proto.ApiPlayerEnterSceneNotify, hostPlayer.PlayerID, hostPlayer.ClientSeq, hostPlayerEnterSceneNotify)
hostWorld = g.worldManager.CreateWorld(hostPlayer, true)
g.UserWorldAddPlayer(hostWorld, hostPlayer)
hostPlayer.SceneLoadState = model.SceneNone
}
otherWorld := g.worldManager.GetWorldByID(otherPlayer.WorldId)
g.UserWorldRemovePlayer(otherWorld, otherPlayer)
otherPlayerOldSceneId := otherPlayer.SceneId
otherPlayerOldPos := &model.Vector{
X: otherPlayer.Pos.X,
Y: otherPlayer.Pos.Y,
Z: otherPlayer.Pos.Z,
}
otherPlayer.Pos = &model.Vector{
X: hostPlayer.Pos.X,
Y: hostPlayer.Pos.Y + 1,
Z: hostPlayer.Pos.Z,
}
otherPlayer.Rot = &model.Vector{
X: hostPlayer.Rot.X,
Y: hostPlayer.Rot.Y,
Z: hostPlayer.Rot.Z,
}
otherPlayer.SceneId = hostPlayer.SceneId
otherPlayer.TeamConfig.CurrTeamIndex = 3
otherPlayer.TeamConfig.CurrAvatarIndex = 0
// PacketPlayerEnterSceneNotify
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyMp(
otherPlayer,
hostPlayer,
proto.EnterType_ENTER_TYPE_OTHER,
uint32(constant.EnterReasonConst.TeamJoin),
otherPlayerOldSceneId,
otherPlayerOldPos,
)
g.SendMsg(proto.ApiPlayerEnterSceneNotify, otherPlayer.PlayerID, otherPlayer.ClientSeq, playerEnterSceneNotify)
g.UserWorldAddPlayer(hostWorld, otherPlayer)
otherPlayer.SceneLoadState = model.SceneNone
}
func (g *GameManager) UserLeaveWorld(player *model.Player) bool {
oldWorld := g.worldManager.GetWorldByID(player.WorldId)
if !oldWorld.multiplayer {
return false
}
for _, worldPlayer := range oldWorld.playerMap {
if worldPlayer.SceneLoadState != model.SceneEnterDone {
return false
}
}
g.UserWorldRemovePlayer(oldWorld, player)
//{
// newWorld := g.worldManager.CreateWorld(player, false)
// g.UserWorldAddPlayer(newWorld, player)
// player.SceneLoadState = model.SceneNone
//
// // PacketPlayerEnterSceneNotify
// enterReasonConst := constant.GetEnterReasonConst()
// playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyMp(
// player,
// player,
// proto.EnterType_ENTER_TYPE_SELF,
// uint32(enterReasonConst.TeamBack),
// player.SceneId,
// player.Pos,
// )
// g.SendMsg(proto.ApiPlayerEnterSceneNotify, player.PlayerID, player.ClientSeq, playerEnterSceneNotify)
//}
{
// PacketClientReconnectNotify
g.SendMsg(proto.ApiClientReconnectNotify, player.PlayerID, 0, new(proto.ClientReconnectNotify))
}
return true
}
func (g *GameManager) UserWorldAddPlayer(world *World, player *model.Player) {
_, exist := world.playerMap[player.PlayerID]
if exist {
return
}
world.AddPlayer(player, player.SceneId)
player.WorldId = world.id
if len(world.playerMap) > 1 {
g.UpdateWorldPlayerInfo(world, player)
}
}
func (g *GameManager) UserWorldRemovePlayer(world *World, player *model.Player) {
if world.multiplayer && player.PlayerID == world.owner.PlayerID {
// 多人世界房主离开剔除所有其他玩家
for _, worldPlayer := range world.playerMap {
if worldPlayer.PlayerID == world.owner.PlayerID {
continue
}
if ok := g.UserLeaveWorld(worldPlayer); !ok {
return
}
}
}
// PacketDelTeamEntityNotify
scene := world.GetSceneById(player.SceneId)
delTeamEntityNotify := g.PacketDelTeamEntityNotify(scene, player)
g.SendMsg(proto.ApiDelTeamEntityNotify, player.PlayerID, player.ClientSeq, delTeamEntityNotify)
if world.multiplayer {
// PlayerQuitFromMpNotify
playerQuitFromMpNotify := new(proto.PlayerQuitFromMpNotify)
playerQuitFromMpNotify.Reason = proto.PlayerQuitFromMpNotify_QUIT_REASON_BACK_TO_MY_WORLD
g.SendMsg(proto.ApiPlayerQuitFromMpNotify, player.PlayerID, player.ClientSeq, playerQuitFromMpNotify)
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
g.RemoveSceneEntityNotifyBroadcast(scene, []uint32{playerTeamEntity.avatarEntityMap[activeAvatarId]})
}
world.RemovePlayer(player)
player.WorldId = 0
if world.multiplayer && len(world.playerMap) > 0 {
g.UpdateWorldPlayerInfo(world, player)
}
if world.owner.PlayerID == player.PlayerID {
// 房主离开销毁世界
g.worldManager.DestroyWorld(world.id)
}
}
func (g *GameManager) UpdateWorldPlayerInfo(hostWorld *World, excludePlayer *model.Player) {
for _, worldPlayer := range hostWorld.playerMap {
if worldPlayer.PlayerID == excludePlayer.PlayerID || worldPlayer.SceneLoadState == model.SceneNone {
continue
}
// PacketSceneTeamUpdateNotify
sceneTeamUpdateNotify := g.PacketSceneTeamUpdateNotify(hostWorld)
g.SendMsg(proto.ApiSceneTeamUpdateNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, sceneTeamUpdateNotify)
// PacketWorldPlayerInfoNotify
worldPlayerInfoNotify := new(proto.WorldPlayerInfoNotify)
for _, subWorldPlayer := range hostWorld.playerMap {
onlinePlayerInfo := new(proto.OnlinePlayerInfo)
onlinePlayerInfo.Uid = subWorldPlayer.PlayerID
onlinePlayerInfo.Nickname = subWorldPlayer.NickName
onlinePlayerInfo.PlayerLevel = subWorldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]
onlinePlayerInfo.MpSettingType = proto.MpSettingType(subWorldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE])
onlinePlayerInfo.NameCardId = subWorldPlayer.NameCard
onlinePlayerInfo.Signature = subWorldPlayer.Signature
onlinePlayerInfo.ProfilePicture = &proto.ProfilePicture{AvatarId: subWorldPlayer.HeadImage}
onlinePlayerInfo.CurPlayerNumInWorld = uint32(len(hostWorld.playerMap))
worldPlayerInfoNotify.PlayerInfoList = append(worldPlayerInfoNotify.PlayerInfoList, onlinePlayerInfo)
worldPlayerInfoNotify.PlayerUidList = append(worldPlayerInfoNotify.PlayerUidList, subWorldPlayer.PlayerID)
}
g.SendMsg(proto.ApiWorldPlayerInfoNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, worldPlayerInfoNotify)
// PacketScenePlayerInfoNotify
scenePlayerInfoNotify := new(proto.ScenePlayerInfoNotify)
for _, subWorldPlayer := range hostWorld.playerMap {
onlinePlayerInfo := new(proto.OnlinePlayerInfo)
onlinePlayerInfo.Uid = subWorldPlayer.PlayerID
onlinePlayerInfo.Nickname = subWorldPlayer.NickName
onlinePlayerInfo.PlayerLevel = subWorldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]
onlinePlayerInfo.MpSettingType = proto.MpSettingType(subWorldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE])
onlinePlayerInfo.NameCardId = subWorldPlayer.NameCard
onlinePlayerInfo.Signature = subWorldPlayer.Signature
onlinePlayerInfo.ProfilePicture = &proto.ProfilePicture{AvatarId: subWorldPlayer.HeadImage}
onlinePlayerInfo.CurPlayerNumInWorld = uint32(len(hostWorld.playerMap))
scenePlayerInfoNotify.PlayerInfoList = append(scenePlayerInfoNotify.PlayerInfoList, &proto.ScenePlayerInfo{
Uid: subWorldPlayer.PlayerID,
PeerId: subWorldPlayer.PeerId,
Name: subWorldPlayer.NickName,
SceneId: subWorldPlayer.SceneId,
OnlinePlayerInfo: onlinePlayerInfo,
})
}
g.SendMsg(proto.ApiScenePlayerInfoNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, scenePlayerInfoNotify)
// PacketSyncTeamEntityNotify
syncTeamEntityNotify := new(proto.SyncTeamEntityNotify)
syncTeamEntityNotify.SceneId = worldPlayer.SceneId
syncTeamEntityNotify.TeamEntityInfoList = make([]*proto.TeamEntityInfo, 0)
if hostWorld.multiplayer {
for _, subWorldPlayer := range hostWorld.playerMap {
if subWorldPlayer.PlayerID == worldPlayer.PlayerID {
continue
}
subWorldPlayerScene := hostWorld.GetSceneById(subWorldPlayer.SceneId)
subWorldPlayerTeamEntity := subWorldPlayerScene.GetPlayerTeamEntity(subWorldPlayer.PlayerID)
teamEntityInfo := &proto.TeamEntityInfo{
TeamEntityId: subWorldPlayerTeamEntity.teamEntityId,
AuthorityPeerId: subWorldPlayer.PeerId,
TeamAbilityInfo: new(proto.AbilitySyncStateInfo),
}
syncTeamEntityNotify.TeamEntityInfoList = append(syncTeamEntityNotify.TeamEntityInfoList, teamEntityInfo)
}
}
g.SendMsg(proto.ApiSyncTeamEntityNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, syncTeamEntityNotify)
// PacketSyncScenePlayTeamEntityNotify
syncScenePlayTeamEntityNotify := new(proto.SyncScenePlayTeamEntityNotify)
syncScenePlayTeamEntityNotify.SceneId = worldPlayer.SceneId
g.SendMsg(proto.ApiSyncScenePlayTeamEntityNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, syncScenePlayTeamEntityNotify)
}
}

View File

@@ -0,0 +1,710 @@
package game
import (
"flswld.com/common/utils/object"
"flswld.com/common/utils/random"
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
gdc "game-hk4e/config"
"game-hk4e/constant"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
"strconv"
"time"
)
func (g *GameManager) EnterSceneReadyReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user enter scene ready, user id: %v", userId)
// PacketEnterScenePeerNotify
enterScenePeerNotify := new(proto.EnterScenePeerNotify)
enterScenePeerNotify.DestSceneId = player.SceneId
world := g.worldManager.GetWorldByID(player.WorldId)
enterScenePeerNotify.PeerId = player.PeerId
enterScenePeerNotify.HostPeerId = world.owner.PeerId
enterScenePeerNotify.EnterSceneToken = player.EnterSceneToken
g.SendMsg(proto.ApiEnterScenePeerNotify, userId, player.ClientSeq, enterScenePeerNotify)
// PacketEnterSceneReadyRsp
enterSceneReadyRsp := new(proto.EnterSceneReadyRsp)
enterSceneReadyRsp.EnterSceneToken = player.EnterSceneToken
g.SendMsg(proto.ApiEnterSceneReadyRsp, userId, player.ClientSeq, enterSceneReadyRsp)
}
func (g *GameManager) SceneInitFinishReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user scene init finish, user id: %v", userId)
// PacketServerTimeNotify
serverTimeNotify := new(proto.ServerTimeNotify)
serverTimeNotify.ServerTime = uint64(time.Now().UnixMilli())
g.SendMsg(proto.ApiServerTimeNotify, userId, player.ClientSeq, serverTimeNotify)
// PacketWorldPlayerInfoNotify
worldPlayerInfoNotify := new(proto.WorldPlayerInfoNotify)
world := g.worldManager.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId)
for _, worldPlayer := range world.playerMap {
onlinePlayerInfo := new(proto.OnlinePlayerInfo)
onlinePlayerInfo.Uid = worldPlayer.PlayerID
onlinePlayerInfo.Nickname = worldPlayer.NickName
onlinePlayerInfo.PlayerLevel = worldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]
onlinePlayerInfo.MpSettingType = proto.MpSettingType(worldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE])
onlinePlayerInfo.NameCardId = worldPlayer.NameCard
onlinePlayerInfo.Signature = worldPlayer.Signature
onlinePlayerInfo.ProfilePicture = &proto.ProfilePicture{AvatarId: worldPlayer.HeadImage}
onlinePlayerInfo.CurPlayerNumInWorld = uint32(len(world.playerMap))
worldPlayerInfoNotify.PlayerInfoList = append(worldPlayerInfoNotify.PlayerInfoList, onlinePlayerInfo)
worldPlayerInfoNotify.PlayerUidList = append(worldPlayerInfoNotify.PlayerUidList, worldPlayer.PlayerID)
}
g.SendMsg(proto.ApiWorldPlayerInfoNotify, userId, player.ClientSeq, worldPlayerInfoNotify)
// PacketWorldDataNotify
worldDataNotify := new(proto.WorldDataNotify)
worldDataNotify.WorldPropMap = make(map[uint32]*proto.PropValue)
// 世界等级
worldDataNotify.WorldPropMap[1] = &proto.PropValue{
Type: 1,
Val: int64(world.worldLevel),
Value: &proto.PropValue_Ival{Ival: int64(world.worldLevel)},
}
// 是否多人游戏
worldDataNotify.WorldPropMap[2] = &proto.PropValue{
Type: 2,
Val: object.ConvBoolToInt64(world.multiplayer),
Value: &proto.PropValue_Ival{Ival: object.ConvBoolToInt64(world.multiplayer)},
}
g.SendMsg(proto.ApiWorldDataNotify, userId, player.ClientSeq, worldDataNotify)
// PacketPlayerWorldSceneInfoListNotify
playerWorldSceneInfoListNotify := new(proto.PlayerWorldSceneInfoListNotify)
playerWorldSceneInfoListNotify.InfoList = []*proto.PlayerWorldSceneInfo{
{SceneId: 1, IsLocked: false, SceneTagIdList: []uint32{}},
{SceneId: 3, IsLocked: false, SceneTagIdList: []uint32{102, 113, 117}},
{SceneId: 4, IsLocked: false, SceneTagIdList: []uint32{106, 109, 117}},
{SceneId: 5, IsLocked: false, SceneTagIdList: []uint32{}},
{SceneId: 6, IsLocked: false, SceneTagIdList: []uint32{}},
{SceneId: 7, IsLocked: false, SceneTagIdList: []uint32{}},
}
xumi := &proto.PlayerWorldSceneInfo{
SceneId: 9,
IsLocked: false,
SceneTagIdList: []uint32{},
}
for i := 0; i < 3000; i++ {
xumi.SceneTagIdList = append(xumi.SceneTagIdList, uint32(i))
}
playerWorldSceneInfoListNotify.InfoList = append(playerWorldSceneInfoListNotify.InfoList, xumi)
g.SendMsg(proto.ApiPlayerWorldSceneInfoListNotify, userId, player.ClientSeq, playerWorldSceneInfoListNotify)
// SceneForceUnlockNotify
g.SendMsg(proto.ApiSceneForceUnlockNotify, userId, player.ClientSeq, new(proto.SceneForceUnlockNotify))
// PacketHostPlayerNotify
hostPlayerNotify := new(proto.HostPlayerNotify)
hostPlayerNotify.HostUid = world.owner.PlayerID
hostPlayerNotify.HostPeerId = world.owner.PeerId
g.SendMsg(proto.ApiHostPlayerNotify, userId, player.ClientSeq, hostPlayerNotify)
// PacketSceneTimeNotify
sceneTimeNotify := new(proto.SceneTimeNotify)
sceneTimeNotify.SceneId = player.SceneId
sceneTimeNotify.SceneTime = uint64(scene.GetSceneTime())
g.SendMsg(proto.ApiSceneTimeNotify, userId, player.ClientSeq, sceneTimeNotify)
// PacketPlayerGameTimeNotify
playerGameTimeNotify := new(proto.PlayerGameTimeNotify)
playerGameTimeNotify.GameTime = scene.gameTime
playerGameTimeNotify.Uid = player.PlayerID
g.SendMsg(proto.ApiPlayerGameTimeNotify, userId, player.ClientSeq, playerGameTimeNotify)
// PacketPlayerEnterSceneInfoNotify
empty := new(proto.AbilitySyncStateInfo)
playerEnterSceneInfoNotify := new(proto.PlayerEnterSceneInfoNotify)
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
playerEnterSceneInfoNotify.CurAvatarEntityId = playerTeamEntity.avatarEntityMap[activeAvatarId]
playerEnterSceneInfoNotify.EnterSceneToken = player.EnterSceneToken
playerEnterSceneInfoNotify.TeamEnterInfo = &proto.TeamEnterSceneInfo{
TeamEntityId: playerTeamEntity.teamEntityId,
TeamAbilityInfo: empty,
AbilityControlBlock: new(proto.AbilityControlBlock),
}
playerEnterSceneInfoNotify.MpLevelEntityInfo = &proto.MPLevelEntityInfo{
EntityId: g.worldManager.GetWorldByID(player.WorldId).mpLevelEntityId,
AuthorityPeerId: g.worldManager.GetWorldByID(player.WorldId).owner.PeerId,
AbilityInfo: empty,
}
activeTeam := player.TeamConfig.GetActiveTeam()
for _, avatarId := range activeTeam.AvatarIdList {
if avatarId == 0 {
break
}
avatar := player.AvatarMap[avatarId]
avatarEnterSceneInfo := new(proto.AvatarEnterSceneInfo)
avatarEnterSceneInfo.AvatarGuid = avatar.Guid
avatarEnterSceneInfo.AvatarEntityId = playerTeamEntity.avatarEntityMap[avatarId]
avatarEnterSceneInfo.WeaponGuid = avatar.EquipWeapon.Guid
avatarEnterSceneInfo.WeaponEntityId = playerTeamEntity.weaponEntityMap[avatar.EquipWeapon.WeaponId]
avatarEnterSceneInfo.AvatarAbilityInfo = empty
avatarEnterSceneInfo.WeaponAbilityInfo = empty
playerEnterSceneInfoNotify.AvatarEnterInfo = append(playerEnterSceneInfoNotify.AvatarEnterInfo, avatarEnterSceneInfo)
}
g.SendMsg(proto.ApiPlayerEnterSceneInfoNotify, userId, player.ClientSeq, playerEnterSceneInfoNotify)
// PacketSceneAreaWeatherNotify
sceneAreaWeatherNotify := new(proto.SceneAreaWeatherNotify)
sceneAreaWeatherNotify.WeatherAreaId = 0
sceneAreaWeatherNotify.ClimateType = uint32(constant.ClimateTypeConst.CLIMATE_SUNNY)
g.SendMsg(proto.ApiSceneAreaWeatherNotify, userId, player.ClientSeq, sceneAreaWeatherNotify)
// PacketScenePlayerInfoNotify
scenePlayerInfoNotify := new(proto.ScenePlayerInfoNotify)
for _, worldPlayer := range world.playerMap {
onlinePlayerInfo := new(proto.OnlinePlayerInfo)
onlinePlayerInfo.Uid = worldPlayer.PlayerID
onlinePlayerInfo.Nickname = worldPlayer.NickName
onlinePlayerInfo.PlayerLevel = worldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]
onlinePlayerInfo.MpSettingType = proto.MpSettingType(worldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE])
onlinePlayerInfo.NameCardId = worldPlayer.NameCard
onlinePlayerInfo.Signature = worldPlayer.Signature
onlinePlayerInfo.ProfilePicture = &proto.ProfilePicture{AvatarId: worldPlayer.HeadImage}
onlinePlayerInfo.CurPlayerNumInWorld = uint32(len(world.playerMap))
scenePlayerInfoNotify.PlayerInfoList = append(scenePlayerInfoNotify.PlayerInfoList, &proto.ScenePlayerInfo{
Uid: worldPlayer.PlayerID,
PeerId: worldPlayer.PeerId,
Name: worldPlayer.NickName,
SceneId: worldPlayer.SceneId,
OnlinePlayerInfo: onlinePlayerInfo,
})
}
g.SendMsg(proto.ApiScenePlayerInfoNotify, userId, player.ClientSeq, scenePlayerInfoNotify)
// PacketSceneTeamUpdateNotify
sceneTeamUpdateNotify := g.PacketSceneTeamUpdateNotify(world)
g.SendMsg(proto.ApiSceneTeamUpdateNotify, userId, player.ClientSeq, sceneTeamUpdateNotify)
// PacketSyncTeamEntityNotify
syncTeamEntityNotify := new(proto.SyncTeamEntityNotify)
syncTeamEntityNotify.SceneId = player.SceneId
syncTeamEntityNotify.TeamEntityInfoList = make([]*proto.TeamEntityInfo, 0)
if world.multiplayer {
for _, worldPlayer := range world.playerMap {
if worldPlayer.PlayerID == player.PlayerID {
continue
}
worldPlayerScene := world.GetSceneById(worldPlayer.SceneId)
worldPlayerTeamEntity := worldPlayerScene.GetPlayerTeamEntity(worldPlayer.PlayerID)
teamEntityInfo := &proto.TeamEntityInfo{
TeamEntityId: worldPlayerTeamEntity.teamEntityId,
AuthorityPeerId: worldPlayer.PeerId,
TeamAbilityInfo: new(proto.AbilitySyncStateInfo),
}
syncTeamEntityNotify.TeamEntityInfoList = append(syncTeamEntityNotify.TeamEntityInfoList, teamEntityInfo)
}
}
g.SendMsg(proto.ApiSyncTeamEntityNotify, userId, player.ClientSeq, syncTeamEntityNotify)
// PacketSyncScenePlayTeamEntityNotify
syncScenePlayTeamEntityNotify := new(proto.SyncScenePlayTeamEntityNotify)
syncScenePlayTeamEntityNotify.SceneId = player.SceneId
g.SendMsg(proto.ApiSyncScenePlayTeamEntityNotify, userId, player.ClientSeq, syncScenePlayTeamEntityNotify)
// PacketSceneInitFinishRsp
SceneInitFinishRsp := new(proto.SceneInitFinishRsp)
SceneInitFinishRsp.EnterSceneToken = player.EnterSceneToken
g.SendMsg(proto.ApiSceneInitFinishRsp, userId, player.ClientSeq, SceneInitFinishRsp)
player.SceneLoadState = model.SceneInitFinish
}
func (g *GameManager) EnterSceneDoneReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user enter scene done, user id: %v", userId)
// PacketEnterSceneDoneRsp
enterSceneDoneRsp := new(proto.EnterSceneDoneRsp)
enterSceneDoneRsp.EnterSceneToken = player.EnterSceneToken
g.SendMsg(proto.ApiEnterSceneDoneRsp, userId, player.ClientSeq, enterSceneDoneRsp)
// PacketPlayerTimeNotify
playerTimeNotify := new(proto.PlayerTimeNotify)
playerTimeNotify.IsPaused = player.Pause
playerTimeNotify.PlayerTime = uint64(player.TotalOnlineTime)
playerTimeNotify.ServerTime = uint64(time.Now().UnixMilli())
g.SendMsg(proto.ApiPlayerTimeNotify, userId, player.ClientSeq, playerTimeNotify)
player.SceneLoadState = model.SceneEnterDone
world := g.worldManager.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId)
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
g.AddSceneEntityNotify(player, proto.VisionType_VISION_TYPE_BORN, []uint32{playerTeamEntity.avatarEntityMap[activeAvatarId]}, true)
// 通过aoi获取场景中在自己周围格子里的全部实体id
entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
g.AddSceneEntityNotify(player, proto.VisionType_VISION_TYPE_MEET, entityIdList, false)
}
func (g *GameManager) PostEnterSceneReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user post enter scene, user id: %v", userId)
// PacketPostEnterSceneRsp
postEnterSceneRsp := new(proto.PostEnterSceneRsp)
postEnterSceneRsp.EnterSceneToken = player.EnterSceneToken
g.SendMsg(proto.ApiPostEnterSceneRsp, userId, player.ClientSeq, postEnterSceneRsp)
}
func (g *GameManager) EnterWorldAreaReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user enter world area, user id: %v", userId)
req := payloadMsg.(*proto.EnterWorldAreaReq)
// PacketEnterWorldAreaRsp
enterWorldAreaRsp := new(proto.EnterWorldAreaRsp)
enterWorldAreaRsp.AreaType = req.AreaType
enterWorldAreaRsp.AreaId = req.AreaId
g.SendMsg(proto.ApiEnterWorldAreaRsp, userId, player.ClientSeq, enterWorldAreaRsp)
}
func (g *GameManager) ChangeGameTimeReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user change game time, user id: %v", userId)
req := payloadMsg.(*proto.ChangeGameTimeReq)
gameTime := req.GameTime
world := g.worldManager.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId)
scene.ChangeGameTime(gameTime)
for _, scenePlayer := range scene.playerMap {
// PacketPlayerGameTimeNotify
playerGameTimeNotify := new(proto.PlayerGameTimeNotify)
playerGameTimeNotify.GameTime = scene.gameTime
playerGameTimeNotify.Uid = scenePlayer.PlayerID
g.SendMsg(proto.ApiPlayerGameTimeNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, playerGameTimeNotify)
}
// PacketChangeGameTimeRsp
changeGameTimeRsp := new(proto.ChangeGameTimeRsp)
changeGameTimeRsp.CurGameTime = scene.gameTime
g.SendMsg(proto.ApiChangeGameTimeRsp, userId, player.ClientSeq, changeGameTimeRsp)
}
func (g *GameManager) PacketPlayerEnterSceneNotify(player *model.Player) *proto.PlayerEnterSceneNotify {
player.EnterSceneToken = uint32(random.GetRandomInt32(1000, 99999))
playerEnterSceneNotify := new(proto.PlayerEnterSceneNotify)
playerEnterSceneNotify.SceneId = player.SceneId
playerEnterSceneNotify.Pos = &proto.Vector{X: float32(player.Pos.X), Y: float32(player.Pos.Y), Z: float32(player.Pos.Z)}
playerEnterSceneNotify.SceneBeginTime = uint64(time.Now().UnixMilli())
playerEnterSceneNotify.Type = proto.EnterType_ENTER_TYPE_SELF
playerEnterSceneNotify.TargetUid = player.PlayerID
playerEnterSceneNotify.EnterSceneToken = player.EnterSceneToken
playerEnterSceneNotify.WorldLevel = player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL]
playerEnterSceneNotify.EnterReason = uint32(constant.EnterReasonConst.Login)
// 刚登录进入场景的时候才为true
playerEnterSceneNotify.IsFirstLoginEnterScene = true
playerEnterSceneNotify.WorldType = 1
playerEnterSceneNotify.SceneTransaction = strconv.Itoa(int(player.SceneId)) + "-" +
strconv.Itoa(int(player.PlayerID)) + "-" +
strconv.Itoa(int(time.Now().Unix())) + "-" +
"18402"
return playerEnterSceneNotify
}
func (g *GameManager) PacketPlayerEnterSceneNotifyTp(
player *model.Player,
enterType proto.EnterType,
enterReason uint32,
prevSceneId uint32,
prevPos *model.Vector,
) *proto.PlayerEnterSceneNotify {
return g.PacketPlayerEnterSceneNotifyMp(player, player, enterType, enterReason, prevSceneId, prevPos)
}
func (g *GameManager) PacketPlayerEnterSceneNotifyMp(
player *model.Player,
targetPlayer *model.Player,
enterType proto.EnterType,
enterReason uint32,
prevSceneId uint32,
prevPos *model.Vector,
) *proto.PlayerEnterSceneNotify {
player.EnterSceneToken = uint32(random.GetRandomInt32(1000, 99999))
playerEnterSceneNotify := new(proto.PlayerEnterSceneNotify)
playerEnterSceneNotify.PrevSceneId = prevSceneId
playerEnterSceneNotify.PrevPos = &proto.Vector{X: float32(prevPos.X), Y: float32(prevPos.Y), Z: float32(prevPos.Z)}
playerEnterSceneNotify.SceneId = player.SceneId
playerEnterSceneNotify.Pos = &proto.Vector{X: float32(player.Pos.X), Y: float32(player.Pos.Y), Z: float32(player.Pos.Z)}
playerEnterSceneNotify.SceneBeginTime = uint64(time.Now().UnixMilli())
playerEnterSceneNotify.Type = enterType
playerEnterSceneNotify.TargetUid = targetPlayer.PlayerID
playerEnterSceneNotify.EnterSceneToken = player.EnterSceneToken
playerEnterSceneNotify.WorldLevel = targetPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL]
playerEnterSceneNotify.EnterReason = enterReason
playerEnterSceneNotify.WorldType = 1
playerEnterSceneNotify.SceneTransaction = strconv.Itoa(int(player.SceneId)) + "-" +
strconv.Itoa(int(targetPlayer.PlayerID)) + "-" +
strconv.Itoa(int(time.Now().Unix())) + "-" +
"18402"
//playerEnterSceneNotify.SceneTagIdList = []uint32{102, 107, 109, 113, 117}
playerEnterSceneNotify.SceneTagIdList = make([]uint32, 0)
for sceneTagId := uint32(0); sceneTagId < 3000; sceneTagId++ {
playerEnterSceneNotify.SceneTagIdList = append(playerEnterSceneNotify.SceneTagIdList, sceneTagId)
}
return playerEnterSceneNotify
}
func (g *GameManager) AddSceneEntityNotifyToPlayer(player *model.Player, visionType proto.VisionType, entityList []*proto.SceneEntityInfo) {
// PacketSceneEntityAppearNotify
sceneEntityAppearNotify := new(proto.SceneEntityAppearNotify)
sceneEntityAppearNotify.AppearType = visionType
sceneEntityAppearNotify.EntityList = entityList
g.SendMsg(proto.ApiSceneEntityAppearNotify, player.PlayerID, player.ClientSeq, sceneEntityAppearNotify)
logger.LOG.Debug("SceneEntityAppearNotify, uid: %v, type: %v, len: %v",
player.PlayerID, sceneEntityAppearNotify.AppearType, len(sceneEntityAppearNotify.EntityList))
}
func (g *GameManager) AddSceneEntityNotifyBroadcast(scene *Scene, visionType proto.VisionType, entityList []*proto.SceneEntityInfo) {
// PacketSceneEntityAppearNotify
sceneEntityAppearNotify := new(proto.SceneEntityAppearNotify)
sceneEntityAppearNotify.AppearType = visionType
sceneEntityAppearNotify.EntityList = entityList
for _, scenePlayer := range scene.playerMap {
g.SendMsg(proto.ApiSceneEntityAppearNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, sceneEntityAppearNotify)
logger.LOG.Debug("SceneEntityAppearNotify, uid: %v, type: %v, len: %v",
scenePlayer.PlayerID, sceneEntityAppearNotify.AppearType, len(sceneEntityAppearNotify.EntityList))
}
}
func (g *GameManager) RemoveSceneEntityNotifyToPlayer(player *model.Player, entityIdList []uint32) {
// PacketSceneEntityDisappearNotify
sceneEntityDisappearNotify := new(proto.SceneEntityDisappearNotify)
sceneEntityDisappearNotify.EntityList = entityIdList
sceneEntityDisappearNotify.DisappearType = proto.VisionType_VISION_TYPE_REMOVE
g.SendMsg(proto.ApiSceneEntityDisappearNotify, player.PlayerID, player.ClientSeq, sceneEntityDisappearNotify)
logger.LOG.Debug("SceneEntityDisappearNotify, uid: %v, type: %v, len: %v",
player.PlayerID, sceneEntityDisappearNotify.DisappearType, len(sceneEntityDisappearNotify.EntityList))
}
func (g *GameManager) RemoveSceneEntityNotifyBroadcast(scene *Scene, entityIdList []uint32) {
// PacketSceneEntityDisappearNotify
sceneEntityDisappearNotify := new(proto.SceneEntityDisappearNotify)
sceneEntityDisappearNotify.EntityList = entityIdList
sceneEntityDisappearNotify.DisappearType = proto.VisionType_VISION_TYPE_REMOVE
for _, scenePlayer := range scene.playerMap {
g.SendMsg(proto.ApiSceneEntityDisappearNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, sceneEntityDisappearNotify)
logger.LOG.Debug("SceneEntityDisappearNotify, uid: %v, type: %v, len: %v",
scenePlayer.PlayerID, sceneEntityDisappearNotify.DisappearType, len(sceneEntityDisappearNotify.EntityList))
}
}
func (g *GameManager) AddSceneEntityNotify(player *model.Player, visionType proto.VisionType, entityIdList []uint32, broadcast bool) {
world := g.worldManager.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId)
entityList := make([]*proto.SceneEntityInfo, 0)
for _, entityId := range entityIdList {
entity := scene.entityMap[entityId]
if entity == nil {
logger.LOG.Error("get entity is nil, entityId: %v", entityId)
continue
}
switch entity.entityType {
case uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_AVATAR):
if visionType == proto.VisionType_VISION_TYPE_MEET && entity.avatarEntity.uid == player.PlayerID {
continue
}
scenePlayer := g.userManager.GetOnlineUser(entity.avatarEntity.uid)
if scenePlayer == nil {
logger.LOG.Error("get scene player is nil, world id: %v, scene id: %v", world.id, scene.id)
continue
}
if scenePlayer.SceneLoadState != model.SceneEnterDone {
continue
}
if entity.avatarEntity.avatarId != scenePlayer.TeamConfig.GetActiveAvatarId() {
continue
}
sceneEntityInfoAvatar := g.PacketSceneEntityInfoAvatar(scene, scenePlayer, scenePlayer.TeamConfig.GetActiveAvatarId())
entityList = append(entityList, sceneEntityInfoAvatar)
case uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_WEAPON):
case uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER):
sceneEntityInfoMonster := g.PacketSceneEntityInfoMonster(scene, entity.id)
entityList = append(entityList, sceneEntityInfoMonster)
case uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_GADGET):
sceneEntityInfoGadget := g.PacketSceneEntityInfoGadget(scene, entity.id)
entityList = append(entityList, sceneEntityInfoGadget)
}
}
if broadcast {
g.AddSceneEntityNotifyBroadcast(scene, visionType, entityList)
} else {
g.AddSceneEntityNotifyToPlayer(player, visionType, entityList)
}
}
func (g *GameManager) PacketFightPropMapToPbFightPropList(fightPropMap map[uint32]float32) []*proto.FightPropPair {
fightPropList := []*proto.FightPropPair{
{
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_HP),
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_HP)],
},
{
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_ATTACK),
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_ATTACK)],
},
{
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_DEFENSE),
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_DEFENSE)],
},
{
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL),
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL)],
},
{
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL_HURT),
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL_HURT)],
},
{
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_CHARGE_EFFICIENCY),
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CHARGE_EFFICIENCY)],
},
{
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP),
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP)],
},
{
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP),
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP)],
},
{
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK),
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK)],
},
{
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_DEFENSE),
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_DEFENSE)],
},
}
return fightPropList
}
func (g *GameManager) PacketSceneEntityInfoAvatar(scene *Scene, player *model.Player, avatarId uint32) *proto.SceneEntityInfo {
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
entity := scene.GetEntity(playerTeamEntity.avatarEntityMap[avatarId])
if entity == nil {
return new(proto.SceneEntityInfo)
}
sceneEntityInfo := &proto.SceneEntityInfo{
EntityType: proto.ProtEntityType_PROT_ENTITY_TYPE_AVATAR,
EntityId: entity.id,
MotionInfo: &proto.MotionInfo{
Pos: &proto.Vector{
X: float32(entity.pos.X),
Y: float32(entity.pos.Y),
Z: float32(entity.pos.Z),
},
Rot: &proto.Vector{
X: float32(entity.rot.X),
Y: float32(entity.rot.Y),
Z: float32(entity.rot.Z),
},
Speed: &proto.Vector{},
State: proto.MotionState(entity.moveState),
},
PropList: []*proto.PropPair{{Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL), PropValue: &proto.PropValue{
Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL),
Value: &proto.PropValue_Ival{Ival: int64(entity.level)},
Val: int64(entity.level),
}}},
FightPropList: g.PacketFightPropMapToPbFightPropList(entity.fightProp),
LifeState: 1,
AnimatorParaList: make([]*proto.AnimatorParameterValueInfoPair, 0),
Entity: &proto.SceneEntityInfo_Avatar{
Avatar: g.PacketSceneAvatarInfo(scene, player, avatarId),
},
EntityClientData: new(proto.EntityClientData),
EntityAuthorityInfo: &proto.EntityAuthorityInfo{
AbilityInfo: new(proto.AbilitySyncStateInfo),
RendererChangedInfo: new(proto.EntityRendererChangedInfo),
AiInfo: &proto.SceneEntityAiInfo{
IsAiOpen: true,
BornPos: new(proto.Vector),
},
BornPos: new(proto.Vector),
},
LastMoveSceneTimeMs: entity.lastMoveSceneTimeMs,
LastMoveReliableSeq: entity.lastMoveReliableSeq,
}
return sceneEntityInfo
}
func (g *GameManager) PacketSceneEntityInfoMonster(scene *Scene, entityId uint32) *proto.SceneEntityInfo {
entity := scene.GetEntity(entityId)
if entity == nil {
return new(proto.SceneEntityInfo)
}
pos := &proto.Vector{
X: float32(entity.pos.X),
Y: float32(entity.pos.Y),
Z: float32(entity.pos.Z),
}
sceneEntityInfo := &proto.SceneEntityInfo{
EntityType: proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER,
EntityId: entity.id,
MotionInfo: &proto.MotionInfo{
Pos: pos,
Rot: &proto.Vector{
X: float32(entity.rot.X),
Y: float32(entity.rot.Y),
Z: float32(entity.rot.Z),
},
Speed: &proto.Vector{},
State: proto.MotionState(entity.moveState),
},
PropList: []*proto.PropPair{{Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL), PropValue: &proto.PropValue{
Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL),
Value: &proto.PropValue_Ival{Ival: int64(entity.level)},
Val: int64(entity.level),
}}},
FightPropList: g.PacketFightPropMapToPbFightPropList(entity.fightProp),
LifeState: 1,
AnimatorParaList: make([]*proto.AnimatorParameterValueInfoPair, 0),
Entity: &proto.SceneEntityInfo_Monster{
Monster: g.PacketSceneMonsterInfo(),
},
EntityClientData: new(proto.EntityClientData),
EntityAuthorityInfo: &proto.EntityAuthorityInfo{
AbilityInfo: new(proto.AbilitySyncStateInfo),
RendererChangedInfo: new(proto.EntityRendererChangedInfo),
AiInfo: &proto.SceneEntityAiInfo{
IsAiOpen: true,
BornPos: pos,
},
BornPos: pos,
},
}
return sceneEntityInfo
}
func (g *GameManager) PacketSceneEntityInfoGadget(scene *Scene, entityId uint32) *proto.SceneEntityInfo {
entity := scene.GetEntity(entityId)
if entity == nil {
return new(proto.SceneEntityInfo)
}
sceneEntityInfo := &proto.SceneEntityInfo{
EntityType: proto.ProtEntityType_PROT_ENTITY_TYPE_GADGET,
EntityId: entity.id,
MotionInfo: &proto.MotionInfo{
Pos: &proto.Vector{
X: float32(entity.pos.X),
Y: float32(entity.pos.Y),
Z: float32(entity.pos.Z),
},
Rot: &proto.Vector{
X: float32(entity.rot.X),
Y: float32(entity.rot.Y),
Z: float32(entity.rot.Z),
},
Speed: &proto.Vector{},
State: proto.MotionState(entity.moveState),
},
PropList: []*proto.PropPair{{Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL), PropValue: &proto.PropValue{
Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL),
Value: &proto.PropValue_Ival{Ival: int64(1)},
Val: int64(1),
}}},
FightPropList: g.PacketFightPropMapToPbFightPropList(entity.fightProp),
LifeState: 1,
AnimatorParaList: make([]*proto.AnimatorParameterValueInfoPair, 0),
Entity: &proto.SceneEntityInfo_Gadget{
Gadget: g.PacketSceneGadgetInfo(entity.gadgetEntity.gatherId),
},
EntityClientData: new(proto.EntityClientData),
EntityAuthorityInfo: &proto.EntityAuthorityInfo{
AbilityInfo: new(proto.AbilitySyncStateInfo),
RendererChangedInfo: new(proto.EntityRendererChangedInfo),
AiInfo: &proto.SceneEntityAiInfo{
IsAiOpen: true,
BornPos: new(proto.Vector),
},
BornPos: new(proto.Vector),
},
}
return sceneEntityInfo
}
func (g *GameManager) PacketSceneAvatarInfo(scene *Scene, player *model.Player, avatarId uint32) *proto.SceneAvatarInfo {
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
activeAvatar := player.AvatarMap[activeAvatarId]
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
equipIdList := make([]uint32, 0)
weapon := player.AvatarMap[avatarId].EquipWeapon
equipIdList = append(equipIdList, weapon.ItemId)
for _, reliquary := range player.AvatarMap[avatarId].EquipReliquaryList {
equipIdList = append(equipIdList, reliquary.ItemId)
}
sceneAvatarInfo := &proto.SceneAvatarInfo{
Uid: player.PlayerID,
AvatarId: avatarId,
Guid: player.AvatarMap[avatarId].Guid,
PeerId: player.PeerId,
EquipIdList: equipIdList,
SkillDepotId: player.AvatarMap[avatarId].SkillDepotId,
Weapon: &proto.SceneWeaponInfo{
EntityId: playerTeamEntity.weaponEntityMap[activeAvatar.EquipWeapon.WeaponId],
GadgetId: uint32(gdc.CONF.ItemDataMap[int32(weapon.ItemId)].GadgetId),
ItemId: weapon.ItemId,
Guid: weapon.Guid,
Level: uint32(weapon.Level),
AbilityInfo: new(proto.AbilitySyncStateInfo),
},
ReliquaryList: nil,
SkillLevelMap: player.AvatarMap[avatarId].SkillLevelMap,
WearingFlycloakId: player.AvatarMap[avatarId].FlyCloak,
CostumeId: player.AvatarMap[avatarId].Costume,
BornTime: uint32(player.AvatarMap[avatarId].BornTime),
TeamResonanceList: make([]uint32, 0),
}
for id := range player.TeamConfig.TeamResonances {
sceneAvatarInfo.TeamResonanceList = append(sceneAvatarInfo.TeamResonanceList, uint32(id))
}
return sceneAvatarInfo
}
func (g *GameManager) PacketSceneMonsterInfo() *proto.SceneMonsterInfo {
sceneMonsterInfo := &proto.SceneMonsterInfo{
MonsterId: 20011301,
AuthorityPeerId: 1,
BornType: proto.MonsterBornType_MONSTER_BORN_TYPE_DEFAULT,
BlockId: 3001,
TitleId: 3001,
SpecialNameId: 40,
}
return sceneMonsterInfo
}
func (g *GameManager) PacketSceneGadgetInfo(gatherId uint32) *proto.SceneGadgetInfo {
gather := gdc.CONF.GatherDataMap[int32(gatherId)]
sceneGadgetInfo := &proto.SceneGadgetInfo{
GadgetId: uint32(gather.GadgetId),
//GroupId: 133003011,
//ConfigId: 11001,
GadgetState: 0,
IsEnableInteract: false,
AuthorityPeerId: 1,
Content: &proto.SceneGadgetInfo_GatherGadget{
GatherGadget: &proto.GatherGadgetInfo{
ItemId: uint32(gather.ItemId),
IsForbidGuest: false,
},
},
}
return sceneGadgetInfo
}
func (g *GameManager) PacketDelTeamEntityNotify(scene *Scene, player *model.Player) *proto.DelTeamEntityNotify {
delTeamEntityNotify := new(proto.DelTeamEntityNotify)
delTeamEntityNotify.SceneId = player.SceneId
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
delTeamEntityNotify.DelEntityIdList = []uint32{playerTeamEntity.teamEntityId}
return delTeamEntityNotify
}

View File

@@ -0,0 +1,128 @@
package game
import (
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
"game-hk4e/constant"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
"time"
)
func (g *GameManager) GetShopmallDataReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get shop mall, userId: %v", userId)
// PacketGetShopmallDataRsp
getShopmallDataRsp := new(proto.GetShopmallDataRsp)
getShopmallDataRsp.ShopTypeList = []uint32{900, 1052, 902, 1001, 903}
g.SendMsg(proto.ApiGetShopmallDataRsp, userId, player.ClientSeq, getShopmallDataRsp)
}
func (g *GameManager) GetShopReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get shop, userId: %v", userId)
req := payloadMsg.(*proto.GetShopReq)
shopType := req.ShopType
if shopType != 1001 {
return
}
nextRefreshTime := uint32(time.Now().Add(time.Hour * 24 * 30).Unix())
// PacketGetShopRsp
getShopRsp := new(proto.GetShopRsp)
getShopRsp.Shop = &proto.Shop{
GoodsList: []*proto.ShopGoods{
{
MinLevel: 1,
EndTime: 2051193600,
Hcoin: 160,
GoodsId: 102001,
NextRefreshTime: nextRefreshTime,
MaxLevel: 99,
BeginTime: 1575129600,
GoodsItem: &proto.ItemParam{
ItemId: 223,
Count: 1,
},
},
{
MinLevel: 1,
EndTime: 2051193600,
Hcoin: 160,
GoodsId: 102002,
NextRefreshTime: nextRefreshTime,
MaxLevel: 99,
BeginTime: 1575129600,
GoodsItem: &proto.ItemParam{
ItemId: 224,
Count: 1,
},
},
},
NextRefreshTime: nextRefreshTime,
ShopType: 1001,
}
g.SendMsg(proto.ApiGetShopRsp, userId, player.ClientSeq, getShopRsp)
}
func (g *GameManager) BuyGoodsReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user buy goods, userId: %v", userId)
req := payloadMsg.(*proto.BuyGoodsReq)
buyItemId := req.Goods.GoodsItem.ItemId
buyItemCount := req.BuyCount
costHcoinCount := req.Goods.Hcoin * buyItemCount
if buyItemId != 223 && buyItemId != 224 {
return
}
if player.GetItemCount(201) < costHcoinCount {
return
}
g.CostUserItem(userId, []*UserItem{{
ItemId: 201,
ChangeCount: costHcoinCount,
}})
g.AddUserItem(userId, []*UserItem{{
ItemId: buyItemId,
ChangeCount: buyItemCount,
}}, true, constant.ActionReasonConst.Shop)
req.Goods.BoughtNum = player.GetItemCount(buyItemId)
// PacketBuyGoodsRsp
buyGoodsRsp := new(proto.BuyGoodsRsp)
buyGoodsRsp.ShopType = req.ShopType
buyGoodsRsp.BuyCount = req.BuyCount
buyGoodsRsp.GoodsList = []*proto.ShopGoods{req.Goods}
g.SendMsg(proto.ApiBuyGoodsRsp, userId, player.ClientSeq, buyGoodsRsp)
}
func (g *GameManager) McoinExchangeHcoinReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user mcoin exchange hcoin, userId: %v", userId)
req := payloadMsg.(*proto.McoinExchangeHcoinReq)
if req.Hcoin != req.McoinCost {
return
}
count := req.Hcoin
if player.GetItemCount(203) < count {
return
}
g.CostUserItem(userId, []*UserItem{{
ItemId: 203,
ChangeCount: count,
}})
g.AddUserItem(userId, []*UserItem{{
ItemId: 201,
ChangeCount: count,
}}, false, 0)
// PacketMcoinExchangeHcoinRsp
mcoinExchangeHcoinRsp := new(proto.McoinExchangeHcoinRsp)
mcoinExchangeHcoinRsp.Hcoin = req.Hcoin
mcoinExchangeHcoinRsp.McoinCost = req.McoinCost
g.SendMsg(proto.ApiMcoinExchangeHcoinRsp, userId, player.ClientSeq, mcoinExchangeHcoinRsp)
}

View File

@@ -0,0 +1,334 @@
package game
import (
"flswld.com/common/utils/object"
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
"game-hk4e/constant"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
"regexp"
"time"
"unicode/utf8"
)
func (g *GameManager) GetPlayerSocialDetailReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get player social detail, user id: %v", userId)
req := payloadMsg.(*proto.GetPlayerSocialDetailReq)
targetUid := req.Uid
// PacketGetPlayerSocialDetailRsp
getPlayerSocialDetailRsp := new(proto.GetPlayerSocialDetailRsp)
// TODO 同步阻塞待优化
targetPlayer := g.userManager.LoadTempOfflineUserSync(targetUid)
if targetPlayer != nil {
socialDetail := new(proto.SocialDetail)
socialDetail.Uid = targetPlayer.PlayerID
socialDetail.ProfilePicture = &proto.ProfilePicture{AvatarId: targetPlayer.HeadImage}
socialDetail.Nickname = targetPlayer.NickName
socialDetail.Signature = targetPlayer.Signature
socialDetail.Level = targetPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]
socialDetail.Birthday = &proto.Birthday{Month: 2, Day: 13}
socialDetail.WorldLevel = targetPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL]
socialDetail.NameCardId = targetPlayer.NameCard
socialDetail.IsShowAvatar = false
socialDetail.FinishAchievementNum = 0
_, exist := player.FriendList[targetPlayer.PlayerID]
socialDetail.IsFriend = exist
getPlayerSocialDetailRsp.DetailData = socialDetail
} else {
getPlayerSocialDetailRsp.Retcode = int32(proto.Retcode_RETCODE_RET_PLAYER_NOT_EXIST)
}
g.SendMsg(proto.ApiGetPlayerSocialDetailRsp, userId, player.ClientSeq, getPlayerSocialDetailRsp)
}
func (g *GameManager) SetPlayerBirthdayReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user set birthday, user id: %v", userId)
req := payloadMsg.(*proto.SetPlayerBirthdayReq)
_ = req
}
func (g *GameManager) SetNameCardReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user change name card, user id: %v", userId)
req := payloadMsg.(*proto.SetNameCardReq)
nameCardId := req.NameCardId
exist := false
for _, nameCard := range player.NameCardList {
if nameCard == nameCardId {
exist = true
}
}
if !exist {
logger.LOG.Error("name card not exist, userId: %v", userId)
return
}
player.NameCard = nameCardId
// PacketSetNameCardRsp
setNameCardRsp := new(proto.SetNameCardRsp)
setNameCardRsp.NameCardId = nameCardId
g.SendMsg(proto.ApiSetNameCardRsp, userId, player.ClientSeq, setNameCardRsp)
}
func (g *GameManager) SetPlayerSignatureReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user change signature, user id: %v", userId)
req := payloadMsg.(*proto.SetPlayerSignatureReq)
signature := req.Signature
// PacketSetPlayerSignatureRsp
setPlayerSignatureRsp := new(proto.SetPlayerSignatureRsp)
if !object.IsUtf8String(signature) {
setPlayerSignatureRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SIGNATURE_ILLEGAL)
} else if utf8.RuneCountInString(signature) > 50 {
setPlayerSignatureRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SIGNATURE_ILLEGAL)
} else {
player.Signature = signature
setPlayerSignatureRsp.Signature = player.Signature
}
g.SendMsg(proto.ApiSetPlayerSignatureRsp, userId, player.ClientSeq, setPlayerSignatureRsp)
}
func (g *GameManager) SetPlayerNameReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user change nickname, user id: %v", userId)
req := payloadMsg.(*proto.SetPlayerNameReq)
nickName := req.NickName
// PacketSetPlayerNameRsp
setPlayerNameRsp := new(proto.SetPlayerNameRsp)
if len(nickName) == 0 {
setPlayerNameRsp.Retcode = int32(proto.Retcode_RETCODE_RET_NICKNAME_IS_EMPTY)
} else if !object.IsUtf8String(nickName) {
setPlayerNameRsp.Retcode = int32(proto.Retcode_RETCODE_RET_NICKNAME_UTF8_ERROR)
} else if utf8.RuneCountInString(nickName) > 14 {
setPlayerNameRsp.Retcode = int32(proto.Retcode_RETCODE_RET_NICKNAME_TOO_LONG)
} else if len(regexp.MustCompile(`\d`).FindAllString(nickName, -1)) > 6 {
setPlayerNameRsp.Retcode = int32(proto.Retcode_RETCODE_RET_NICKNAME_TOO_MANY_DIGITS)
} else {
player.NickName = nickName
setPlayerNameRsp.NickName = player.NickName
}
g.SendMsg(proto.ApiSetPlayerNameRsp, userId, player.ClientSeq, setPlayerNameRsp)
}
func (g *GameManager) SetPlayerHeadImageReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user change head image, user id: %v", userId)
req := payloadMsg.(*proto.SetPlayerHeadImageReq)
avatarId := req.AvatarId
_, exist := player.AvatarMap[avatarId]
if !exist {
logger.LOG.Error("the head img of the avatar not exist, userId: %v", userId)
return
}
player.HeadImage = avatarId
// PacketSetPlayerHeadImageRsp
setPlayerHeadImageRsp := new(proto.SetPlayerHeadImageRsp)
setPlayerHeadImageRsp.ProfilePicture = &proto.ProfilePicture{AvatarId: player.HeadImage}
g.SendMsg(proto.ApiSetPlayerHeadImageRsp, userId, player.ClientSeq, setPlayerHeadImageRsp)
}
func (g *GameManager) GetAllUnlockNameCardReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get all unlock name card, user id: %v", userId)
// PacketGetAllUnlockNameCardRsp
getAllUnlockNameCardRsp := new(proto.GetAllUnlockNameCardRsp)
getAllUnlockNameCardRsp.NameCardList = player.NameCardList
g.SendMsg(proto.ApiGetAllUnlockNameCardRsp, userId, player.ClientSeq, getAllUnlockNameCardRsp)
}
func (g *GameManager) GetPlayerFriendListReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get friend list, user id: %v", userId)
// PacketGetPlayerFriendListRsp
getPlayerFriendListRsp := new(proto.GetPlayerFriendListRsp)
getPlayerFriendListRsp.FriendList = make([]*proto.FriendBrief, 0)
for uid := range player.FriendList {
// TODO 同步阻塞待优化
var onlineState proto.FriendOnlineState
online := g.userManager.GetUserOnlineState(uid)
if online {
onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE
} else {
onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_FREIEND_DISCONNECT
}
friendPlayer := g.userManager.LoadTempOfflineUserSync(uid)
if friendPlayer == nil {
logger.LOG.Error("target player is nil, userId: %v", userId)
continue
}
friendBrief := &proto.FriendBrief{
Uid: friendPlayer.PlayerID,
Nickname: friendPlayer.NickName,
Level: friendPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL],
ProfilePicture: &proto.ProfilePicture{AvatarId: friendPlayer.HeadImage},
WorldLevel: friendPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL],
Signature: friendPlayer.Signature,
OnlineState: onlineState,
IsMpModeAvailable: true,
LastActiveTime: player.OfflineTime,
NameCardId: friendPlayer.NameCard,
Param: (uint32(time.Now().Unix()) - player.OfflineTime) / 3600 / 24,
IsGameSource: true,
PlatformType: proto.PlatformType_PLATFORM_TYPE_PC,
}
getPlayerFriendListRsp.FriendList = append(getPlayerFriendListRsp.FriendList, friendBrief)
}
g.SendMsg(proto.ApiGetPlayerFriendListRsp, userId, player.ClientSeq, getPlayerFriendListRsp)
}
func (g *GameManager) GetPlayerAskFriendListReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get friend apply list, user id: %v", userId)
// PacketGetPlayerAskFriendListRsp
getPlayerAskFriendListRsp := new(proto.GetPlayerAskFriendListRsp)
getPlayerAskFriendListRsp.AskFriendList = make([]*proto.FriendBrief, 0)
for uid := range player.FriendApplyList {
// TODO 同步阻塞待优化
var onlineState proto.FriendOnlineState
online := g.userManager.GetUserOnlineState(uid)
if online {
onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE
} else {
onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_FREIEND_DISCONNECT
}
friendPlayer := g.userManager.LoadTempOfflineUserSync(uid)
if friendPlayer == nil {
logger.LOG.Error("target player is nil, userId: %v", userId)
continue
}
friendBrief := &proto.FriendBrief{
Uid: friendPlayer.PlayerID,
Nickname: friendPlayer.NickName,
Level: friendPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL],
ProfilePicture: &proto.ProfilePicture{AvatarId: friendPlayer.HeadImage},
WorldLevel: friendPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL],
Signature: friendPlayer.Signature,
OnlineState: onlineState,
IsMpModeAvailable: true,
LastActiveTime: player.OfflineTime,
NameCardId: friendPlayer.NameCard,
Param: (uint32(time.Now().Unix()) - player.OfflineTime) / 3600 / 24,
IsGameSource: true,
PlatformType: proto.PlatformType_PLATFORM_TYPE_PC,
}
getPlayerAskFriendListRsp.AskFriendList = append(getPlayerAskFriendListRsp.AskFriendList, friendBrief)
}
g.SendMsg(proto.ApiGetPlayerAskFriendListRsp, userId, player.ClientSeq, getPlayerAskFriendListRsp)
}
func (g *GameManager) AskAddFriendReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user apply add friend, user id: %v", userId)
req := payloadMsg.(*proto.AskAddFriendReq)
targetUid := req.TargetUid
// TODO 同步阻塞待优化
targetPlayerOnline := g.userManager.GetUserOnlineState(targetUid)
targetPlayer := g.userManager.LoadTempOfflineUserSync(targetUid)
if targetPlayer == nil {
logger.LOG.Error("apply add friend target player is nil, userId: %v", userId)
return
}
_, applyExist := targetPlayer.FriendApplyList[player.PlayerID]
_, friendExist := targetPlayer.FriendList[player.PlayerID]
if applyExist || friendExist {
logger.LOG.Error("friend or apply already exist, user id: %v", userId)
return
}
targetPlayer.FriendApplyList[player.PlayerID] = true
if targetPlayerOnline {
// PacketAskAddFriendNotify
askAddFriendNotify := new(proto.AskAddFriendNotify)
askAddFriendNotify.TargetUid = player.PlayerID
askAddFriendNotify.TargetFriendBrief = &proto.FriendBrief{
Uid: player.PlayerID,
Nickname: player.NickName,
Level: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL],
ProfilePicture: &proto.ProfilePicture{AvatarId: player.HeadImage},
WorldLevel: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL],
Signature: player.Signature,
OnlineState: proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE,
IsMpModeAvailable: true,
LastActiveTime: player.OfflineTime,
NameCardId: player.NameCard,
Param: (uint32(time.Now().Unix()) - player.OfflineTime) / 3600 / 24,
IsGameSource: true,
PlatformType: proto.PlatformType_PLATFORM_TYPE_PC,
}
g.SendMsg(proto.ApiAskAddFriendNotify, targetPlayer.PlayerID, targetPlayer.ClientSeq, askAddFriendNotify)
}
// PacketAskAddFriendRsp
askAddFriendRsp := new(proto.AskAddFriendRsp)
askAddFriendRsp.TargetUid = targetUid
g.SendMsg(proto.ApiAskAddFriendRsp, userId, player.ClientSeq, askAddFriendRsp)
}
func (g *GameManager) DealAddFriendReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user deal friend apply, user id: %v", userId)
req := payloadMsg.(*proto.DealAddFriendReq)
targetUid := req.TargetUid
result := req.DealAddFriendResult
if result == proto.DealAddFriendResultType_DEAL_ADD_FRIEND_RESULT_TYPE_ACCEPT {
player.FriendList[targetUid] = true
// TODO 同步阻塞待优化
targetPlayer := g.userManager.LoadTempOfflineUserSync(targetUid)
if targetPlayer == nil {
logger.LOG.Error("agree friend apply target player is nil, userId: %v", userId)
return
}
targetPlayer.FriendList[player.PlayerID] = true
}
delete(player.FriendApplyList, targetUid)
// PacketDealAddFriendRsp
dealAddFriendRsp := new(proto.DealAddFriendRsp)
dealAddFriendRsp.TargetUid = targetUid
dealAddFriendRsp.DealAddFriendResult = result
g.SendMsg(proto.ApiDealAddFriendRsp, userId, player.ClientSeq, dealAddFriendRsp)
}
func (g *GameManager) GetOnlinePlayerListReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user get online player list, user id: %v", userId)
count := 0
onlinePlayerList := make([]*model.Player, 0)
for _, onlinePlayer := range g.userManager.GetAllOnlineUserList() {
if onlinePlayer.PlayerID == player.PlayerID {
continue
}
onlinePlayerList = append(onlinePlayerList, onlinePlayer)
count++
if count >= 50 {
break
}
}
// PacketGetOnlinePlayerListRsp
getOnlinePlayerListRsp := new(proto.GetOnlinePlayerListRsp)
getOnlinePlayerListRsp.PlayerInfoList = make([]*proto.OnlinePlayerInfo, 0)
for _, onlinePlayer := range onlinePlayerList {
onlinePlayerInfo := g.PacketOnlinePlayerInfo(onlinePlayer)
getOnlinePlayerListRsp.PlayerInfoList = append(getOnlinePlayerListRsp.PlayerInfoList, onlinePlayerInfo)
}
g.SendMsg(proto.ApiGetOnlinePlayerListRsp, userId, player.ClientSeq, getOnlinePlayerListRsp)
}
func (g *GameManager) PacketOnlinePlayerInfo(player *model.Player) *proto.OnlinePlayerInfo {
onlinePlayerInfo := &proto.OnlinePlayerInfo{
Uid: player.PlayerID,
Nickname: player.NickName,
PlayerLevel: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL],
MpSettingType: proto.MpSettingType(player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE]),
NameCardId: player.NameCard,
Signature: player.Signature,
ProfilePicture: &proto.ProfilePicture{AvatarId: player.HeadImage},
CurPlayerNumInWorld: 1,
}
world := g.worldManager.GetWorldByID(player.WorldId)
if world != nil && world.playerMap != nil {
onlinePlayerInfo.CurPlayerNumInWorld = uint32(len(world.playerMap))
}
return onlinePlayerInfo
}

View File

@@ -0,0 +1,347 @@
package game
import (
"flswld.com/common/utils/endec"
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
gdc "game-hk4e/config"
"game-hk4e/constant"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
)
func (g *GameManager) ChangeAvatarReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user change avatar, user id: %v", userId)
req := payloadMsg.(*proto.ChangeAvatarReq)
targetAvatarGuid := req.Guid
world := g.worldManager.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId)
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
oldAvatarId := player.TeamConfig.GetActiveAvatarId()
oldAvatar := player.AvatarMap[oldAvatarId]
if oldAvatar.Guid == targetAvatarGuid {
logger.LOG.Error("can not change to the same avatar, user id: %v, oldAvatarId: %v, oldAvatarGuid: %v", userId, oldAvatarId, oldAvatar.Guid)
return
}
activeTeam := player.TeamConfig.GetActiveTeam()
index := -1
for avatarIndex, avatarId := range activeTeam.AvatarIdList {
if avatarId == 0 {
break
}
if targetAvatarGuid == player.AvatarMap[avatarId].Guid {
index = avatarIndex
}
}
if index == -1 {
logger.LOG.Error("can not find the target avatar in team, user id: %v, target avatar guid: %v", userId, targetAvatarGuid)
return
}
player.TeamConfig.CurrAvatarIndex = uint8(index)
entity := scene.GetEntity(playerTeamEntity.avatarEntityMap[oldAvatarId])
if entity == nil {
return
}
entity.moveState = uint16(proto.MotionState_MOTION_STATE_STANDBY)
// PacketSceneEntityDisappearNotify
sceneEntityDisappearNotify := new(proto.SceneEntityDisappearNotify)
sceneEntityDisappearNotify.DisappearType = proto.VisionType_VISION_TYPE_REPLACE
sceneEntityDisappearNotify.EntityList = []uint32{playerTeamEntity.avatarEntityMap[oldAvatarId]}
for _, scenePlayer := range scene.playerMap {
g.SendMsg(proto.ApiSceneEntityDisappearNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, sceneEntityDisappearNotify)
}
// PacketSceneEntityAppearNotify
sceneEntityAppearNotify := new(proto.SceneEntityAppearNotify)
sceneEntityAppearNotify.AppearType = proto.VisionType_VISION_TYPE_REPLACE
sceneEntityAppearNotify.Param = playerTeamEntity.avatarEntityMap[oldAvatarId]
sceneEntityAppearNotify.EntityList = []*proto.SceneEntityInfo{g.PacketSceneEntityInfoAvatar(scene, player, player.TeamConfig.GetActiveAvatarId())}
for _, scenePlayer := range scene.playerMap {
g.SendMsg(proto.ApiSceneEntityAppearNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, sceneEntityAppearNotify)
}
// PacketChangeAvatarRsp
changeAvatarRsp := new(proto.ChangeAvatarRsp)
changeAvatarRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SUCC)
changeAvatarRsp.CurGuid = targetAvatarGuid
g.SendMsg(proto.ApiChangeAvatarRsp, userId, player.ClientSeq, changeAvatarRsp)
}
func (g *GameManager) SetUpAvatarTeamReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user change team, user id: %v", userId)
req := payloadMsg.(*proto.SetUpAvatarTeamReq)
teamId := req.TeamId
if teamId <= 0 || teamId >= 5 {
// PacketSetUpAvatarTeamRsp
setUpAvatarTeamRsp := new(proto.SetUpAvatarTeamRsp)
setUpAvatarTeamRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SVR_ERROR)
g.SendMsg(proto.ApiSetUpAvatarTeamRsp, userId, player.ClientSeq, setUpAvatarTeamRsp)
return
}
avatarGuidList := req.AvatarTeamGuidList
world := g.worldManager.GetWorldByID(player.WorldId)
multiTeam := teamId == 4
selfTeam := teamId == uint32(player.TeamConfig.GetActiveTeamId())
if (multiTeam && len(avatarGuidList) == 0) || (selfTeam && len(avatarGuidList) == 0) || len(avatarGuidList) > 4 || world.multiplayer {
// PacketSetUpAvatarTeamRsp
setUpAvatarTeamRsp := new(proto.SetUpAvatarTeamRsp)
setUpAvatarTeamRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SVR_ERROR)
g.SendMsg(proto.ApiSetUpAvatarTeamRsp, userId, player.ClientSeq, setUpAvatarTeamRsp)
return
}
avatarIdList := make([]uint32, 0)
for _, avatarGuid := range avatarGuidList {
for avatarId, avatar := range player.AvatarMap {
if avatarGuid == avatar.Guid {
avatarIdList = append(avatarIdList, avatarId)
}
}
}
player.TeamConfig.ClearTeamAvatar(uint8(teamId - 1))
for _, avatarId := range avatarIdList {
player.TeamConfig.AddAvatarToTeam(avatarId, uint8(teamId-1))
}
if world.multiplayer {
// PacketSetUpAvatarTeamRsp
setUpAvatarTeamRsp := new(proto.SetUpAvatarTeamRsp)
setUpAvatarTeamRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SVR_ERROR)
g.SendMsg(proto.ApiSetUpAvatarTeamRsp, userId, player.ClientSeq, setUpAvatarTeamRsp)
return
}
// PacketAvatarTeamUpdateNotify
avatarTeamUpdateNotify := new(proto.AvatarTeamUpdateNotify)
avatarTeamUpdateNotify.AvatarTeamMap = make(map[uint32]*proto.AvatarTeam)
for teamIndex, team := range player.TeamConfig.TeamList {
avatarTeam := new(proto.AvatarTeam)
avatarTeam.TeamName = team.Name
for _, avatarId := range team.AvatarIdList {
if avatarId == 0 {
break
}
avatarTeam.AvatarGuidList = append(avatarTeam.AvatarGuidList, player.AvatarMap[avatarId].Guid)
}
avatarTeamUpdateNotify.AvatarTeamMap[uint32(teamIndex)+1] = avatarTeam
}
g.SendMsg(proto.ApiAvatarTeamUpdateNotify, userId, player.ClientSeq, avatarTeamUpdateNotify)
if selfTeam {
player.TeamConfig.CurrAvatarIndex = 0
player.TeamConfig.UpdateTeam()
scene := world.GetSceneById(player.SceneId)
scene.UpdatePlayerTeamEntity(player)
// PacketSceneTeamUpdateNotify
sceneTeamUpdateNotify := g.PacketSceneTeamUpdateNotify(world)
g.SendMsg(proto.ApiSceneTeamUpdateNotify, userId, player.ClientSeq, sceneTeamUpdateNotify)
// PacketSetUpAvatarTeamRsp
setUpAvatarTeamRsp := new(proto.SetUpAvatarTeamRsp)
setUpAvatarTeamRsp.TeamId = teamId
setUpAvatarTeamRsp.CurAvatarGuid = player.AvatarMap[player.TeamConfig.GetActiveAvatarId()].Guid
team := player.TeamConfig.GetTeamByIndex(uint8(teamId - 1))
for _, avatarId := range team.AvatarIdList {
if avatarId == 0 {
break
}
setUpAvatarTeamRsp.AvatarTeamGuidList = append(setUpAvatarTeamRsp.AvatarTeamGuidList, player.AvatarMap[avatarId].Guid)
}
g.SendMsg(proto.ApiSetUpAvatarTeamRsp, userId, player.ClientSeq, setUpAvatarTeamRsp)
} else {
// PacketSetUpAvatarTeamRsp
setUpAvatarTeamRsp := new(proto.SetUpAvatarTeamRsp)
setUpAvatarTeamRsp.TeamId = teamId
setUpAvatarTeamRsp.CurAvatarGuid = player.AvatarMap[player.TeamConfig.GetActiveAvatarId()].Guid
team := player.TeamConfig.GetTeamByIndex(uint8(teamId - 1))
for _, avatarId := range team.AvatarIdList {
if avatarId == 0 {
break
}
setUpAvatarTeamRsp.AvatarTeamGuidList = append(setUpAvatarTeamRsp.AvatarTeamGuidList, player.AvatarMap[avatarId].Guid)
}
g.SendMsg(proto.ApiSetUpAvatarTeamRsp, userId, player.ClientSeq, setUpAvatarTeamRsp)
}
}
func (g *GameManager) ChooseCurAvatarTeamReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user switch team, user id: %v", userId)
req := payloadMsg.(*proto.ChooseCurAvatarTeamReq)
teamId := req.TeamId
world := g.worldManager.GetWorldByID(player.WorldId)
if world.multiplayer {
return
}
team := player.TeamConfig.GetTeamByIndex(uint8(teamId) - 1)
if team == nil || len(team.AvatarIdList) == 0 {
return
}
player.TeamConfig.CurrTeamIndex = uint8(teamId) - 1
player.TeamConfig.CurrAvatarIndex = 0
player.TeamConfig.UpdateTeam()
scene := world.GetSceneById(player.SceneId)
scene.UpdatePlayerTeamEntity(player)
// PacketSceneTeamUpdateNotify
sceneTeamUpdateNotify := g.PacketSceneTeamUpdateNotify(world)
g.SendMsg(proto.ApiSceneTeamUpdateNotify, userId, player.ClientSeq, sceneTeamUpdateNotify)
// PacketChooseCurAvatarTeamRsp
chooseCurAvatarTeamRsp := new(proto.ChooseCurAvatarTeamRsp)
chooseCurAvatarTeamRsp.CurTeamId = teamId
g.SendMsg(proto.ApiChooseCurAvatarTeamRsp, userId, player.ClientSeq, chooseCurAvatarTeamRsp)
}
func (g *GameManager) ChangeMpTeamAvatarReq(userId uint32, player *model.Player, clientSeq uint32, payloadMsg pb.Message) {
logger.LOG.Debug("user change mp team, user id: %v", userId)
req := payloadMsg.(*proto.ChangeMpTeamAvatarReq)
avatarGuidList := req.AvatarGuidList
world := g.worldManager.GetWorldByID(player.WorldId)
if len(avatarGuidList) == 0 || len(avatarGuidList) > 4 || !world.multiplayer {
// PacketChangeMpTeamAvatarRsp
changeMpTeamAvatarRsp := new(proto.ChangeMpTeamAvatarRsp)
changeMpTeamAvatarRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SVR_ERROR)
g.SendMsg(proto.ApiChangeMpTeamAvatarRsp, userId, player.ClientSeq, changeMpTeamAvatarRsp)
return
}
avatarIdList := make([]uint32, 0)
for _, avatarGuid := range avatarGuidList {
for avatarId, avatar := range player.AvatarMap {
if avatarGuid == avatar.Guid {
avatarIdList = append(avatarIdList, avatarId)
}
}
}
player.TeamConfig.ClearTeamAvatar(3)
for _, avatarId := range avatarIdList {
player.TeamConfig.AddAvatarToTeam(avatarId, 3)
}
player.TeamConfig.CurrAvatarIndex = 0
player.TeamConfig.UpdateTeam()
scene := world.GetSceneById(player.SceneId)
scene.UpdatePlayerTeamEntity(player)
for _, worldPlayer := range world.playerMap {
// PacketSceneTeamUpdateNotify
sceneTeamUpdateNotify := g.PacketSceneTeamUpdateNotify(world)
g.SendMsg(proto.ApiSceneTeamUpdateNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, sceneTeamUpdateNotify)
}
// PacketChangeMpTeamAvatarRsp
changeMpTeamAvatarRsp := new(proto.ChangeMpTeamAvatarRsp)
changeMpTeamAvatarRsp.CurAvatarGuid = player.AvatarMap[player.TeamConfig.GetActiveAvatarId()].Guid
team := player.TeamConfig.GetTeamByIndex(3)
for _, avatarId := range team.AvatarIdList {
if avatarId == 0 {
break
}
changeMpTeamAvatarRsp.AvatarGuidList = append(changeMpTeamAvatarRsp.AvatarGuidList, player.AvatarMap[avatarId].Guid)
}
g.SendMsg(proto.ApiChangeMpTeamAvatarRsp, userId, player.ClientSeq, changeMpTeamAvatarRsp)
}
func (g *GameManager) PacketSceneTeamUpdateNotify(world *World) *proto.SceneTeamUpdateNotify {
sceneTeamUpdateNotify := new(proto.SceneTeamUpdateNotify)
sceneTeamUpdateNotify.IsInMp = world.multiplayer
empty := new(proto.AbilitySyncStateInfo)
for _, worldPlayer := range world.playerMap {
worldPlayerScene := world.GetSceneById(worldPlayer.SceneId)
worldPlayerTeamEntity := worldPlayerScene.GetPlayerTeamEntity(worldPlayer.PlayerID)
team := worldPlayer.TeamConfig.GetActiveTeam()
for _, avatarId := range team.AvatarIdList {
if avatarId == 0 {
break
}
worldPlayerAvatar := worldPlayer.AvatarMap[avatarId]
equipIdList := make([]uint32, 0)
weapon := worldPlayerAvatar.EquipWeapon
equipIdList = append(equipIdList, weapon.ItemId)
for _, reliquary := range worldPlayerAvatar.EquipReliquaryList {
equipIdList = append(equipIdList, reliquary.ItemId)
}
sceneTeamAvatar := &proto.SceneTeamAvatar{
PlayerUid: worldPlayer.PlayerID,
AvatarGuid: worldPlayerAvatar.Guid,
SceneId: worldPlayer.SceneId,
EntityId: worldPlayerTeamEntity.avatarEntityMap[avatarId],
SceneEntityInfo: g.PacketSceneEntityInfoAvatar(worldPlayerScene, worldPlayer, avatarId),
WeaponGuid: worldPlayerAvatar.EquipWeapon.Guid,
WeaponEntityId: worldPlayerTeamEntity.weaponEntityMap[worldPlayerAvatar.EquipWeapon.WeaponId],
IsPlayerCurAvatar: worldPlayer.TeamConfig.GetActiveAvatarId() == avatarId,
IsOnScene: worldPlayer.TeamConfig.GetActiveAvatarId() == avatarId,
AvatarAbilityInfo: empty,
WeaponAbilityInfo: empty,
AbilityControlBlock: new(proto.AbilityControlBlock),
}
if world.multiplayer {
sceneTeamAvatar.AvatarInfo = g.PacketAvatarInfo(worldPlayerAvatar)
sceneTeamAvatar.SceneAvatarInfo = g.PacketSceneAvatarInfo(worldPlayerScene, worldPlayer, avatarId)
}
// add AbilityControlBlock
avatarDataConfig := gdc.CONF.AvatarDataMap[int32(avatarId)]
acb := sceneTeamAvatar.AbilityControlBlock
embryoId := 0
// add avatar abilities
for _, abilityId := range avatarDataConfig.Abilities {
embryoId++
emb := &proto.AbilityEmbryo{
AbilityId: uint32(embryoId),
AbilityNameHash: uint32(abilityId),
AbilityOverrideNameHash: uint32(constant.GameConstantConst.DEFAULT_ABILITY_NAME),
}
acb.AbilityEmbryoList = append(acb.AbilityEmbryoList, emb)
}
// add default abilities
for _, abilityId := range constant.GameConstantConst.DEFAULT_ABILITY_HASHES {
embryoId++
emb := &proto.AbilityEmbryo{
AbilityId: uint32(embryoId),
AbilityNameHash: uint32(abilityId),
AbilityOverrideNameHash: uint32(constant.GameConstantConst.DEFAULT_ABILITY_NAME),
}
acb.AbilityEmbryoList = append(acb.AbilityEmbryoList, emb)
}
// add team resonances
for id := range worldPlayer.TeamConfig.TeamResonancesConfig {
embryoId++
emb := &proto.AbilityEmbryo{
AbilityId: uint32(embryoId),
AbilityNameHash: uint32(id),
AbilityOverrideNameHash: uint32(constant.GameConstantConst.DEFAULT_ABILITY_NAME),
}
acb.AbilityEmbryoList = append(acb.AbilityEmbryoList, emb)
}
// add skill depot abilities
skillDepot := gdc.CONF.AvatarSkillDepotDataMap[int32(worldPlayerAvatar.SkillDepotId)]
if skillDepot != nil && len(skillDepot.Abilities) != 0 {
for _, id := range skillDepot.Abilities {
embryoId++
emb := &proto.AbilityEmbryo{
AbilityId: uint32(embryoId),
AbilityNameHash: uint32(id),
AbilityOverrideNameHash: uint32(constant.GameConstantConst.DEFAULT_ABILITY_NAME),
}
acb.AbilityEmbryoList = append(acb.AbilityEmbryoList, emb)
}
}
// add equip abilities
for skill := range worldPlayerAvatar.ExtraAbilityEmbryos {
embryoId++
emb := &proto.AbilityEmbryo{
AbilityId: uint32(embryoId),
AbilityNameHash: uint32(endec.Hk4eAbilityHashCode(skill)),
AbilityOverrideNameHash: uint32(constant.GameConstantConst.DEFAULT_ABILITY_NAME),
}
acb.AbilityEmbryoList = append(acb.AbilityEmbryoList, emb)
}
sceneTeamUpdateNotify.SceneTeamAvatarList = append(sceneTeamUpdateNotify.SceneTeamAvatarList, sceneTeamAvatar)
}
}
return sceneTeamUpdateNotify
}

View File

@@ -0,0 +1,77 @@
package game
import (
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
gdc "game-hk4e/config"
"game-hk4e/constant"
)
func (g *GameManager) GetAllWeaponDataConfig() map[int32]*gdc.ItemData {
allWeaponDataConfig := make(map[int32]*gdc.ItemData)
for itemId, itemData := range gdc.CONF.ItemDataMap {
if itemData.EquipEnumType != constant.EquipTypeConst.EQUIP_WEAPON {
continue
}
if (itemId >= 10000 && itemId <= 10008) ||
itemId == 11411 ||
(itemId >= 11506 && itemId <= 11508) ||
itemId == 12505 ||
itemId == 12506 ||
itemId == 12508 ||
itemId == 12509 ||
itemId == 13503 ||
itemId == 13506 ||
itemId == 14411 ||
itemId == 14503 ||
itemId == 14505 ||
itemId == 14508 ||
(itemId >= 15504 && itemId <= 15506) ||
itemId == 20001 || itemId == 15306 || itemId == 14306 || itemId == 13304 || itemId == 12304 {
// 跳过无效武器
continue
}
allWeaponDataConfig[itemId] = itemData
}
return allWeaponDataConfig
}
func (g *GameManager) AddUserWeapon(userId uint32, itemId uint32) uint64 {
player := g.userManager.GetOnlineUser(userId)
if player == nil {
logger.LOG.Error("player is nil, userId: %v", userId)
return 0
}
weaponId := uint64(g.snowflake.GenId())
player.AddWeapon(itemId, weaponId)
weapon := player.GetWeapon(weaponId)
// PacketStoreItemChangeNotify
storeItemChangeNotify := new(proto.StoreItemChangeNotify)
storeItemChangeNotify.StoreType = proto.StoreType_STORE_TYPE_PACK
affixMap := make(map[uint32]uint32)
for _, affixId := range weapon.AffixIdList {
affixMap[affixId] = uint32(weapon.Refinement)
}
pbItem := &proto.Item{
ItemId: itemId,
Guid: player.GetWeaponGuid(weaponId),
Detail: &proto.Item_Equip{
Equip: &proto.Equip{
Detail: &proto.Equip_Weapon{
Weapon: &proto.Weapon{
Level: uint32(weapon.Level),
Exp: weapon.Exp,
PromoteLevel: uint32(weapon.Promote),
// key:武器效果id value:精炼等阶
AffixMap: affixMap,
},
},
IsLocked: weapon.Lock,
},
},
}
storeItemChangeNotify.ItemList = append(storeItemChangeNotify.ItemList, pbItem)
g.SendMsg(proto.ApiStoreItemChangeNotify, userId, player.ClientSeq, storeItemChangeNotify)
return weaponId
}

View File

@@ -0,0 +1,620 @@
package game
import (
"bytes"
"encoding/gob"
"flswld.com/common/utils/alg"
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
gdc "game-hk4e/config"
"game-hk4e/constant"
"game-hk4e/game/aoi"
"game-hk4e/model"
pb "google.golang.org/protobuf/proto"
"math"
"time"
"unsafe"
)
// 世界管理器
type MeshMapPos struct {
X int16
Y int16
Z int16
}
type WorldStatic struct {
// x y z -> if terrain exist
terrain map[MeshMapPos]bool
// x y z -> gather id
gather map[MeshMapPos]uint32
pathfindingStartPos MeshMapPos
pathfindingEndPos MeshMapPos
pathVectorList []MeshMapPos
aiMoveMeshSpeedParam int
aiMoveVectorList []*model.Vector
aiMoveCurrIndex int
}
func NewWorldStatic() (r *WorldStatic) {
r = new(WorldStatic)
r.terrain = make(map[MeshMapPos]bool)
r.gather = make(map[MeshMapPos]uint32)
r.InitGather()
r.pathfindingStartPos = MeshMapPos{
X: 2747,
Y: 194,
Z: -1719,
}
r.pathfindingEndPos = MeshMapPos{
X: 2588,
Y: 211,
Z: -1349,
}
r.pathVectorList = make([]MeshMapPos, 0)
r.aiMoveMeshSpeedParam = 3
r.aiMoveVectorList = make([]*model.Vector, 0)
r.aiMoveCurrIndex = 0
return r
}
func (w *WorldStatic) ConvWSTMapToPFMap() map[alg.MeshMapPos]bool {
return *(*map[alg.MeshMapPos]bool)(unsafe.Pointer(&w.terrain))
}
func (w *WorldStatic) ConvWSPosToPFPos(v MeshMapPos) alg.MeshMapPos {
return alg.MeshMapPos(v)
}
func (w *WorldStatic) ConvPFPVLToWSPVL(v []alg.MeshMapPos) []MeshMapPos {
return *(*[]MeshMapPos)(unsafe.Pointer(&v))
}
func (w *WorldStatic) Pathfinding() {
bfs := alg.NewBFS()
bfs.InitMap(
w.ConvWSTMapToPFMap(),
w.ConvWSPosToPFPos(w.pathfindingStartPos),
w.ConvWSPosToPFPos(w.pathfindingEndPos),
100,
)
pathVectorList := bfs.Pathfinding()
if pathVectorList == nil {
logger.LOG.Error("could not find path")
return
}
logger.LOG.Debug("find path success, path: %v", pathVectorList)
w.pathVectorList = w.ConvPFPVLToWSPVL(pathVectorList)
}
func (w *WorldStatic) ConvPathVectorListToAiMoveVectorList() {
for index, currPathVector := range w.pathVectorList {
if index > 0 {
lastPathVector := w.pathVectorList[index-1]
for i := 0; i < w.aiMoveMeshSpeedParam; i++ {
w.aiMoveVectorList = append(w.aiMoveVectorList, &model.Vector{
X: float64(lastPathVector.X) + float64(currPathVector.X-lastPathVector.X)/float64(w.aiMoveMeshSpeedParam)*float64(i),
Y: float64(lastPathVector.Y) + float64(currPathVector.Y-lastPathVector.Y)/float64(w.aiMoveMeshSpeedParam)*float64(i),
Z: float64(lastPathVector.Z) + float64(currPathVector.Z-lastPathVector.Z)/float64(w.aiMoveMeshSpeedParam)*float64(i),
})
}
}
}
}
func (w *WorldStatic) InitTerrain() bool {
data := gdc.CONF.ReadWorldTerrain()
decoder := gob.NewDecoder(bytes.NewReader(data))
err := decoder.Decode(&w.terrain)
if err != nil {
logger.LOG.Error("unmarshal world terrain data error: %v", err)
return false
}
return true
}
func (w *WorldStatic) SaveTerrain() bool {
var buffer bytes.Buffer
encoder := gob.NewEncoder(&buffer)
err := encoder.Encode(w.terrain)
if err != nil {
logger.LOG.Error("marshal world terrain data error: %v", err)
return false
}
gdc.CONF.WriteWorldTerrain(buffer.Bytes())
return true
}
func (w *WorldStatic) GetTerrain(x int16, y int16, z int16) (exist bool) {
pos := MeshMapPos{
X: x,
Y: y,
Z: z,
}
exist = w.terrain[pos]
return exist
}
func (w *WorldStatic) SetTerrain(x int16, y int16, z int16) {
pos := MeshMapPos{
X: x,
Y: y,
Z: z,
}
w.terrain[pos] = true
}
func (w *WorldStatic) InitGather() {
}
func (w *WorldStatic) GetGather(x int16, y int16, z int16) (gatherId uint32, exist bool) {
pos := MeshMapPos{
X: x,
Y: y,
Z: z,
}
gatherId, exist = w.gather[pos]
return gatherId, exist
}
func (w *WorldStatic) SetGather(x int16, y int16, z int16, gatherId uint32) {
pos := MeshMapPos{
X: x,
Y: y,
Z: z,
}
w.gather[pos] = gatherId
}
type WorldManager struct {
worldMap map[uint32]*World
snowflake *alg.SnowflakeWorker
worldStatic *WorldStatic
bigWorld *World
}
func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) {
r = new(WorldManager)
r.worldMap = make(map[uint32]*World)
r.snowflake = snowflake
r.worldStatic = NewWorldStatic()
return r
}
func (w *WorldManager) GetWorldByID(worldId uint32) *World {
return w.worldMap[worldId]
}
func (w *WorldManager) GetWorldMap() map[uint32]*World {
return w.worldMap
}
func (w *WorldManager) CreateWorld(owner *model.Player, multiplayer bool) *World {
worldId := uint32(w.snowflake.GenId())
world := &World{
id: worldId,
owner: owner,
playerMap: make(map[uint32]*model.Player),
sceneMap: make(map[uint32]*Scene),
entityIdCounter: 0,
worldLevel: 0,
multiplayer: multiplayer,
mpLevelEntityId: 0,
chatMsgList: make([]*proto.ChatInfo, 0),
// aoi划分
aoiManager: aoi.NewAoiManager(
-8000, 4000, 120,
-2000, 2000, 80,
-5500, 6500, 120,
),
}
if world.IsBigWorld() {
world.aoiManager = aoi.NewAoiManager(
-8000, 4000, 800,
-2000, 2000, 80,
-5500, 6500, 800,
)
}
world.mpLevelEntityId = world.GetNextWorldEntityId(constant.EntityIdTypeConst.MPLEVEL)
w.worldMap[worldId] = world
return world
}
func (w *WorldManager) DestroyWorld(worldId uint32) {
world := w.GetWorldByID(worldId)
for _, player := range world.playerMap {
world.RemovePlayer(player)
player.WorldId = 0
}
delete(w.worldMap, worldId)
}
func (w *WorldManager) GetBigWorld() *World {
return w.bigWorld
}
func (w *WorldManager) InitBigWorld(owner *model.Player) {
w.bigWorld = w.GetWorldByID(owner.WorldId)
w.bigWorld.multiplayer = true
}
type World struct {
id uint32
owner *model.Player
playerMap map[uint32]*model.Player
sceneMap map[uint32]*Scene
entityIdCounter uint32
worldLevel uint8
multiplayer bool
mpLevelEntityId uint32
chatMsgList []*proto.ChatInfo
aoiManager *aoi.AoiManager // 当前世界地图的aoi管理器
}
func (w *World) GetNextWorldEntityId(entityType uint16) uint32 {
w.entityIdCounter++
ret := (uint32(entityType) << 24) + w.entityIdCounter
return ret
}
func (w *World) AddPlayer(player *model.Player, sceneId uint32) {
player.PeerId = uint32(len(w.playerMap) + 1)
w.playerMap[player.PlayerID] = player
scene := w.GetSceneById(sceneId)
scene.AddPlayer(player)
}
func (w *World) RemovePlayer(player *model.Player) {
scene := w.sceneMap[player.SceneId]
scene.RemovePlayer(player)
delete(w.playerMap, player.PlayerID)
}
func (w *World) CreateScene(sceneId uint32) *Scene {
scene := &Scene{
id: sceneId,
world: w,
playerMap: make(map[uint32]*model.Player),
entityMap: make(map[uint32]*Entity),
playerTeamEntityMap: make(map[uint32]*PlayerTeamEntity),
gameTime: 18 * 60,
attackQueue: alg.NewRAQueue[*Attack](1000),
createTime: time.Now().UnixMilli(),
}
w.sceneMap[sceneId] = scene
return scene
}
func (w *World) GetSceneById(sceneId uint32) *Scene {
scene, exist := w.sceneMap[sceneId]
if !exist {
scene = w.CreateScene(sceneId)
}
return scene
}
func (w *World) AddChat(chatInfo *proto.ChatInfo) {
w.chatMsgList = append(w.chatMsgList, chatInfo)
}
func (w *World) GetChatList() []*proto.ChatInfo {
return w.chatMsgList
}
func (w *World) IsBigWorld() bool {
return w.owner.PlayerID == 1
}
type Scene struct {
id uint32
world *World
playerMap map[uint32]*model.Player
entityMap map[uint32]*Entity
playerTeamEntityMap map[uint32]*PlayerTeamEntity
gameTime uint32
attackQueue *alg.RAQueue[*Attack]
createTime int64
}
type AvatarEntity struct {
uid uint32
avatarId uint32
}
type MonsterEntity struct {
}
type GadgetEntity struct {
gatherId uint32
}
type Entity struct {
id uint32
scene *Scene
pos *model.Vector
rot *model.Vector
moveState uint16
lastMoveSceneTimeMs uint32
lastMoveReliableSeq uint32
fightProp map[uint32]float32
entityType uint32
level uint8
avatarEntity *AvatarEntity
monsterEntity *MonsterEntity
gadgetEntity *GadgetEntity
}
type PlayerTeamEntity struct {
teamEntityId uint32
avatarEntityMap map[uint32]uint32
weaponEntityMap map[uint64]uint32
}
type Attack struct {
combatInvokeEntry *proto.CombatInvokeEntry
uid uint32
}
func (s *Scene) ChangeGameTime(time uint32) {
s.gameTime = time % 1440
}
func (s *Scene) GetSceneTime() int64 {
now := time.Now().UnixMilli()
return now - s.createTime
}
func (s *Scene) GetPlayerTeamEntity(userId uint32) *PlayerTeamEntity {
return s.playerTeamEntityMap[userId]
}
func (s *Scene) CreatePlayerTeamEntity(player *model.Player) {
playerTeamEntity := &PlayerTeamEntity{
teamEntityId: s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.TEAM),
avatarEntityMap: make(map[uint32]uint32),
weaponEntityMap: make(map[uint64]uint32),
}
s.playerTeamEntityMap[player.PlayerID] = playerTeamEntity
}
func (s *Scene) UpdatePlayerTeamEntity(player *model.Player) {
team := player.TeamConfig.GetActiveTeam()
playerTeamEntity := s.playerTeamEntityMap[player.PlayerID]
for _, avatarId := range team.AvatarIdList {
if avatarId == 0 {
break
}
avatar := player.AvatarMap[avatarId]
avatarEntityId, exist := playerTeamEntity.avatarEntityMap[avatarId]
if exist {
s.DestroyEntity(avatarEntityId)
}
playerTeamEntity.avatarEntityMap[avatarId] = s.CreateEntityAvatar(player, avatarId)
weaponEntityId, exist := playerTeamEntity.weaponEntityMap[avatar.EquipWeapon.WeaponId]
if exist {
s.DestroyEntity(weaponEntityId)
}
playerTeamEntity.weaponEntityMap[avatar.EquipWeapon.WeaponId] = s.CreateEntityWeapon()
}
}
func (s *Scene) AddPlayer(player *model.Player) {
s.playerMap[player.PlayerID] = player
s.CreatePlayerTeamEntity(player)
s.UpdatePlayerTeamEntity(player)
}
func (s *Scene) RemovePlayer(player *model.Player) {
playerTeamEntity := s.GetPlayerTeamEntity(player.PlayerID)
for _, avatarEntityId := range playerTeamEntity.avatarEntityMap {
s.DestroyEntity(avatarEntityId)
}
for _, weaponEntityId := range playerTeamEntity.weaponEntityMap {
s.DestroyEntity(weaponEntityId)
}
delete(s.playerTeamEntityMap, player.PlayerID)
delete(s.playerMap, player.PlayerID)
}
func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32 {
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.AVATAR)
entity := &Entity{
id: entityId,
scene: s,
pos: player.Pos,
rot: player.Rot,
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
fightProp: player.AvatarMap[avatarId].FightPropMap,
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_AVATAR),
level: player.AvatarMap[avatarId].Level,
avatarEntity: &AvatarEntity{
uid: player.PlayerID,
avatarId: avatarId,
},
}
s.entityMap[entity.id] = entity
if avatarId == player.TeamConfig.GetActiveAvatarId() {
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
}
return entity.id
}
func (s *Scene) CreateEntityWeapon() uint32 {
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.WEAPON)
entity := &Entity{
id: entityId,
scene: s,
pos: new(model.Vector),
rot: new(model.Vector),
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
fightProp: nil,
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_WEAPON),
level: 0,
}
s.entityMap[entity.id] = entity
return entity.id
}
func (s *Scene) CreateEntityMonster(pos *model.Vector, level uint8, fightProp map[uint32]float32) uint32 {
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.MONSTER)
entity := &Entity{
id: entityId,
scene: s,
pos: pos,
rot: new(model.Vector),
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
fightProp: fightProp,
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER),
level: level,
}
s.entityMap[entity.id] = entity
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
return entity.id
}
func (s *Scene) CreateEntityGadget(pos *model.Vector, gatherId uint32) uint32 {
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.GADGET)
entity := &Entity{
id: entityId,
scene: s,
pos: pos,
rot: new(model.Vector),
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
fightProp: map[uint32]float32{
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP): math.MaxFloat32,
uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP): math.MaxFloat32,
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_HP): float32(1),
},
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_GADGET),
level: 0,
gadgetEntity: &GadgetEntity{
gatherId: gatherId,
},
}
s.entityMap[entity.id] = entity
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
return entity.id
}
func (s *Scene) DestroyEntity(entityId uint32) {
entity := s.GetEntity(entityId)
if entity == nil {
return
}
s.world.aoiManager.RemoveEntityIdFromGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
delete(s.entityMap, entityId)
}
func (s *Scene) GetEntity(entityId uint32) *Entity {
return s.entityMap[entityId]
}
func (s *Scene) AddAttack(attack *Attack) {
s.attackQueue.EnQueue(attack)
}
func (s *Scene) AttackHandler(gameManager *GameManager) {
combatInvokeEntryListAll := make([]*proto.CombatInvokeEntry, 0)
combatInvokeEntryListOther := make(map[uint32][]*proto.CombatInvokeEntry)
combatInvokeEntryListHost := make([]*proto.CombatInvokeEntry, 0)
for s.attackQueue.Len() != 0 {
attack := s.attackQueue.DeQueue()
if attack.combatInvokeEntry == nil {
logger.LOG.Error("error attack data, attack value: %v", attack)
continue
}
hitInfo := new(proto.EvtBeingHitInfo)
err := pb.Unmarshal(attack.combatInvokeEntry.CombatData, hitInfo)
if err != nil {
logger.LOG.Error("parse combat invocations entity hit info error: %v", err)
continue
}
attackResult := hitInfo.AttackResult
//logger.LOG.Debug("run attack handler, attackResult: %v", attackResult)
target := s.entityMap[attackResult.DefenseId]
if target == nil {
logger.LOG.Error("could not found target, defense id: %v", attackResult.DefenseId)
continue
}
attackResult.Damage *= 100
damage := attackResult.Damage
attackerId := attackResult.AttackerId
_ = attackerId
currHp := float32(0)
if target.fightProp != nil {
currHp = target.fightProp[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP)]
currHp -= damage
if currHp < 0 {
currHp = 0
}
target.fightProp[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP)] = currHp
}
// PacketEntityFightPropUpdateNotify
entityFightPropUpdateNotify := new(proto.EntityFightPropUpdateNotify)
entityFightPropUpdateNotify.EntityId = target.id
entityFightPropUpdateNotify.FightPropMap = make(map[uint32]float32)
entityFightPropUpdateNotify.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP)] = currHp
for _, player := range s.playerMap {
gameManager.SendMsg(proto.ApiEntityFightPropUpdateNotify, player.PlayerID, player.ClientSeq, entityFightPropUpdateNotify)
}
combatData, err := pb.Marshal(hitInfo)
if err != nil {
logger.LOG.Error("create combat invocations entity hit info error: %v", err)
}
attack.combatInvokeEntry.CombatData = combatData
switch attack.combatInvokeEntry.ForwardType {
case proto.ForwardType_FORWARD_TYPE_TO_ALL:
combatInvokeEntryListAll = append(combatInvokeEntryListAll, attack.combatInvokeEntry)
case proto.ForwardType_FORWARD_TYPE_TO_ALL_EXCEPT_CUR:
fallthrough
case proto.ForwardType_FORWARD_TYPE_TO_ALL_EXIST_EXCEPT_CUR:
if combatInvokeEntryListOther[attack.uid] == nil {
combatInvokeEntryListOther[attack.uid] = make([]*proto.CombatInvokeEntry, 0)
}
combatInvokeEntryListOther[attack.uid] = append(combatInvokeEntryListOther[attack.uid], attack.combatInvokeEntry)
case proto.ForwardType_FORWARD_TYPE_TO_HOST:
combatInvokeEntryListHost = append(combatInvokeEntryListHost, attack.combatInvokeEntry)
default:
}
}
// PacketCombatInvocationsNotify
if len(combatInvokeEntryListAll) > 0 {
combatInvocationsNotifyAll := new(proto.CombatInvocationsNotify)
combatInvocationsNotifyAll.InvokeList = combatInvokeEntryListAll
for _, player := range s.playerMap {
gameManager.SendMsg(proto.ApiCombatInvocationsNotify, player.PlayerID, player.ClientSeq, combatInvocationsNotifyAll)
}
}
if len(combatInvokeEntryListOther) > 0 {
for uid, list := range combatInvokeEntryListOther {
combatInvocationsNotifyOther := new(proto.CombatInvocationsNotify)
combatInvocationsNotifyOther.InvokeList = list
for _, player := range s.playerMap {
if player.PlayerID == uid {
continue
}
gameManager.SendMsg(proto.ApiCombatInvocationsNotify, player.PlayerID, player.ClientSeq, combatInvocationsNotifyOther)
}
}
}
if len(combatInvokeEntryListHost) > 0 {
combatInvocationsNotifyHost := new(proto.CombatInvocationsNotify)
combatInvocationsNotifyHost.InvokeList = combatInvokeEntryListHost
gameManager.SendMsg(proto.ApiCombatInvocationsNotify, s.world.owner.PlayerID, s.world.owner.ClientSeq, combatInvocationsNotifyHost)
}
}

64
service/game-hk4e/go.mod Normal file
View File

@@ -0,0 +1,64 @@
module game-hk4e
go 1.19
require flswld.com/common v0.0.0-incompatible
replace flswld.com/common => ../../common
require flswld.com/logger v0.0.0-incompatible
replace flswld.com/logger => ../../logger
require flswld.com/air-api v0.0.0-incompatible // indirect
replace flswld.com/air-api => ../../air-api
require flswld.com/light v0.0.0-incompatible
replace flswld.com/light => ../../light
require flswld.com/gate-hk4e-api v0.0.0-incompatible
replace flswld.com/gate-hk4e-api => ../../gate-hk4e-api
// protobuf
require google.golang.org/protobuf v1.28.0
// mongodb
require go.mongodb.org/mongo-driver v1.8.3
// jwt
require github.com/golang-jwt/jwt/v4 v4.4.0
// csv
require github.com/jszwec/csvutil v1.7.1
// nats
require github.com/nats-io/nats.go v1.16.0
// msgpack
require github.com/vmihailenco/msgpack/v5 v5.3.5
// statsviz
require github.com/arl/statsviz v0.5.1
require (
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/klauspost/compress v1.14.4 // indirect
github.com/nats-io/nats-server/v2 v2.8.4 // indirect
github.com/nats-io/nkeys v0.3.0 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.0.2 // indirect
github.com/xdg-go/stringprep v1.0.2 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
golang.org/x/text v0.3.6 // indirect
)

96
service/game-hk4e/go.sum Normal file
View File

@@ -0,0 +1,96 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/arl/statsviz v0.5.1 h1:3HY0ZEB738JtguWsD1Tf1pFJZiCcWUmYRq/3OTYKaSI=
github.com/arl/statsviz v0.5.1/go.mod h1:zDnjgRblGm1Dyd7J5YlbH7gM1/+HRC+SfkhZhQb5AnM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/golang-jwt/jwt/v4 v4.4.0 h1:EmVIxB5jzbllGIjiCV5JG4VylbK3KE400tLGLI1cdfU=
github.com/golang-jwt/jwt/v4 v4.4.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/jszwec/csvutil v1.7.1 h1:btxPxFwms8lHMgl0OIgOQ4Tayfqo0xid0hGkq1kM510=
github.com/jszwec/csvutil v1.7.1/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.14.4 h1:eijASRJcobkVtSt81Olfh7JX43osYLwy5krOJo6YEu4=
github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/nats-io/jwt/v2 v2.2.1-0.20220330180145-442af02fd36a h1:lem6QCvxR0Y28gth9P+wV2K/zYUUAkJ+55U8cpS0p5I=
github.com/nats-io/nats-server/v2 v2.8.4 h1:0jQzze1T9mECg8YZEl8+WYUXb9JKluJfCBriPUtluB4=
github.com/nats-io/nats-server/v2 v2.8.4/go.mod h1:8zZa+Al3WsESfmgSs98Fi06dRWLH5Bnq90m5bKD/eT4=
github.com/nats-io/nats.go v1.16.0 h1:zvLE7fGBQYW6MWaFaRdsgm9qT39PJDQoju+DS8KsO1g=
github.com/nats-io/nats.go v1.16.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
go.mongodb.org/mongo-driver v1.8.3 h1:TDKlTkGDKm9kkJVUOAXDK5/fkqKHJVwYQSpoRfB43R4=
go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/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-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
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.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,111 @@
package model
import (
"game-hk4e/constant"
)
type Item struct {
ItemId uint32 `bson:"itemId"` // 道具id
Count uint32 `bson:"count"` // 道具数量
Guid uint64 `bson:"-"`
}
func (p *Player) InitAllItem() {
for itemId, item := range p.ItemMap {
item.Guid = p.GetNextGameObjectGuid()
p.ItemMap[itemId] = item
}
}
func (p *Player) GetItemGuid(itemId uint32) uint64 {
itemInfo := p.ItemMap[itemId]
if itemInfo == nil {
return 0
}
return itemInfo.Guid
}
func (p *Player) GetItemCount(itemId uint32) uint32 {
isVirtualItem, prop := p.GetVirtualItemProp(itemId)
if isVirtualItem {
value := p.PropertiesMap[prop]
return value
} else {
itemInfo := p.ItemMap[itemId]
if itemInfo == nil {
return 0
}
return itemInfo.Count
}
}
// 虚拟道具如下 实际值存在玩家的属性上
// 原石 201
// 摩拉 202
// 创世结晶 203
// 树脂 106
// 传说任务钥匙 107
// 洞天宝钱 204
func (p *Player) GetVirtualItemProp(itemId uint32) (isVirtualItem bool, prop uint16) {
switch itemId {
case 106:
return true, constant.PlayerPropertyConst.PROP_PLAYER_RESIN
case 107:
return true, constant.PlayerPropertyConst.PROP_PLAYER_LEGENDARY_KEY
case 201:
return true, constant.PlayerPropertyConst.PROP_PLAYER_HCOIN
case 202:
return true, constant.PlayerPropertyConst.PROP_PLAYER_SCOIN
case 203:
return true, constant.PlayerPropertyConst.PROP_PLAYER_MCOIN
case 204:
return true, constant.PlayerPropertyConst.PROP_PLAYER_HOME_COIN
default:
return false, 0
}
}
func (p *Player) AddItem(itemId uint32, count uint32) {
isVirtualItem, prop := p.GetVirtualItemProp(itemId)
if isVirtualItem {
value := p.PropertiesMap[prop]
value += count
p.PropertiesMap[prop] = value
} else {
itemInfo := p.ItemMap[itemId]
if itemInfo == nil {
itemInfo = &Item{
ItemId: itemId,
Count: 0,
Guid: p.GetNextGameObjectGuid(),
}
}
itemInfo.Count += count
p.ItemMap[itemId] = itemInfo
}
}
func (p *Player) CostItem(itemId uint32, count uint32) {
isVirtualItem, prop := p.GetVirtualItemProp(itemId)
if isVirtualItem {
value := p.PropertiesMap[prop]
if value < count {
value = 0
} else {
value -= count
}
p.PropertiesMap[prop] = value
} else {
itemInfo := p.ItemMap[itemId]
if itemInfo == nil {
return
}
if itemInfo.Count < count {
itemInfo.Count = 0
} else {
itemInfo.Count -= count
}
p.ItemMap[itemId] = itemInfo
}
}

View File

@@ -0,0 +1,173 @@
package model
import (
gdc "game-hk4e/config"
"game-hk4e/constant"
"time"
)
type Avatar struct {
AvatarId uint32 `bson:"avatarId"` // 角色id
Level uint8 `bson:"level"` // 等级
Exp uint32 `bson:"exp"` // 经验值
Promote uint8 `bson:"promote"` // 突破等阶
Satiation uint32 `bson:"satiation"` // 饱食度
SatiationPenalty uint32 `bson:"satiationPenalty"` // 饱食度溢出
CurrHP float64 `bson:"currHP"` // 当前生命值
CurrEnergy float64 `bson:"currEnergy"` // 当前元素能量值
FetterList []uint32 `bson:"fetterList"` // 资料解锁条目
SkillLevelMap map[uint32]uint32 `bson:"skillLevelMap"` // 技能等级
SkillExtraChargeMap map[uint32]uint32 `bson:"skillExtraChargeMap"`
ProudSkillBonusMap map[uint32]uint32 `bson:"proudSkillBonusMap"`
SkillDepotId uint32 `bson:"skillDepotId"`
CoreProudSkillLevel uint8 `bson:"coreProudSkillLevel"` // 已解锁命之座层数
TalentIdList []uint32 `bson:"talentIdList"` // 已解锁命之座技能列表
ProudSkillList []uint32 `bson:"proudSkillList"` // 被动技能列表
FlyCloak uint32 `bson:"flyCloak"` // 当前风之翼
Costume uint32 `bson:"costume"` // 当前衣装
BornTime int64 `bson:"bornTime"` // 获得时间
FetterLevel uint8 `bson:"fetterLevel"` // 好感度等级
FetterExp uint32 `bson:"fetterExp"` // 好感度经验
NameCardRewardId uint32 `bson:"nameCardRewardId"`
NameCardId uint32 `bson:"nameCardId"`
Guid uint64 `bson:"-"`
EquipGuidList map[uint64]uint64 `bson:"-"`
EquipWeapon *Weapon `bson:"-"`
EquipReliquaryList []*Reliquary `bson:"-"`
FightPropMap map[uint32]float32 `bson:"-"`
ExtraAbilityEmbryos map[string]bool `bson:"-"`
}
func (p *Player) InitAllAvatar() {
for _, avatar := range p.AvatarMap {
p.InitAvatar(avatar)
}
}
func (p *Player) InitAvatar(avatar *Avatar) {
avatarDataConfig := gdc.CONF.AvatarDataMap[int32(avatar.AvatarId)]
// 角色战斗属性
avatar.FightPropMap = make(map[uint32]float32)
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_NONE)] = 0.0
// 白字攻防血
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_ATTACK)] = float32(avatarDataConfig.GetBaseAttackByLevel(avatar.Level))
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_DEFENSE)] = float32(avatarDataConfig.GetBaseDefenseByLevel(avatar.Level))
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_HP)] = float32(avatarDataConfig.GetBaseHpByLevel(avatar.Level))
// 白字+绿字攻防血
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK)] = float32(avatarDataConfig.GetBaseAttackByLevel(avatar.Level))
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_DEFENSE)] = float32(avatarDataConfig.GetBaseDefenseByLevel(avatar.Level))
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP)] = float32(avatarDataConfig.GetBaseHpByLevel(avatar.Level))
// 当前血量
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP)] = float32(avatar.CurrHP)
// 双暴
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL)] = float32(avatarDataConfig.Critical)
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL_HURT)] = float32(avatarDataConfig.CriticalHurt)
// 元素充能
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CHARGE_EFFICIENCY)] = 1.0
p.SetCurrEnergy(avatar, avatar.CurrEnergy, true)
// guid
avatar.Guid = p.GetNextGameObjectGuid()
p.GameObjectGuidMap[avatar.Guid] = GameObject(avatar)
avatar.EquipGuidList = make(map[uint64]uint64)
p.AvatarMap[avatar.AvatarId] = avatar
return
}
func (p *Player) AddAvatar(avatarId uint32) {
avatarDataConfig := gdc.CONF.AvatarDataMap[int32(avatarId)]
skillDepotId := int32(0)
// 主角要单独设置
if avatarId == 10000005 {
skillDepotId = 504
} else if avatarId == 10000007 {
skillDepotId = 704
} else {
skillDepotId = avatarDataConfig.SkillDepotId
}
avatarSkillDepotDataConfig := gdc.CONF.AvatarSkillDepotDataMap[skillDepotId]
avatar := &Avatar{
AvatarId: avatarId,
Level: 1,
Exp: 0,
Promote: 0,
Satiation: 0,
SatiationPenalty: 0,
CurrHP: 0,
CurrEnergy: 0,
FetterList: nil,
SkillLevelMap: make(map[uint32]uint32),
SkillExtraChargeMap: make(map[uint32]uint32),
ProudSkillBonusMap: nil,
SkillDepotId: uint32(avatarSkillDepotDataConfig.Id),
CoreProudSkillLevel: 0,
TalentIdList: make([]uint32, 0),
ProudSkillList: make([]uint32, 0),
FlyCloak: 140001,
Costume: 0,
BornTime: time.Now().Unix(),
FetterLevel: 1,
FetterExp: 0,
NameCardRewardId: 0,
NameCardId: 0,
Guid: 0,
EquipGuidList: nil,
EquipWeapon: nil,
EquipReliquaryList: nil,
FightPropMap: nil,
ExtraAbilityEmbryos: nil,
}
if avatarSkillDepotDataConfig.EnergySkill > 0 {
avatar.SkillLevelMap[uint32(avatarSkillDepotDataConfig.EnergySkill)] = 1
}
for _, skillId := range avatarSkillDepotDataConfig.Skills {
if skillId > 0 {
avatar.SkillLevelMap[uint32(skillId)] = 1
}
}
for _, openData := range avatarSkillDepotDataConfig.InherentProudSkillOpens {
if openData.ProudSkillGroupId == 0 {
continue
}
if openData.NeedAvatarPromoteLevel <= int32(avatar.Promote) {
proudSkillId := (openData.ProudSkillGroupId * 100) + 1
// TODO if GameData.getProudSkillDataMap().containsKey(proudSkillId) java
avatar.ProudSkillList = append(avatar.ProudSkillList, uint32(proudSkillId))
}
}
avatar.CurrHP = avatarDataConfig.GetBaseHpByLevel(avatar.Level)
p.InitAvatar(avatar)
p.AvatarMap[avatarId] = avatar
}
func (p *Player) SetCurrEnergy(avatar *Avatar, value float64, max bool) {
avatarDataConfig := gdc.CONF.AvatarDataMap[int32(avatar.AvatarId)]
avatarSkillDepotDataConfig := gdc.CONF.AvatarSkillDepotDataMap[avatarDataConfig.SkillDepotId]
if avatarSkillDepotDataConfig == nil || avatarSkillDepotDataConfig.EnergySkillData == nil {
return
}
element := avatarSkillDepotDataConfig.ElementType
avatar.FightPropMap[uint32(element.MaxEnergyProp)] = float32(avatarSkillDepotDataConfig.EnergySkillData.CostElemVal)
if max {
avatar.FightPropMap[uint32(element.CurrEnergyProp)] = float32(avatarSkillDepotDataConfig.EnergySkillData.CostElemVal)
} else {
avatar.FightPropMap[uint32(element.CurrEnergyProp)] = float32(value)
}
}
func (p *Player) WearWeapon(avatarId uint32, weaponId uint64) {
avatar := p.AvatarMap[avatarId]
weapon := p.WeaponMap[weaponId]
avatar.EquipWeapon = weapon
weapon.AvatarId = avatarId
avatar.EquipGuidList[weapon.Guid] = weapon.Guid
}
func (p *Player) TakeOffWeapon(avatarId uint32, weaponId uint64) {
avatar := p.AvatarMap[avatarId]
weapon := p.WeaponMap[weaponId]
avatar.EquipWeapon = nil
weapon.AvatarId = 0
delete(avatar.EquipGuidList, weapon.Guid)
}

View File

@@ -0,0 +1,16 @@
package model
const (
ChatMsgTypeText = iota
ChatMsgTypeIcon
)
type ChatMsg struct {
Time uint32 `bson:"time"`
ToUid uint32 `bson:"toUid"`
Uid uint32 `bson:"uid"`
IsRead bool `bson:"isRead"`
MsgType uint8 `bson:"msgType"`
Text string `bson:"text"`
Icon uint32 `bson:"icon"`
}

View File

@@ -0,0 +1,51 @@
package model
type GachaPoolInfo struct {
GachaType uint32 `bson:"gachaType"` // 卡池类型
OrangeTimes uint32 `bson:"orangeTimes"` // 5星保底计数
PurpleTimes uint32 `bson:"purpleTimes"` // 4星保底计数
MustGetUpOrange bool `bson:"mustGetUpOrange"` // 是否5星大保底
MustGetUpPurple bool `bson:"mustGetUpPurple"` // 是否4星大保底
}
type DropInfo struct {
GachaPoolInfo map[uint32]*GachaPoolInfo `bson:"gachaPoolInfo"`
}
func NewDropInfo() (r *DropInfo) {
r = new(DropInfo)
r.GachaPoolInfo = make(map[uint32]*GachaPoolInfo)
r.GachaPoolInfo[300] = &GachaPoolInfo{
// 温迪
GachaType: 300,
OrangeTimes: 0,
PurpleTimes: 0,
MustGetUpOrange: false,
MustGetUpPurple: false,
}
r.GachaPoolInfo[400] = &GachaPoolInfo{
// 可莉
GachaType: 400,
OrangeTimes: 0,
PurpleTimes: 0,
MustGetUpOrange: false,
MustGetUpPurple: false,
}
r.GachaPoolInfo[431] = &GachaPoolInfo{
// 阿莫斯之弓&天空之傲
GachaType: 431,
OrangeTimes: 0,
PurpleTimes: 0,
MustGetUpOrange: false,
MustGetUpPurple: false,
}
r.GachaPoolInfo[201] = &GachaPoolInfo{
// 常驻
GachaType: 201,
OrangeTimes: 0,
PurpleTimes: 0,
MustGetUpOrange: false,
MustGetUpPurple: false,
}
return r
}

View File

@@ -0,0 +1,93 @@
package model
import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
const (
DbInsert = iota
DbDelete
DbUpdate
DbNormal
DbOffline
)
const (
SceneNone = iota
SceneInitFinish
SceneEnterDone
)
type GameObject interface {
}
type Player struct {
// 离线数据
ID primitive.ObjectID `bson:"_id,omitempty"`
PlayerID uint32 `bson:"playerID"` // 玩家uid
NickName string `bson:"nickname"` // 玩家昵称
Signature string `bson:"signature"` // 玩家签名
HeadImage uint32 `bson:"headImage"` // 玩家头像
NameCard uint32 `bson:"nameCard"` // 当前名片
NameCardList []uint32 `bson:"nameCardList"` // 已解锁名片列表
FriendList map[uint32]bool `bson:"friendList"` // 好友uid列表
FriendApplyList map[uint32]bool `bson:"friendApplyList"` // 好友申请uid列表
OfflineTime uint32 `bson:"offlineTime"` // 离线时间点
OnlineTime uint32 `bson:"onlineTime"` // 上线时间点
TotalOnlineTime uint32 `bson:"totalOnlineTime"` // 玩家累计在线时长
PropertiesMap map[uint16]uint32 `bson:"propertiesMap"` // 玩家自身相关的一些属性
RegionId uint32 `bson:"regionId"` // regionId
FlyCloakList []uint32 `bson:"flyCloakList"` // 风之翼列表
CostumeList []uint32 `bson:"costumeList"` // 角色衣装列表
SceneId uint32 `bson:"sceneId"` // 场景
Pos *Vector `bson:"pos"` // 玩家坐标
Rot *Vector `bson:"rot"` // 玩家朝向
ItemMap map[uint32]*Item `bson:"itemMap"` // 玩家统一大背包仓库
WeaponMap map[uint64]*Weapon `bson:"weaponMap"` // 玩家武器背包
ReliquaryMap map[uint64]*Reliquary `bson:"reliquaryMap"` // 玩家圣遗物背包
TeamConfig *TeamInfo `bson:"teamConfig"` // 队伍配置
AvatarMap map[uint32]*Avatar `bson:"avatarMap"` // 角色信息
DropInfo *DropInfo `bson:"dropInfo"` // 掉落信息
MainCharAvatarId uint32 `bson:"mainCharAvatarId"` // 主角id
ChatMsgMap map[uint32][]*ChatMsg `bson:"chatMsgMap"` // 聊天信息
// 在线数据
EnterSceneToken uint32 `bson:"-"` // 玩家的世界进入令牌
DbState int `bson:"-"` // 数据库存档状态
WorldId uint32 `bson:"-"` // 所在的世界id
PeerId uint32 `bson:"-"` // 多人世界的玩家编号
GameObjectGuidCounter uint64 `bson:"-"` // 游戏对象guid计数器
ClientTime uint32 `bson:"-"` // 玩家客户端的本地时钟
ClientRTT uint32 `bson:"-"` // 玩家客户端往返时延
GameObjectGuidMap map[uint64]GameObject `bson:"-"` // 游戏对象guid映射表
Online bool `bson:"-"` // 在线状态
Pause bool `bson:"-"` // 暂停状态
SceneLoadState int `bson:"-"` // 场景加载状态
CoopApplyMap map[uint32]int64 `bson:"-"` // 敲门申请的玩家uid及时间
ClientSeq uint32 `bson:"-"`
}
func (p *Player) GetNextGameObjectGuid() uint64 {
p.GameObjectGuidCounter++
return uint64(p.PlayerID)<<32 + p.GameObjectGuidCounter
}
func (p *Player) InitAll() {
p.GameObjectGuidMap = make(map[uint64]GameObject)
p.CoopApplyMap = make(map[uint32]int64)
p.InitAllAvatar()
p.InitAllWeapon()
p.InitAllItem()
p.InitAllReliquary()
}
func (p *Player) InitAllReliquary() {
for reliquaryId, reliquary := range p.ReliquaryMap {
reliquary.Guid = p.GetNextGameObjectGuid()
p.ReliquaryMap[reliquaryId] = reliquary
if reliquary.AvatarId != 0 {
avatar := p.AvatarMap[reliquary.AvatarId]
avatar.EquipGuidList[reliquary.Guid] = reliquary.Guid
avatar.EquipReliquaryList = append(avatar.EquipReliquaryList, reliquary)
}
}
}

View File

@@ -0,0 +1,16 @@
package model
type Reliquary struct {
ReliquaryId uint64 `bson:"reliquaryId"` // 圣遗物的唯一id
ItemId uint32 `bson:"itemId"` // 圣遗物的道具id
Level uint8 `bson:"level"` // 等级
Exp uint32 `bson:"exp"` // 当前经验值
TotalExp uint32 `bson:"totalExp"` // 升级所需总经验值
Promote uint8 `bson:"promote"` // 突破等阶
Lock bool `bson:"lock"` // 锁定状态
AffixIdList []uint32 `bson:"affixIdList"` // 词缀
Refinement uint8 `bson:"refinement"` // 精炼等阶
MainPropId uint32 `bson:"mainPropId"` // 主词条id
AvatarId uint32 `bson:"avatarId"` // 装备角色id
Guid uint64 `bson:"-"`
}

View File

@@ -0,0 +1,115 @@
package model
import (
gdc "game-hk4e/config"
"game-hk4e/constant"
)
type Team struct {
Name string `bson:"name"`
AvatarIdList []uint32 `bson:"avatarIdList"`
}
type TeamInfo struct {
TeamList []*Team `bson:"teamList"`
CurrTeamIndex uint8 `bson:"currTeamIndex"`
CurrAvatarIndex uint8 `bson:"currAvatarIndex"`
TeamResonances map[uint16]bool `bson:"-"`
TeamResonancesConfig map[int32]bool `bson:"-"`
}
func NewTeamInfo() (r *TeamInfo) {
r = &TeamInfo{
TeamList: []*Team{
{Name: "冒险", AvatarIdList: make([]uint32, 4)},
{Name: "委托", AvatarIdList: make([]uint32, 4)},
{Name: "秘境", AvatarIdList: make([]uint32, 4)},
{Name: "联机", AvatarIdList: make([]uint32, 4)},
},
CurrTeamIndex: 0,
CurrAvatarIndex: 0,
}
return r
}
func (t *TeamInfo) UpdateTeam() {
activeTeam := t.GetActiveTeam()
// 队伍元素共鸣
t.TeamResonances = make(map[uint16]bool)
t.TeamResonancesConfig = make(map[int32]bool)
teamElementTypeCountMap := make(map[uint16]uint8)
avatarSkillDepotDataMapConfig := gdc.CONF.AvatarSkillDepotDataMap
for _, avatarId := range activeTeam.AvatarIdList {
if avatarId == 0 {
break
}
skillData := avatarSkillDepotDataMapConfig[int32(avatarId)]
if skillData != nil {
teamElementTypeCountMap[skillData.ElementType.Value] += 1
}
}
for k, v := range teamElementTypeCountMap {
if v >= 2 {
element := constant.ElementTypeConst.VALUE_MAP[k]
if element.TeamResonanceId != 0 {
t.TeamResonances[element.TeamResonanceId] = true
t.TeamResonancesConfig[element.ConfigHash] = true
}
}
}
if len(t.TeamResonances) == 0 {
t.TeamResonances[constant.ElementTypeConst.Default.TeamResonanceId] = true
t.TeamResonancesConfig[int32(constant.ElementTypeConst.Default.TeamResonanceId)] = true
}
}
func (t *TeamInfo) GetActiveTeamId() uint8 {
return t.CurrTeamIndex + 1
}
func (t *TeamInfo) GetTeamByIndex(teamIndex uint8) *Team {
if t.TeamList == nil {
return nil
}
if teamIndex >= uint8(len(t.TeamList)) {
return nil
}
activeTeam := t.TeamList[teamIndex]
return activeTeam
}
func (t *TeamInfo) GetActiveTeam() *Team {
return t.GetTeamByIndex(t.CurrTeamIndex)
}
func (t *TeamInfo) ClearTeamAvatar(teamIndex uint8) {
team := t.GetTeamByIndex(teamIndex)
if team == nil {
return
}
team.AvatarIdList = make([]uint32, 4)
}
func (t *TeamInfo) AddAvatarToTeam(avatarId uint32, teamIndex uint8) {
team := t.GetTeamByIndex(teamIndex)
if team == nil {
return
}
for i, v := range team.AvatarIdList {
if v == 0 {
team.AvatarIdList[i] = avatarId
break
}
}
}
func (t *TeamInfo) GetActiveAvatarId() uint32 {
activeTeam := t.GetActiveTeam()
if activeTeam == nil {
return 0
}
if t.CurrAvatarIndex >= uint8(len(activeTeam.AvatarIdList)) {
return 0
}
return activeTeam.AvatarIdList[t.CurrAvatarIndex]
}

View File

@@ -0,0 +1,7 @@
package model
type Vector struct {
X float64 `bson:"x"`
Y float64 `bson:"y"`
Z float64 `bson:"z"`
}

View File

@@ -0,0 +1,76 @@
package model
import (
gdc "game-hk4e/config"
)
type Weapon struct {
WeaponId uint64 `bson:"weaponId"` // 武器的唯一id
ItemId uint32 `bson:"itemId"` // 武器的道具id
Level uint8 `bson:"level"` // 等级
Exp uint32 `bson:"exp"` // 当前经验值
TotalExp uint32 `bson:"totalExp"` // 升级所需总经验值
Promote uint8 `bson:"promote"` // 突破等阶
Lock bool `bson:"lock"` // 锁定状态
AffixIdList []uint32 `bson:"affixIdList"` // 词缀
Refinement uint8 `bson:"refinement"` // 精炼等阶
MainPropId uint32 `bson:"mainPropId"` // 主词条id
AvatarId uint32 `bson:"avatarId"` // 装备角色id
Guid uint64 `bson:"-"`
}
func (p *Player) InitWeapon(weapon *Weapon) {
weapon.Guid = p.GetNextGameObjectGuid()
p.GameObjectGuidMap[weapon.Guid] = GameObject(weapon)
p.WeaponMap[weapon.WeaponId] = weapon
if weapon.AvatarId != 0 {
avatar := p.AvatarMap[weapon.AvatarId]
avatar.EquipGuidList[weapon.Guid] = weapon.Guid
avatar.EquipWeapon = weapon
}
return
}
func (p *Player) InitAllWeapon() {
for _, weapon := range p.WeaponMap {
p.InitWeapon(weapon)
}
}
func (p *Player) GetWeaponGuid(weaponId uint64) uint64 {
weaponInfo := p.WeaponMap[weaponId]
if weaponInfo == nil {
return 0
}
return weaponInfo.Guid
}
func (p *Player) GetWeapon(weaponId uint64) *Weapon {
return p.WeaponMap[weaponId]
}
func (p *Player) AddWeapon(itemId uint32, weaponId uint64) {
weapon := &Weapon{
WeaponId: weaponId,
ItemId: itemId,
Level: 1,
Exp: 0,
TotalExp: 0,
Promote: 0,
Lock: false,
AffixIdList: make([]uint32, 0),
Refinement: 0,
MainPropId: 0,
Guid: 0,
}
itemDataConfig := gdc.CONF.ItemDataMap[int32(itemId)]
if itemDataConfig.SkillAffix != nil {
for _, skillAffix := range itemDataConfig.SkillAffix {
if skillAffix > 0 {
weapon.AffixIdList = append(weapon.AffixIdList, uint32(skillAffix))
}
}
}
p.InitWeapon(weapon)
p.WeaponMap[weaponId] = weapon
}

View File

@@ -0,0 +1,91 @@
package mq
import (
"flswld.com/common/config"
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
"github.com/nats-io/nats.go"
"github.com/vmihailenco/msgpack/v5"
pb "google.golang.org/protobuf/proto"
)
type MessageQueue struct {
natsConn *nats.Conn
natsMsgChan chan *nats.Msg
netMsgInput chan *proto.NetMsg
netMsgOutput chan *proto.NetMsg
apiProtoMap *proto.ApiProtoMap
}
func NewMessageQueue(netMsgInput chan *proto.NetMsg, netMsgOutput chan *proto.NetMsg) (r *MessageQueue) {
r = new(MessageQueue)
conn, err := nats.Connect(config.CONF.MQ.NatsUrl)
if err != nil {
logger.LOG.Error("connect nats error: %v", err)
return nil
}
r.natsConn = conn
r.natsMsgChan = make(chan *nats.Msg, 10000)
_, err = r.natsConn.ChanSubscribe("GAME_HK4E", r.natsMsgChan)
if err != nil {
logger.LOG.Error("nats subscribe error: %v", err)
return nil
}
r.netMsgInput = netMsgInput
r.netMsgOutput = netMsgOutput
r.apiProtoMap = proto.NewApiProtoMap()
return r
}
func (m *MessageQueue) Start() {
go m.startRecvHandler()
go m.startSendHandler()
}
func (m *MessageQueue) Close() {
m.natsConn.Close()
}
func (m *MessageQueue) startRecvHandler() {
for {
natsMsg := <-m.natsMsgChan
// msgpack NetMsg
netMsg := new(proto.NetMsg)
err := msgpack.Unmarshal(natsMsg.Data, netMsg)
if err != nil {
logger.LOG.Error("parse bin to net msg error: %v", err)
continue
}
if netMsg.EventId == proto.NormalMsg || netMsg.EventId == proto.UserRegNotify {
// protobuf PayloadMessage
payloadMessage := m.apiProtoMap.GetProtoObjByApiId(netMsg.ApiId)
err = pb.Unmarshal(netMsg.PayloadMessageData, payloadMessage)
if err != nil {
logger.LOG.Error("parse bin to payload msg error: %v", err)
continue
}
netMsg.PayloadMessage = payloadMessage
}
m.netMsgOutput <- netMsg
}
}
func (m *MessageQueue) startSendHandler() {
for {
netMsg := <-m.netMsgInput
// protobuf PayloadMessage 已在上一层完成
// msgpack NetMsg
netMsgData, err := msgpack.Marshal(netMsg)
if err != nil {
logger.LOG.Error("parse net msg to bin error: %v", err)
continue
}
natsMsg := nats.NewMsg("GATE_HK4E")
natsMsg.Data = netMsgData
err = m.natsConn.PublishMsg(natsMsg)
if err != nil {
logger.LOG.Error("nats publish msg error: %v", err)
continue
}
}
}

View File

@@ -0,0 +1,29 @@
package rpc
import (
"flswld.com/gate-hk4e-api/gm"
"flswld.com/light"
)
type RpcManager struct {
hk4eGatewayConsumer *light.Consumer
}
func NewRpcManager(hk4eGatewayConsumer *light.Consumer) (r *RpcManager) {
r = new(RpcManager)
r.hk4eGatewayConsumer = hk4eGatewayConsumer
return r
}
func (r *RpcManager) SendKickPlayerToHk4eGateway(userId uint32) {
info := new(gm.KickPlayerInfo)
info.UserId = userId
// 客户端提示信息为服务器断开连接
info.Reason = uint32(5)
var result bool
ok := r.hk4eGatewayConsumer.CallFunction("RpcManager", "KickPlayer", &info, &result)
if ok == true && result == true {
return
}
return
}

View File

@@ -0,0 +1,11 @@
http_port = 9004
[logger]
level = "DEBUG"
method = "CONSOLE"
track_line = true
[air]
addr = "air"
port = 8086
service_name = "gm-hk4e-app"

View File

@@ -0,0 +1,48 @@
package main
import (
"flswld.com/common/config"
"flswld.com/light"
"flswld.com/logger"
"gm-hk4e/controller"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
filePath := "./application.toml"
config.InitConfig(filePath)
logger.InitLogger()
logger.LOG.Info("gm hk4e start")
httpProvider := light.NewHttpProvider()
// 认证服务
rpcWaterAuthConsumer := light.NewRpcConsumer("water-auth")
rpcHk4eGatewayConsumer := light.NewRpcConsumer("hk4e-gateway")
_ = controller.NewController(rpcWaterAuthConsumer, rpcHk4eGatewayConsumer)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
logger.LOG.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
rpcWaterAuthConsumer.CloseRpcConsumer()
rpcHk4eGatewayConsumer.CloseRpcConsumer()
httpProvider.CloseHttpProvider()
logger.LOG.Info("gm hk4e exit")
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,75 @@
package controller
import (
"flswld.com/common/config"
"flswld.com/light"
waterAuth "flswld.com/water-api/auth"
"github.com/gin-gonic/gin"
"net/http"
"strconv"
"strings"
)
type Controller struct {
rpcWaterAuthConsumer *light.Consumer
rpcHk4eGatewayConsumer *light.Consumer
}
func NewController(rpcWaterAuthConsumer *light.Consumer, rpcHk4eGatewayConsumer *light.Consumer) (r *Controller) {
r = new(Controller)
r.rpcWaterAuthConsumer = rpcWaterAuthConsumer
r.rpcHk4eGatewayConsumer = rpcHk4eGatewayConsumer
go r.registerRouter()
return r
}
func (c *Controller) getAccessToken(context *gin.Context) string {
accessToken := context.GetHeader("Authorization")
divIndex := strings.Index(accessToken, " ")
if divIndex > 0 {
payload := accessToken[divIndex+1:]
return payload
} else {
return ""
}
}
// access_token鉴权
func (c *Controller) authorize() gin.HandlerFunc {
return func(context *gin.Context) {
valid, err := waterAuth.WaterVerifyAccessToken(c.rpcWaterAuthConsumer, c.getAccessToken(context))
if err == nil && valid == true {
// 验证通过
context.Next()
return
}
// 验证不通过
context.Abort()
context.JSON(http.StatusOK, gin.H{
"code": "10001",
"msg": "没有访问权限",
})
}
}
func (c *Controller) registerRouter() {
if config.CONF.Logger.Level == "DEBUG" {
gin.SetMode(gin.DebugMode)
} else {
gin.SetMode(gin.ReleaseMode)
}
engine := gin.Default()
// gacha
engine.GET("/gm/gacha", c.gacha)
engine.GET("/gm/gacha/details", c.gachaDetails)
engine.Use(c.authorize())
// gate
engine.POST("/gm/gate/state", c.changeGateState)
engine.POST("/gm/gate/kick", c.kickPlayer)
engine.GET("/gm/gate/online", c.getOnlineUser)
engine.POST("/gm/gate/forbid", c.forbidUser)
engine.POST("/gm/gate/forbid/cancel", c.unForbidUser)
port := strconv.FormatInt(int64(config.CONF.HttpPort), 10)
portStr := ":" + port
_ = engine.Run(portStr)
}

View File

@@ -0,0 +1,65 @@
package controller
import (
"flswld.com/common/entity/dto"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v4"
"net/http"
)
type UserInfo struct {
UserId uint32 `json:"userId"`
jwt.RegisteredClaims
}
func (c *Controller) gacha(context *gin.Context) {
jwtStr := context.Query("jwt")
token, err := jwt.ParseWithClaims(jwtStr, new(UserInfo), func(token *jwt.Token) (interface{}, error) {
return []byte("flswld"), nil
})
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(10005, "验签失败", nil))
return
}
if !token.Valid {
context.JSON(http.StatusOK, dto.NewResponseResult(10005, "验签失败", nil))
return
}
info, ok := token.Claims.(*UserInfo)
if !ok {
context.JSON(http.StatusOK, dto.NewResponseResult(10005, "验签失败", nil))
return
}
gachaType := context.Query("gachaType")
rsp := map[string]any{
"uid": info.UserId,
"gachaType": gachaType,
}
context.JSON(http.StatusOK, dto.NewResponseResult(0, "成功", rsp))
}
func (c *Controller) gachaDetails(context *gin.Context) {
jwtStr := context.Query("jwt")
token, err := jwt.ParseWithClaims(jwtStr, new(UserInfo), func(token *jwt.Token) (interface{}, error) {
return []byte("flswld"), nil
})
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(10005, "验签失败", nil))
return
}
if !token.Valid {
context.JSON(http.StatusOK, dto.NewResponseResult(10005, "验签失败", nil))
return
}
info, ok := token.Claims.(*UserInfo)
if !ok {
context.JSON(http.StatusOK, dto.NewResponseResult(10005, "验签失败", nil))
return
}
scheduleId := context.Query("scheduleId")
rsp := map[string]any{
"uid": info.UserId,
"scheduleId": scheduleId,
}
context.JSON(http.StatusOK, dto.NewResponseResult(0, "成功", rsp))
}

View File

@@ -0,0 +1,161 @@
package controller
import (
"flswld.com/common/entity/dto"
"flswld.com/gate-hk4e-api/gm"
waterAuth "flswld.com/water-api/auth"
"github.com/gin-gonic/gin"
"net/http"
"strconv"
)
func (c *Controller) changeGateState(context *gin.Context) {
accessToken := c.getAccessToken(context)
user, err := waterAuth.WaterQueryUserByAccessToken(c.rpcWaterAuthConsumer, accessToken)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(1001, "服务器内部错误", nil))
return
}
if !user.IsAdmin {
context.JSON(http.StatusOK, dto.NewResponseResult(10001, "没有访问权限", nil))
return
}
stateStr := context.Query("state")
state, err := strconv.ParseBool(stateStr)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(10003, "参数错误", nil))
return
}
var res bool
ok := c.rpcHk4eGatewayConsumer.CallFunction("RpcManager", "ChangeGateOpenState", &state, &res)
if ok == true && res == true {
context.JSON(http.StatusOK, dto.NewResponseResult(0, "操作成功", nil))
} else {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "操作失败", nil))
}
}
func (c *Controller) kickPlayer(context *gin.Context) {
accessToken := c.getAccessToken(context)
user, err := waterAuth.WaterQueryUserByAccessToken(c.rpcWaterAuthConsumer, accessToken)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(1001, "服务器内部错误", nil))
return
}
if !user.IsAdmin {
context.JSON(http.StatusOK, dto.NewResponseResult(10001, "没有访问权限", nil))
return
}
uidStr := context.Query("uid")
reasonStr := context.Query("reason")
uid, err := strconv.ParseInt(uidStr, 10, 64)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(10003, "参数错误", nil))
return
}
reason, err := strconv.ParseInt(reasonStr, 10, 64)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(10003, "参数错误", nil))
return
}
info := new(gm.KickPlayerInfo)
info.UserId = uint32(uid)
info.Reason = uint32(reason)
var result bool
ok := c.rpcHk4eGatewayConsumer.CallFunction("RpcManager", "KickPlayer", &info, &result)
if ok == true && result == true {
context.JSON(http.StatusOK, dto.NewResponseResult(0, "操作成功", nil))
} else {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "操作失败", nil))
}
}
func (c *Controller) getOnlineUser(context *gin.Context) {
accessToken := c.getAccessToken(context)
user, err := waterAuth.WaterQueryUserByAccessToken(c.rpcWaterAuthConsumer, accessToken)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(1001, "服务器内部错误", nil))
return
}
if !user.IsAdmin {
context.JSON(http.StatusOK, dto.NewResponseResult(10001, "没有访问权限", nil))
return
}
uidStr := context.Query("uid")
uid, err := strconv.ParseInt(uidStr, 10, 64)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(10003, "参数错误", nil))
return
}
list := new(gm.OnlineUserList)
list.UserList = make([]*gm.OnlineUserInfo, 0)
userId := uint32(uid)
ok := c.rpcHk4eGatewayConsumer.CallFunction("RpcManager", "GetOnlineUser", &userId, &list)
if ok {
context.JSON(http.StatusOK, dto.NewResponseResult(0, "查询成功", list))
} else {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "查询失败", nil))
}
}
func (c *Controller) forbidUser(context *gin.Context) {
accessToken := c.getAccessToken(context)
user, err := waterAuth.WaterQueryUserByAccessToken(c.rpcWaterAuthConsumer, accessToken)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(1001, "服务器内部错误", nil))
return
}
if !user.IsAdmin {
context.JSON(http.StatusOK, dto.NewResponseResult(10001, "没有访问权限", nil))
return
}
uidStr := context.Query("uid")
uid, err := strconv.ParseInt(uidStr, 10, 64)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(10003, "参数错误", nil))
return
}
endTimeStr := context.Query("endTime")
endTime, err := strconv.ParseInt(endTimeStr, 10, 64)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(10003, "参数错误", nil))
return
}
info := new(gm.ForbidUserInfo)
info.UserId = uint32(uid)
info.ForbidEndTime = uint64(endTime)
var result bool
ok := c.rpcHk4eGatewayConsumer.CallFunction("RpcManager", "ForbidUser", &info, &result)
if ok == true && result == true {
context.JSON(http.StatusOK, dto.NewResponseResult(0, "操作成功", nil))
} else {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "操作失败", nil))
}
}
func (c *Controller) unForbidUser(context *gin.Context) {
accessToken := c.getAccessToken(context)
user, err := waterAuth.WaterQueryUserByAccessToken(c.rpcWaterAuthConsumer, accessToken)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(1001, "服务器内部错误", nil))
return
}
if !user.IsAdmin {
context.JSON(http.StatusOK, dto.NewResponseResult(10001, "没有访问权限", nil))
return
}
uidStr := context.Query("uid")
uid, err := strconv.ParseInt(uidStr, 10, 64)
if err != nil {
context.JSON(http.StatusOK, dto.NewResponseResult(10003, "参数错误", nil))
return
}
userId := uint32(uid)
var result bool
ok := c.rpcHk4eGatewayConsumer.CallFunction("RpcManager", "UnForbidUser", &userId, &result)
if ok == true && result == true {
context.JSON(http.StatusOK, dto.NewResponseResult(0, "操作成功", nil))
} else {
context.JSON(http.StatusOK, dto.NewResponseResult(-1, "操作失败", nil))
}
}

53
service/gm-hk4e/go.mod Normal file
View File

@@ -0,0 +1,53 @@
module gm-hk4e
go 1.19
require flswld.com/common v0.0.0-incompatible
replace flswld.com/common => ../../common
require flswld.com/logger v0.0.0-incompatible
replace flswld.com/logger => ../../logger
require flswld.com/air-api v0.0.0-incompatible // indirect
replace flswld.com/air-api => ../../air-api
require flswld.com/light v0.0.0-incompatible
replace flswld.com/light => ../../light
require flswld.com/gate-hk4e-api v0.0.0-incompatible
replace flswld.com/gate-hk4e-api => ../../gate-hk4e-api
require (
flswld.com/annie-user-api v0.0.0-incompatible // indirect
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.2.0 // indirect
github.com/golang/protobuf v1.3.3 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
)
replace flswld.com/annie-user-api => ../annie-user-api
require flswld.com/water-api v0.0.0-incompatible
replace flswld.com/water-api => ../../water-api
// gin
require github.com/gin-gonic/gin v1.6.3
// jwt
require github.com/golang-jwt/jwt/v4 v4.4.0

50
service/gm-hk4e/go.sum Normal file
View File

@@ -0,0 +1,50 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/golang-jwt/jwt/v4 v4.4.0 h1:EmVIxB5jzbllGIjiCV5JG4VylbK3KE400tLGLI1cdfU=
github.com/golang-jwt/jwt/v4 v4.4.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -0,0 +1,43 @@
/*
Navicat Premium Data Transfer
Source Server : MySQL-Dev
Source Server Type : MySQL
Source Server Version : 50727
Source Host : 192.168.199.131:3306
Source Schema : annie_user
Target Server Type : MySQL
Target Server Version : 50727
File Encoding : 65001
Date: 25/05/2022 00:38:54
*/
SET NAMES utf8mb4;
SET
FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`
(
`uid` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`is_admin` tinyint(1) NULL DEFAULT NULL,
PRIMARY KEY (`uid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user`
VALUES (1, 'flswld', '25d55ad283aa400af464c76d713c07ad', 1);
INSERT INTO `user`
VALUES (2, 'fhqs', '25d55ad283aa400af464c76d713c07ad', 0);
SET
FOREIGN_KEY_CHECKS = 1;

View File

@@ -0,0 +1,59 @@
/*
Navicat Premium Data Transfer
Source Server : MySQL-Dev
Source Server Type : MySQL
Source Server Version : 50727
Source Host : 192.168.199.131:3306
Source Schema : annie_wxmp
Target Server Type : MySQL
Target Server Version : 50727
File Encoding : 65001
Date: 25/05/2022 00:39:11
*/
SET NAMES utf8mb4;
SET
FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for fw_death_info
-- ----------------------------
DROP TABLE IF EXISTS `fw_death_info`;
CREATE TABLE `fw_death_info`
(
`fdid` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`fw_alive` tinyint(1) NULL DEFAULT NULL,
`fw_cancel` tinyint(1) NULL DEFAULT NULL,
`fw_info` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`fdid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of fw_death_info
-- ----------------------------
INSERT INTO `fw_death_info`
VALUES (1, 1, 0, '你好');
-- ----------------------------
-- Table structure for fw_death_notify_user
-- ----------------------------
DROP TABLE IF EXISTS `fw_death_notify_user`;
CREATE TABLE `fw_death_notify_user`
(
`dnuid` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`wx_open_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`email` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`dnuid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of fw_death_notify_user
-- ----------------------------
INSERT INTO `fw_death_notify_user`
VALUES (1, 'oAuwFwB2-uoEeDQDUdleUbH5jAlI', '1782360262@qq.com');
SET
FOREIGN_KEY_CHECKS = 1;