mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-04 16:02:26 +08:00
优化代码
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
http_port = 8080
|
http_port = 8080
|
||||||
|
|
||||||
|
[hk4e]
|
||||||
|
dispatch_url = "https://hk4e.flswld.com/query_cur_region" # 二级dispatch地址 将域名改为dispatch的外网地址
|
||||||
|
|
||||||
[logger]
|
[logger]
|
||||||
level = "DEBUG"
|
level = "DEBUG"
|
||||||
mode = "CONSOLE"
|
mode = "CONSOLE"
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ type Hk4e struct {
|
|||||||
GateTcpMqPort int32 `toml:"gate_tcp_mq_port"`
|
GateTcpMqPort int32 `toml:"gate_tcp_mq_port"`
|
||||||
LoginSdkUrl string `toml:"login_sdk_url"` // 网关登录验证token的sdk服务器地址 目前填dispatch的内网地址
|
LoginSdkUrl string `toml:"login_sdk_url"` // 网关登录验证token的sdk服务器地址 目前填dispatch的内网地址
|
||||||
LoadSceneLuaConfig bool `toml:"load_scene_lua_config"` // 是否加载场景详情LUA配置数据
|
LoadSceneLuaConfig bool `toml:"load_scene_lua_config"` // 是否加载场景详情LUA配置数据
|
||||||
|
DispatchUrl string `toml:"dispatch_url"` // 二级dispatch地址 将域名改为dispatch的外网地址
|
||||||
}
|
}
|
||||||
|
|
||||||
// MQ 消息队列
|
// MQ 消息队列
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"hk4e/common/config"
|
||||||
"hk4e/pkg/endec"
|
"hk4e/pkg/endec"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
"hk4e/pkg/random"
|
"hk4e/pkg/random"
|
||||||
@@ -61,7 +62,7 @@ func GetRegionList(ec2b *random.Ec2b) *proto.QueryRegionListHttpRsp {
|
|||||||
Name: "os_usa",
|
Name: "os_usa",
|
||||||
Title: "America",
|
Title: "America",
|
||||||
Type: "DEV_PUBLIC",
|
Type: "DEV_PUBLIC",
|
||||||
DispatchUrl: "https://osusadispatch.yuanshen.com/query_cur_region",
|
DispatchUrl: config.GetConfig().Hk4e.DispatchUrl,
|
||||||
}
|
}
|
||||||
serverList = append(serverList, server)
|
serverList = append(serverList, server)
|
||||||
regionList := new(proto.QueryRegionListHttpRsp)
|
regionList := new(proto.QueryRegionListHttpRsp)
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func (c *Controller) getClientVersionByName(versionName string) (int, string) {
|
|||||||
func (c *Controller) queryCurRegion(context *gin.Context) {
|
func (c *Controller) queryCurRegion(context *gin.Context) {
|
||||||
rspError := func() {
|
rspError := func() {
|
||||||
rspContentError := "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw=="
|
rspContentError := "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw=="
|
||||||
rspSignError := "TW9yZSBsb3ZlIGZvciBVQSBQYXRjaCBwbGF5ZXJz"
|
rspSignError := ""
|
||||||
rsp := &httpapi.QueryCurRegionRspJson{
|
rsp := &httpapi.QueryCurRegionRspJson{
|
||||||
Content: rspContentError,
|
Content: rspContentError,
|
||||||
Sign: rspSignError,
|
Sign: rspSignError,
|
||||||
@@ -100,7 +100,6 @@ func (c *Controller) queryCurRegion(context *gin.Context) {
|
|||||||
_, _ = context.Writer.WriteString(regionCurrBase64)
|
_, _ = context.Writer.WriteString(regionCurrBase64)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Debug("do hk4e 2.8 rsa logic")
|
|
||||||
keyId := context.Query("key_id")
|
keyId := context.Query("key_id")
|
||||||
encPubPrivKey, exist := c.encRsaKeyMap[keyId]
|
encPubPrivKey, exist := c.encRsaKeyMap[keyId]
|
||||||
if !exist {
|
if !exist {
|
||||||
|
|||||||
@@ -457,7 +457,6 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
|
|||||||
serverSeedUint64 := timeRand.Uint64()
|
serverSeedUint64 := timeRand.Uint64()
|
||||||
session.seed = serverSeedUint64
|
session.seed = serverSeedUint64
|
||||||
if req.KeyId != 0 {
|
if req.KeyId != 0 {
|
||||||
logger.Debug("do hk4e 2.8 rsa logic, uid: %v", uid)
|
|
||||||
session.useMagicSeed = true
|
session.useMagicSeed = true
|
||||||
keyId := strconv.Itoa(int(req.KeyId))
|
keyId := strconv.Itoa(int(req.KeyId))
|
||||||
encPubPrivKey, exist := k.encRsaKeyMap[keyId]
|
encPubPrivKey, exist := k.encRsaKeyMap[keyId]
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -35,6 +36,8 @@ type GameDataConfig struct {
|
|||||||
ScenePointMap map[int32]*ScenePoint // 场景传送点
|
ScenePointMap map[int32]*ScenePoint // 场景传送点
|
||||||
SceneTagDataMap map[int32]*SceneTagData // 场景标签
|
SceneTagDataMap map[int32]*SceneTagData // 场景标签
|
||||||
SceneLuaConfigMap map[int32]*SceneLuaConfig // 场景LUA配置
|
SceneLuaConfigMap map[int32]*SceneLuaConfig // 场景LUA配置
|
||||||
|
GroupMap map[int32]*Group // 场景LUA区块group索引
|
||||||
|
LuaStateLruMap map[int32]*LuaStateLru // 场景LUA虚拟机LRU内存淘汰
|
||||||
WorldAreaDataMap map[int32]*WorldAreaData // 世界区域
|
WorldAreaDataMap map[int32]*WorldAreaData // 世界区域
|
||||||
GatherDataMap map[int32]*GatherData // 采集物
|
GatherDataMap map[int32]*GatherData // 采集物
|
||||||
GatherDataPointTypeMap map[int32]*GatherData // 采集物场景节点索引
|
GatherDataPointTypeMap map[int32]*GatherData // 采集物场景节点索引
|
||||||
@@ -60,6 +63,7 @@ func InitGameDataConfig() {
|
|||||||
startTime := time.Now().Unix()
|
startTime := time.Now().Unix()
|
||||||
CONF.loadAll()
|
CONF.loadAll()
|
||||||
endTime := time.Now().Unix()
|
endTime := time.Now().Unix()
|
||||||
|
runtime.GC()
|
||||||
logger.Info("load all game data config finish, cost: %v(s)", endTime-startTime)
|
logger.Info("load all game data config finish, cost: %v(s)", endTime-startTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +72,7 @@ func ReloadGameDataConfig() {
|
|||||||
startTime := time.Now().Unix()
|
startTime := time.Now().Unix()
|
||||||
CONF_RELOAD.loadAll()
|
CONF_RELOAD.loadAll()
|
||||||
endTime := time.Now().Unix()
|
endTime := time.Now().Unix()
|
||||||
|
runtime.GC()
|
||||||
logger.Info("reload all game data config finish, cost: %v(s)", endTime-startTime)
|
logger.Info("reload all game data config finish, cost: %v(s)", endTime-startTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
"github.com/jszwec/csvutil"
|
||||||
"github.com/mroth/weightedrand"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReliquaryAffixData 圣遗物追加属性配置表
|
// ReliquaryAffixData 圣遗物追加属性配置表
|
||||||
@@ -46,35 +45,6 @@ func GetReliquaryAffixDataByDepotIdAndPropId(appendPropDepotId int32, appendProp
|
|||||||
return value[appendPropId]
|
return value[appendPropId]
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetReliquaryAffixDataRandomByDepotId(appendPropDepotId int32, excludeTypeList ...uint32) *ReliquaryAffixData {
|
|
||||||
appendPropMap, exist := CONF.ReliquaryAffixDataMap[appendPropDepotId]
|
|
||||||
if !exist {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
choices := make([]weightedrand.Choice, 0, len(appendPropMap))
|
|
||||||
for _, data := range appendPropMap {
|
|
||||||
isBoth := false
|
|
||||||
// 排除列表中的属性类型是否相同
|
|
||||||
for _, propType := range excludeTypeList {
|
|
||||||
if propType == uint32(data.PropType) {
|
|
||||||
isBoth = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if isBoth {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
choices = append(choices, weightedrand.NewChoice(data, uint(data.RandomWeight)))
|
|
||||||
}
|
|
||||||
chooser, err := weightedrand.NewChooser(choices...)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("reliquary append random error: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
result := chooser.Pick()
|
|
||||||
return result.(*ReliquaryAffixData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetReliquaryAffixDataMap() map[int32]map[int32]*ReliquaryAffixData {
|
func GetReliquaryAffixDataMap() map[int32]map[int32]*ReliquaryAffixData {
|
||||||
return CONF.ReliquaryAffixDataMap
|
return CONF.ReliquaryAffixDataMap
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
"github.com/jszwec/csvutil"
|
||||||
"github.com/mroth/weightedrand"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReliquaryMainData 圣遗物主属性配置表
|
// ReliquaryMainData 圣遗物主属性配置表
|
||||||
@@ -46,24 +45,6 @@ func GetReliquaryMainDataByDepotIdAndPropId(mainPropDepotId int32, mainPropId in
|
|||||||
return value[mainPropId]
|
return value[mainPropId]
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetReliquaryMainDataRandomByDepotId(mainPropDepotId int32) *ReliquaryMainData {
|
|
||||||
mainPropMap, exist := CONF.ReliquaryMainDataMap[mainPropDepotId]
|
|
||||||
if !exist {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
choices := make([]weightedrand.Choice, 0, len(mainPropMap))
|
|
||||||
for _, data := range mainPropMap {
|
|
||||||
choices = append(choices, weightedrand.NewChoice(data, uint(data.RandomWeight)))
|
|
||||||
}
|
|
||||||
chooser, err := weightedrand.NewChooser(choices...)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("reliquary main random error: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
result := chooser.Pick()
|
|
||||||
return result.(*ReliquaryMainData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetReliquaryMainDataMap() map[int32]map[int32]*ReliquaryMainData {
|
func GetReliquaryMainDataMap() map[int32]map[int32]*ReliquaryMainData {
|
||||||
return CONF.ReliquaryMainDataMap
|
return CONF.ReliquaryMainDataMap
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ package gdconf
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
@@ -68,7 +70,53 @@ type Group struct {
|
|||||||
LuaState *lua.LState `json:"-"`
|
LuaState *lua.LState `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
LuaStateLruKeepNum = 1000
|
||||||
|
)
|
||||||
|
|
||||||
|
type LuaStateLru struct {
|
||||||
|
GroupId int32
|
||||||
|
AccessTime int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type LuaStateLruList []*LuaStateLru
|
||||||
|
|
||||||
|
func (l LuaStateLruList) Len() int {
|
||||||
|
return len(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LuaStateLruList) Less(i, j int) bool {
|
||||||
|
return l[i].AccessTime < l[j].AccessTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LuaStateLruList) Swap(i, j int) {
|
||||||
|
l[i], l[j] = l[j], l[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func LuaStateLruRemove() {
|
||||||
|
removeNum := len(CONF.LuaStateLruMap) - LuaStateLruKeepNum
|
||||||
|
if removeNum <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
luaStateLruList := make(LuaStateLruList, 0)
|
||||||
|
for _, luaStateLru := range CONF.LuaStateLruMap {
|
||||||
|
luaStateLruList = append(luaStateLruList, luaStateLru)
|
||||||
|
}
|
||||||
|
sort.Stable(luaStateLruList)
|
||||||
|
for i := 0; i < removeNum; i++ {
|
||||||
|
luaStateLru := luaStateLruList[i]
|
||||||
|
group := GetSceneGroup(luaStateLru.GroupId)
|
||||||
|
group.LuaState = nil
|
||||||
|
delete(CONF.LuaStateLruMap, luaStateLru.GroupId)
|
||||||
|
}
|
||||||
|
logger.Info("lua state lru remove finish, remove num: %v", removeNum)
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Group) GetLuaState() *lua.LState {
|
func (g *Group) GetLuaState() *lua.LState {
|
||||||
|
CONF.LuaStateLruMap[g.Id] = &LuaStateLru{
|
||||||
|
GroupId: g.Id,
|
||||||
|
AccessTime: time.Now().UnixMilli(),
|
||||||
|
}
|
||||||
if g.LuaState == nil {
|
if g.LuaState == nil {
|
||||||
g.LuaState = newLuaState(g.LuaStr)
|
g.LuaState = newLuaState(g.LuaStr)
|
||||||
scriptLib := g.LuaState.NewTable()
|
scriptLib := g.LuaState.NewTable()
|
||||||
@@ -207,6 +255,8 @@ func (g *GameDataConfig) loadGroup(group *Group, block *Block, sceneId int32, bl
|
|||||||
func (g *GameDataConfig) loadSceneLuaConfig() {
|
func (g *GameDataConfig) loadSceneLuaConfig() {
|
||||||
OBJECT_ID_COUNTER = 0
|
OBJECT_ID_COUNTER = 0
|
||||||
g.SceneLuaConfigMap = make(map[int32]*SceneLuaConfig)
|
g.SceneLuaConfigMap = make(map[int32]*SceneLuaConfig)
|
||||||
|
g.GroupMap = make(map[int32]*Group)
|
||||||
|
g.LuaStateLruMap = make(map[int32]*LuaStateLru)
|
||||||
sceneLuaPrefix := g.luaPrefix + "scene/"
|
sceneLuaPrefix := g.luaPrefix + "scene/"
|
||||||
for _, sceneData := range g.SceneDataMap {
|
for _, sceneData := range g.SceneDataMap {
|
||||||
sceneId := sceneData.SceneId
|
sceneId := sceneData.SceneId
|
||||||
@@ -279,6 +329,7 @@ func (g *GameDataConfig) loadSceneLuaConfig() {
|
|||||||
<-wc
|
<-wc
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
g.GroupMap[group.Id] = group
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
sceneLuaConfig.BlockMap[block.Id] = block
|
sceneLuaConfig.BlockMap[block.Id] = block
|
||||||
@@ -315,29 +366,10 @@ func GetSceneLuaConfigMap() map[int32]*SceneLuaConfig {
|
|||||||
return CONF.SceneLuaConfigMap
|
return CONF.SceneLuaConfigMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSceneBlockConfig(sceneId int32, blockId int32) ([]*Monster, []*Npc, []*Gadget, bool) {
|
func GetSceneGroup(groupId int32) *Group {
|
||||||
monsterList := make([]*Monster, 0)
|
groupConfig, exist := CONF.GroupMap[groupId]
|
||||||
npcList := make([]*Npc, 0)
|
|
||||||
gadgetList := make([]*Gadget, 0)
|
|
||||||
sceneConfig, exist := CONF.SceneLuaConfigMap[sceneId]
|
|
||||||
if !exist {
|
if !exist {
|
||||||
return nil, nil, nil, false
|
return nil
|
||||||
}
|
}
|
||||||
blockConfig, exist := sceneConfig.BlockMap[blockId]
|
return groupConfig
|
||||||
if !exist {
|
|
||||||
return nil, nil, nil, false
|
|
||||||
}
|
|
||||||
for _, groupConfig := range blockConfig.GroupMap {
|
|
||||||
for _, monsterConfig := range groupConfig.MonsterList {
|
|
||||||
monsterList = append(monsterList, monsterConfig)
|
|
||||||
}
|
|
||||||
for _, npcConfig := range groupConfig.NpcList {
|
|
||||||
npcList = append(npcList, npcConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, gadgetConfig := range groupConfig.GadgetList {
|
|
||||||
gadgetList = append(gadgetList, gadgetConfig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return monsterList, npcList, gadgetList, true
|
|
||||||
}
|
}
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -54,7 +54,6 @@ require github.com/pierrec/lz4/v4 v4.1.17
|
|||||||
require github.com/FlourishingWorld/dpdk-go v0.0.0-20230213165129-6c5bc55b1f63
|
require github.com/FlourishingWorld/dpdk-go v0.0.0-20230213165129-6c5bc55b1f63
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/mroth/weightedrand v1.0.0
|
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2
|
||||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -71,8 +71,6 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
|
|||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
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/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||||
github.com/mroth/weightedrand v1.0.0 h1:V8JeHChvl2MP1sAoXq4brElOcza+jxLkRuwvtQu8L3E=
|
|
||||||
github.com/mroth/weightedrand v1.0.0/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE=
|
|
||||||
github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI=
|
github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI=
|
||||||
github.com/nats-io/nats-server/v2 v2.9.7 h1:VBlfq7xvv/72v0mzGZ2rgsDzUoVyX2Xhssl9XpKDue0=
|
github.com/nats-io/nats-server/v2 v2.9.7 h1:VBlfq7xvv/72v0mzGZ2rgsDzUoVyX2Xhssl9XpKDue0=
|
||||||
github.com/nats-io/nats-server/v2 v2.9.7/go.mod h1:AB6hAnGZDlYfqb7CTAm66ZKMZy9DpfierY1/PbpvI2g=
|
github.com/nats-io/nats-server/v2 v2.9.7/go.mod h1:AB6hAnGZDlYfqb7CTAm66ZKMZy9DpfierY1/PbpvI2g=
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
package game
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
|
||||||
|
|
||||||
"gitlab.com/gomidi/midi/v2"
|
|
||||||
"gitlab.com/gomidi/midi/v2/smf"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
KeyOffset = -12 * 1 // 八度修正偏移
|
|
||||||
)
|
|
||||||
|
|
||||||
var AUDIO_CHAN chan uint32
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
AUDIO_CHAN = make(chan uint32, 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunPlayAudio() {
|
|
||||||
audio, err := smf.ReadFile("./in.mid")
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("read midi file error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tempoChangeList := audio.TempoChanges()
|
|
||||||
if len(tempoChangeList) != 1 {
|
|
||||||
logger.Error("midi file format not support")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tempoChange := tempoChangeList[0]
|
|
||||||
metricTicks := audio.TimeFormat.(smf.MetricTicks)
|
|
||||||
tickTime := ((60000000.0 / tempoChange.BPM) / float64(metricTicks.Resolution())) / 1000.0
|
|
||||||
for {
|
|
||||||
// 洗脑循环
|
|
||||||
logger.Debug("start play audio")
|
|
||||||
for _, track := range audio.Tracks {
|
|
||||||
// 全部轨道
|
|
||||||
totalTick := uint64(0)
|
|
||||||
for _, event := range track {
|
|
||||||
// 单个轨道
|
|
||||||
delay := uint32(float64(event.Delta) * tickTime)
|
|
||||||
// busyPollWaitMilliSecond(delay)
|
|
||||||
interruptWaitMilliSecond(delay)
|
|
||||||
totalTick += uint64(delay)
|
|
||||||
|
|
||||||
msg := event.Message
|
|
||||||
if msg.Type() != midi.NoteOnMsg {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
midiMsg := midi.Message(msg)
|
|
||||||
var channel, key, velocity uint8
|
|
||||||
midiMsg.GetNoteOn(&channel, &key, &velocity)
|
|
||||||
// TODO 测试一下客户端是否支持更宽的音域
|
|
||||||
// 60 -> 中央C C4
|
|
||||||
// if key < 36 || key > 71 {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
note := int32(key) + int32(KeyOffset)
|
|
||||||
if note < 21 || note > 108 {
|
|
||||||
// 非88键钢琴音域
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if velocity == 0 {
|
|
||||||
// 可能是NoteOffMsg
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
AUDIO_CHAN <- uint32(note)
|
|
||||||
// logger.Debug("send midi note: %v, delay: %v, totalTick: %v", note, delay, totalTick)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func interruptWaitMilliSecond(delay uint32) {
|
|
||||||
time.Sleep(time.Millisecond * time.Duration(delay))
|
|
||||||
}
|
|
||||||
|
|
||||||
func busyPollWaitMilliSecond(delay uint32) {
|
|
||||||
start := time.Now()
|
|
||||||
end := start.Add(time.Millisecond * time.Duration(delay))
|
|
||||||
for {
|
|
||||||
now := time.Now()
|
|
||||||
if now.After(end) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
@@ -15,8 +16,88 @@ import (
|
|||||||
"hk4e/protocol/proto"
|
"hk4e/protocol/proto"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"gitlab.com/gomidi/midi/v2"
|
||||||
|
"gitlab.com/gomidi/midi/v2/smf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
KeyOffset = -12 * 1 // 八度修正偏移
|
||||||
|
)
|
||||||
|
|
||||||
|
var AUDIO_CHAN chan uint32
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
AUDIO_CHAN = make(chan uint32, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PlayAudio() {
|
||||||
|
audio, err := smf.ReadFile("./audio.mid")
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("read midi file error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tempoChangeList := audio.TempoChanges()
|
||||||
|
if len(tempoChangeList) != 1 {
|
||||||
|
logger.Error("midi file format not support")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tempoChange := tempoChangeList[0]
|
||||||
|
metricTicks := audio.TimeFormat.(smf.MetricTicks)
|
||||||
|
tickTime := ((60000000.0 / tempoChange.BPM) / float64(metricTicks.Resolution())) / 1000.0
|
||||||
|
logger.Debug("start play audio")
|
||||||
|
for _, track := range audio.Tracks {
|
||||||
|
// 全部轨道
|
||||||
|
totalTick := uint64(0)
|
||||||
|
for _, event := range track {
|
||||||
|
// 单个轨道
|
||||||
|
delay := uint32(float64(event.Delta) * tickTime)
|
||||||
|
// busyPollWaitMilliSecond(delay)
|
||||||
|
interruptWaitMilliSecond(delay)
|
||||||
|
totalTick += uint64(delay)
|
||||||
|
|
||||||
|
msg := event.Message
|
||||||
|
if msg.Type() != midi.NoteOnMsg {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
midiMsg := midi.Message(msg)
|
||||||
|
var channel, key, velocity uint8
|
||||||
|
midiMsg.GetNoteOn(&channel, &key, &velocity)
|
||||||
|
// TODO 测试一下客户端是否支持更宽的音域
|
||||||
|
// 60 -> 中央C C4
|
||||||
|
// if key < 36 || key > 71 {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
note := int32(key) + int32(KeyOffset)
|
||||||
|
if note < 21 || note > 108 {
|
||||||
|
// 非88键钢琴音域
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if velocity == 0 {
|
||||||
|
// 可能是NoteOffMsg
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
AUDIO_CHAN <- uint32(note)
|
||||||
|
// logger.Debug("send midi note: %v, delay: %v, totalTick: %v", note, delay, totalTick)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func interruptWaitMilliSecond(delay uint32) {
|
||||||
|
time.Sleep(time.Millisecond * time.Duration(delay))
|
||||||
|
}
|
||||||
|
|
||||||
|
func busyPollWaitMilliSecond(delay uint32) {
|
||||||
|
start := time.Now()
|
||||||
|
end := start.Add(time.Millisecond * time.Duration(delay))
|
||||||
|
for {
|
||||||
|
now := time.Now()
|
||||||
|
if now.After(end) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SCREEN_WIDTH = 80
|
SCREEN_WIDTH = 80
|
||||||
SCREEN_HEIGHT = 80
|
SCREEN_HEIGHT = 80
|
||||||
@@ -159,9 +240,9 @@ func WriteJpgFile(fileName string, jpg image.Image) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadVideoPlayerFile() error {
|
func LoadFrameFile() error {
|
||||||
inImg := ReadJpgFile("./in.jpg")
|
frameImg := ReadJpgFile("./frame.jpg")
|
||||||
if inImg == nil {
|
if frameImg == nil {
|
||||||
return errors.New("file not exist")
|
return errors.New("file not exist")
|
||||||
}
|
}
|
||||||
FRAME = make([][]bool, SCREEN_WIDTH)
|
FRAME = make([][]bool, SCREEN_WIDTH)
|
||||||
@@ -176,20 +257,20 @@ func LoadVideoPlayerFile() error {
|
|||||||
grayImg := image.NewRGBA(image.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))
|
grayImg := image.NewRGBA(image.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))
|
||||||
for w := 0; w < SCREEN_WIDTH; w++ {
|
for w := 0; w < SCREEN_WIDTH; w++ {
|
||||||
for h := 0; h < SCREEN_HEIGHT; h++ {
|
for h := 0; h < SCREEN_HEIGHT; h++ {
|
||||||
pix := inImg.At(w, h)
|
pix := frameImg.At(w, h)
|
||||||
r, g, b, _ := pix.RGBA()
|
r, g, b, _ := pix.RGBA()
|
||||||
gray := float32(r>>8)*0.299 + float32(g>>8)*0.587 + float32(b>>8)*0.114
|
gray := float32(r>>8)*0.299 + float32(g>>8)*0.587 + float32(b>>8)*0.114
|
||||||
grayImg.SetRGBA(w, h, color.RGBA{R: uint8(gray), G: uint8(gray), B: uint8(gray), A: 255})
|
grayImg.SetRGBA(w, h, color.RGBA{R: uint8(gray), G: uint8(gray), B: uint8(gray), A: 255})
|
||||||
grayAvg += uint64(gray)
|
grayAvg += uint64(gray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WriteJpgFile("./gray.jpg", grayImg)
|
WriteJpgFile("./frame_gray.jpg", grayImg)
|
||||||
grayAvg /= SCREEN_WIDTH * SCREEN_HEIGHT
|
grayAvg /= SCREEN_WIDTH * SCREEN_HEIGHT
|
||||||
rgbImg := image.NewRGBA(image.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))
|
rgbImg := image.NewRGBA(image.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))
|
||||||
binImg := image.NewRGBA(image.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))
|
binImg := image.NewRGBA(image.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))
|
||||||
for w := 0; w < SCREEN_WIDTH; w++ {
|
for w := 0; w < SCREEN_WIDTH; w++ {
|
||||||
for h := 0; h < SCREEN_HEIGHT; h++ {
|
for h := 0; h < SCREEN_HEIGHT; h++ {
|
||||||
pix := inImg.At(w, h)
|
pix := frameImg.At(w, h)
|
||||||
r, g, b, _ := pix.RGBA()
|
r, g, b, _ := pix.RGBA()
|
||||||
gray := float32(r>>8)*0.299 + float32(g>>8)*0.587 + float32(b>>8)*0.114
|
gray := float32(r>>8)*0.299 + float32(g>>8)*0.587 + float32(b>>8)*0.114
|
||||||
c := ""
|
c := ""
|
||||||
@@ -211,15 +292,15 @@ func LoadVideoPlayerFile() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WriteJpgFile("./rgb.jpg", rgbImg)
|
WriteJpgFile("./frame_rgb.jpg", rgbImg)
|
||||||
WriteJpgFile("./bin.jpg", binImg)
|
WriteJpgFile("./frame_bin.jpg", binImg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var OBJECT_ID_COUNTER uint64 = math.MaxUint64
|
var OBJECT_ID_COUNTER uint64 = math.MaxUint64
|
||||||
|
|
||||||
func (g *GameManager) VideoPlayerUpdate(rgb bool) {
|
func UpdateFrame(rgb bool) {
|
||||||
err := LoadVideoPlayerFile()
|
err := LoadFrameFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -235,8 +316,8 @@ func (g *GameManager) VideoPlayerUpdate(rgb bool) {
|
|||||||
GAME_MANAGER.RemoveSceneEntityNotifyBroadcast(scene, proto.VisionType_VISION_REMOVE, SCREEN_ENTITY_ID_LIST)
|
GAME_MANAGER.RemoveSceneEntityNotifyBroadcast(scene, proto.VisionType_VISION_REMOVE, SCREEN_ENTITY_ID_LIST)
|
||||||
SCREEN_ENTITY_ID_LIST = make([]uint32, 0)
|
SCREEN_ENTITY_ID_LIST = make([]uint32, 0)
|
||||||
leftTopPos := &model.Vector{
|
leftTopPos := &model.Vector{
|
||||||
X: BASE_POS.X + float64(float64(SCREEN_WIDTH)*SCREEN_DPI/2),
|
X: BASE_POS.X + float64(SCREEN_WIDTH)*SCREEN_DPI/2,
|
||||||
Y: BASE_POS.Y + float64(float64(SCREEN_HEIGHT)*SCREEN_DPI),
|
Y: BASE_POS.Y + float64(SCREEN_HEIGHT)*SCREEN_DPI,
|
||||||
Z: BASE_POS.Z,
|
Z: BASE_POS.Z,
|
||||||
}
|
}
|
||||||
for w := 0; w < SCREEN_WIDTH; w++ {
|
for w := 0; w < SCREEN_WIDTH; w++ {
|
||||||
@@ -338,7 +338,7 @@ func (c *CommandManager) GiveCommand(cmd *CommandMessage) {
|
|||||||
|
|
||||||
// ReloadConfigCommand 帮助命令
|
// ReloadConfigCommand 帮助命令
|
||||||
func (c *CommandManager) ReloadConfigCommand(cmd *CommandMessage) {
|
func (c *CommandManager) ReloadConfigCommand(cmd *CommandMessage) {
|
||||||
LOCAL_EVENT_MANAGER.localEventChan <- &LocalEvent{
|
LOCAL_EVENT_MANAGER.GetLocalEventChan() <- &LocalEvent{
|
||||||
EventId: ReloadGameDataConfig,
|
EventId: ReloadGameDataConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package game
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hk4e/common/mq"
|
"hk4e/common/mq"
|
||||||
@@ -24,6 +25,10 @@ const (
|
|||||||
ReloadGameDataConfigFinish // 热更表完成
|
ReloadGameDataConfigFinish // 热更表完成
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserCopyGoroutineLimit = 4
|
||||||
|
)
|
||||||
|
|
||||||
type LocalEvent struct {
|
type LocalEvent struct {
|
||||||
EventId int
|
EventId int
|
||||||
Msg any
|
Msg any
|
||||||
@@ -62,9 +67,9 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
|
|||||||
case LoadLoginUserFromDbFinish:
|
case LoadLoginUserFromDbFinish:
|
||||||
playerLoginInfo := localEvent.Msg.(*PlayerLoginInfo)
|
playerLoginInfo := localEvent.Msg.(*PlayerLoginInfo)
|
||||||
if playerLoginInfo.Player != nil {
|
if playerLoginInfo.Player != nil {
|
||||||
USER_MANAGER.playerMap[playerLoginInfo.Player.PlayerID] = playerLoginInfo.Player
|
USER_MANAGER.AddUser(playerLoginInfo.Player)
|
||||||
}
|
}
|
||||||
GAME_MANAGER.OnLoginOk(playerLoginInfo.UserId, playerLoginInfo.Player, playerLoginInfo.ClientSeq, playerLoginInfo.GateAppId)
|
GAME_MANAGER.OnLoginOk(playerLoginInfo.UserId, playerLoginInfo.ClientSeq, playerLoginInfo.GateAppId, false, playerLoginInfo.Player)
|
||||||
case CheckUserExistOnRegFromDbFinish:
|
case CheckUserExistOnRegFromDbFinish:
|
||||||
playerRegInfo := localEvent.Msg.(*PlayerRegInfo)
|
playerRegInfo := localEvent.Msg.(*PlayerRegInfo)
|
||||||
GAME_MANAGER.OnRegOk(playerRegInfo.Exist, playerRegInfo.Req, playerRegInfo.UserId, playerRegInfo.ClientSeq, playerRegInfo.GateAppId)
|
GAME_MANAGER.OnRegOk(playerRegInfo.Exist, playerRegInfo.Req, playerRegInfo.UserId, playerRegInfo.ClientSeq, playerRegInfo.GateAppId)
|
||||||
@@ -73,7 +78,7 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
|
|||||||
case RunUserCopyAndSave:
|
case RunUserCopyAndSave:
|
||||||
startTime := time.Now().UnixNano()
|
startTime := time.Now().UnixNano()
|
||||||
playerList := make(PlayerLastSaveTimeSortList, 0)
|
playerList := make(PlayerLastSaveTimeSortList, 0)
|
||||||
for _, player := range USER_MANAGER.playerMap {
|
for _, player := range USER_MANAGER.GetAllOnlineUserList() {
|
||||||
if player.PlayerID < PlayerBaseUid {
|
if player.PlayerID < PlayerBaseUid {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -84,32 +89,65 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
|
|||||||
insertPlayerList := make([][]byte, 0)
|
insertPlayerList := make([][]byte, 0)
|
||||||
updatePlayerList := make([][]byte, 0)
|
updatePlayerList := make([][]byte, 0)
|
||||||
saveCount := 0
|
saveCount := 0
|
||||||
for _, player := range playerList {
|
times := len(playerList) / UserCopyGoroutineLimit
|
||||||
|
if times == 0 && len(playerList) > 0 {
|
||||||
|
times = 1
|
||||||
|
}
|
||||||
|
for index := 0; index < times; index++ {
|
||||||
totalCostTime := time.Now().UnixNano() - startTime
|
totalCostTime := time.Now().UnixNano() - startTime
|
||||||
if totalCostTime > time.Millisecond.Nanoseconds()*50 {
|
if totalCostTime > time.Millisecond.Nanoseconds()*10 {
|
||||||
// 总耗时超过50ms就中止本轮保存
|
// 总耗时超过10ms就中止本轮保存
|
||||||
logger.Debug("user copy loop overtime exit, total cost time: %v ns", totalCostTime)
|
logger.Info("user copy loop overtime exit, total cost time: %v ns", totalCostTime)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
playerData, err := msgpack.Marshal(player)
|
// 分批次并发序列化玩家数据
|
||||||
if err != nil {
|
oncePlayerListEndIndex := 0
|
||||||
logger.Error("marshal player data error: %v", err)
|
if index < times-1 {
|
||||||
continue
|
oncePlayerListEndIndex = (index + 1) * UserCopyGoroutineLimit
|
||||||
|
} else {
|
||||||
|
oncePlayerListEndIndex = len(playerList)
|
||||||
}
|
}
|
||||||
switch player.DbState {
|
oncePlayerList := playerList[index*UserCopyGoroutineLimit : oncePlayerListEndIndex]
|
||||||
case model.DbNone:
|
var playerDataMapLock sync.Mutex
|
||||||
break
|
playerDataMap := make(map[uint32][]byte)
|
||||||
case model.DbInsert:
|
var wg sync.WaitGroup
|
||||||
insertPlayerList = append(insertPlayerList, playerData)
|
for _, player := range oncePlayerList {
|
||||||
USER_MANAGER.playerMap[player.PlayerID].DbState = model.DbNormal
|
wg.Add(1)
|
||||||
player.LastSaveTime = uint32(time.Now().UnixMilli())
|
go func(player *model.Player) {
|
||||||
saveCount++
|
defer func() {
|
||||||
case model.DbDelete:
|
wg.Done()
|
||||||
delete(USER_MANAGER.playerMap, player.PlayerID)
|
}()
|
||||||
case model.DbNormal:
|
playerData, err := msgpack.Marshal(player)
|
||||||
updatePlayerList = append(updatePlayerList, playerData)
|
if err != nil {
|
||||||
player.LastSaveTime = uint32(time.Now().UnixMilli())
|
logger.Error("marshal player data error: %v", err)
|
||||||
saveCount++
|
return
|
||||||
|
}
|
||||||
|
playerDataMapLock.Lock()
|
||||||
|
playerDataMap[player.PlayerID] = playerData
|
||||||
|
playerDataMapLock.Unlock()
|
||||||
|
}(player)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
for _, player := range oncePlayerList {
|
||||||
|
playerData, exist := playerDataMap[player.PlayerID]
|
||||||
|
if !exist {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch player.DbState {
|
||||||
|
case model.DbNone:
|
||||||
|
break
|
||||||
|
case model.DbInsert:
|
||||||
|
insertPlayerList = append(insertPlayerList, playerData)
|
||||||
|
player.DbState = model.DbNormal
|
||||||
|
player.LastSaveTime = uint32(time.Now().UnixMilli())
|
||||||
|
saveCount++
|
||||||
|
case model.DbDelete:
|
||||||
|
USER_MANAGER.DeleteUser(player.PlayerID)
|
||||||
|
case model.DbNormal:
|
||||||
|
updatePlayerList = append(updatePlayerList, playerData)
|
||||||
|
player.LastSaveTime = uint32(time.Now().UnixMilli())
|
||||||
|
saveCount++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
saveUserData := &SaveUserData{
|
saveUserData := &SaveUserData{
|
||||||
@@ -120,10 +158,10 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
|
|||||||
if localEvent.EventId == ExitRunUserCopyAndSave {
|
if localEvent.EventId == ExitRunUserCopyAndSave {
|
||||||
saveUserData.exitSave = true
|
saveUserData.exitSave = true
|
||||||
}
|
}
|
||||||
USER_MANAGER.saveUserChan <- saveUserData
|
USER_MANAGER.GetSaveUserChan() <- saveUserData
|
||||||
endTime := time.Now().UnixNano()
|
endTime := time.Now().UnixNano()
|
||||||
costTime := endTime - startTime
|
costTime := endTime - startTime
|
||||||
logger.Debug("run save user copy cost time: %v ns, save user count: %v", costTime, saveCount)
|
logger.Info("run save user copy cost time: %v ns, save user count: %v", costTime, saveCount)
|
||||||
if localEvent.EventId == ExitRunUserCopyAndSave {
|
if localEvent.EventId == ExitRunUserCopyAndSave {
|
||||||
// 在此阻塞掉主协程 不再进行任何消息和任务的处理
|
// 在此阻塞掉主协程 不再进行任何消息和任务的处理
|
||||||
select {}
|
select {}
|
||||||
@@ -167,7 +205,10 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
|
|||||||
}()
|
}()
|
||||||
case ReloadGameDataConfigFinish:
|
case ReloadGameDataConfigFinish:
|
||||||
gdconf.ReplaceGameDataConfig()
|
gdconf.ReplaceGameDataConfig()
|
||||||
// TODO 参考更表一样改成异步加载
|
startTime := time.Now().UnixNano()
|
||||||
WORLD_MANAGER.LoadSceneBlockAoiMap()
|
WORLD_MANAGER.LoadSceneBlockAoiMap()
|
||||||
|
endTime := time.Now().UnixNano()
|
||||||
|
costTime := endTime - startTime
|
||||||
|
logger.Info("run [LoadSceneBlockAoiMap], cost time: %v ns", costTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,16 +36,16 @@ func (g *GameManager) SetPlayerBornDataReq(userId uint32, clientSeq uint32, gate
|
|||||||
func (g *GameManager) OnLogin(userId uint32, clientSeq uint32, gateAppId string, isReg bool, regPlayer *model.Player) {
|
func (g *GameManager) OnLogin(userId uint32, clientSeq uint32, gateAppId string, isReg bool, regPlayer *model.Player) {
|
||||||
logger.Info("user login, uid: %v", userId)
|
logger.Info("user login, uid: %v", userId)
|
||||||
if isReg {
|
if isReg {
|
||||||
g.OnLoginOk(userId, regPlayer, clientSeq, gateAppId)
|
g.OnLoginOk(userId, clientSeq, gateAppId, true, regPlayer)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
player, isRobot := USER_MANAGER.OnlineUser(userId, clientSeq, gateAppId)
|
player, isRobot := USER_MANAGER.OnlineUser(userId, clientSeq, gateAppId)
|
||||||
if isRobot {
|
if isRobot {
|
||||||
g.OnLoginOk(userId, player, clientSeq, gateAppId)
|
g.OnLoginOk(userId, clientSeq, gateAppId, false, player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq uint32, gateAppId string) {
|
func (g *GameManager) OnLoginOk(userId uint32, clientSeq uint32, gateAppId string, isReg bool, player *model.Player) {
|
||||||
if player == nil {
|
if player == nil {
|
||||||
g.SendMsgToGate(cmd.DoSetPlayerBornDataNotify, userId, clientSeq, gateAppId, new(proto.DoSetPlayerBornDataNotify))
|
g.SendMsgToGate(cmd.DoSetPlayerBornDataNotify, userId, clientSeq, gateAppId, new(proto.DoSetPlayerBornDataNotify))
|
||||||
return
|
return
|
||||||
@@ -67,6 +67,27 @@ func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq u
|
|||||||
dbItem := player.GetDbItem()
|
dbItem := player.GetDbItem()
|
||||||
dbItem.InitAllItem(player)
|
dbItem.InitAllItem(player)
|
||||||
|
|
||||||
|
if isReg {
|
||||||
|
// 添加选定的主角
|
||||||
|
dbAvatar.AddAvatar(player, dbAvatar.MainCharAvatarId)
|
||||||
|
// 添加主角初始武器
|
||||||
|
avatarDataConfig := gdconf.GetAvatarDataById(int32(dbAvatar.MainCharAvatarId))
|
||||||
|
if avatarDataConfig == nil {
|
||||||
|
logger.Error("get avatar data config is nil, avatarId: %v", dbAvatar.MainCharAvatarId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
weaponId := uint64(g.snowflake.GenId())
|
||||||
|
dbWeapon := player.GetDbWeapon()
|
||||||
|
dbWeapon.AddWeapon(player, uint32(avatarDataConfig.InitialWeapon), weaponId)
|
||||||
|
weapon := dbWeapon.WeaponMap[weaponId]
|
||||||
|
dbAvatar.WearWeapon(dbAvatar.MainCharAvatarId, weapon)
|
||||||
|
|
||||||
|
dbTeam := player.GetDbTeam()
|
||||||
|
dbTeam.GetActiveTeam().SetAvatarIdList([]uint32{dbAvatar.MainCharAvatarId})
|
||||||
|
|
||||||
|
g.AcceptQuest(player, false)
|
||||||
|
}
|
||||||
|
|
||||||
// 确保玩家位置安全
|
// 确保玩家位置安全
|
||||||
player.Pos.X = player.SafePos.X
|
player.Pos.X = player.SafePos.X
|
||||||
player.Pos.Y = player.SafePos.Y
|
player.Pos.Y = player.SafePos.Y
|
||||||
@@ -81,9 +102,6 @@ func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq u
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO DEBUG DEL
|
|
||||||
g.AcceptQuest(player, false)
|
|
||||||
|
|
||||||
g.LoginNotify(userId, player, clientSeq)
|
g.LoginNotify(userId, player, clientSeq)
|
||||||
|
|
||||||
MESSAGE_QUEUE.SendToAll(&mq.NetMsg{
|
MESSAGE_QUEUE.SendToAll(&mq.NetMsg{
|
||||||
@@ -129,11 +147,71 @@ func (g *GameManager) OnRegOk(exist bool, req *proto.SetPlayerBornDataReq, userI
|
|||||||
logger.Error("player is nil, uid: %v", userId)
|
logger.Error("player is nil, uid: %v", userId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
USER_MANAGER.ChangeUserDbState(player, model.DbInsert)
|
||||||
USER_MANAGER.AddUser(player)
|
USER_MANAGER.AddUser(player)
|
||||||
g.SendMsgToGate(cmd.SetPlayerBornDataRsp, userId, clientSeq, gateAppId, new(proto.SetPlayerBornDataRsp))
|
g.SendMsgToGate(cmd.SetPlayerBornDataRsp, userId, clientSeq, gateAppId, new(proto.SetPlayerBornDataRsp))
|
||||||
g.OnLogin(userId, clientSeq, gateAppId, true, player)
|
g.OnLogin(userId, clientSeq, gateAppId, true, 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.HeadImage = mainCharAvatarId
|
||||||
|
player.Birthday = []uint8{0, 0}
|
||||||
|
player.NameCard = 210001
|
||||||
|
player.NameCardList = make([]uint32, 0)
|
||||||
|
player.FriendList = make(map[uint32]bool)
|
||||||
|
player.FriendApplyList = make(map[uint32]bool)
|
||||||
|
player.PropertiesMap = make(map[uint16]uint32)
|
||||||
|
player.FlyCloakList = make([]uint32, 0)
|
||||||
|
player.CostumeList = make([]uint32, 0)
|
||||||
|
player.ChatMsgMap = make(map[uint32][]*model.ChatMsg)
|
||||||
|
|
||||||
|
player.SceneId = 3
|
||||||
|
|
||||||
|
player.NameCardList = append(player.NameCardList, 210001, 210042)
|
||||||
|
|
||||||
|
player.PropertiesMap[constant.PLAYER_PROP_PLAYER_LEVEL] = 1
|
||||||
|
player.PropertiesMap[constant.PLAYER_PROP_PLAYER_WORLD_LEVEL] = 0
|
||||||
|
player.PropertiesMap[constant.PLAYER_PROP_IS_SPRING_AUTO_USE] = 1
|
||||||
|
player.PropertiesMap[constant.PLAYER_PROP_SPRING_AUTO_USE_PERCENT] = 100
|
||||||
|
player.PropertiesMap[constant.PLAYER_PROP_IS_FLYABLE] = 1
|
||||||
|
player.PropertiesMap[constant.PLAYER_PROP_IS_TRANSFERABLE] = 1
|
||||||
|
player.PropertiesMap[constant.PLAYER_PROP_MAX_STAMINA] = 24000
|
||||||
|
player.PropertiesMap[constant.PLAYER_PROP_CUR_PERSIST_STAMINA] = 24000
|
||||||
|
player.PropertiesMap[constant.PLAYER_PROP_PLAYER_RESIN] = 160
|
||||||
|
player.PropertiesMap[constant.PLAYER_PROP_PLAYER_MP_SETTING_TYPE] = 2
|
||||||
|
player.PropertiesMap[constant.PLAYER_PROP_IS_MP_MODE_AVAILABLE] = 1
|
||||||
|
|
||||||
|
sceneLuaConfig := gdconf.GetSceneLuaConfigById(int32(player.SceneId))
|
||||||
|
if sceneLuaConfig == nil {
|
||||||
|
logger.Error("get scene lua config is nil, sceneId: %v", player.SceneId)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
player.SafePos = &model.Vector{
|
||||||
|
X: float64(sceneLuaConfig.SceneConfig.BornPos.X),
|
||||||
|
Y: float64(sceneLuaConfig.SceneConfig.BornPos.Y),
|
||||||
|
Z: float64(sceneLuaConfig.SceneConfig.BornPos.Z),
|
||||||
|
}
|
||||||
|
player.Pos = &model.Vector{
|
||||||
|
X: float64(sceneLuaConfig.SceneConfig.BornPos.X),
|
||||||
|
Y: float64(sceneLuaConfig.SceneConfig.BornPos.Y),
|
||||||
|
Z: float64(sceneLuaConfig.SceneConfig.BornPos.Z),
|
||||||
|
}
|
||||||
|
player.Rot = &model.Vector{
|
||||||
|
X: float64(sceneLuaConfig.SceneConfig.BornRot.X),
|
||||||
|
Y: float64(sceneLuaConfig.SceneConfig.BornRot.Y),
|
||||||
|
Z: float64(sceneLuaConfig.SceneConfig.BornRot.Z),
|
||||||
|
}
|
||||||
|
|
||||||
|
dbAvatar := player.GetDbAvatar()
|
||||||
|
dbAvatar.MainCharAvatarId = mainCharAvatarId
|
||||||
|
|
||||||
|
return player
|
||||||
|
}
|
||||||
|
|
||||||
func (g *GameManager) OnUserOffline(userId uint32, changeGsInfo *ChangeGsInfo) {
|
func (g *GameManager) OnUserOffline(userId uint32, changeGsInfo *ChangeGsInfo) {
|
||||||
logger.Info("user offline, uid: %v", userId)
|
logger.Info("user offline, uid: %v", userId)
|
||||||
player := USER_MANAGER.GetOnlineUser(userId)
|
player := USER_MANAGER.GetOnlineUser(userId)
|
||||||
@@ -164,9 +242,9 @@ func (g *GameManager) LoginNotify(userId uint32, player *model.Player, clientSeq
|
|||||||
playerLoginRsp := &proto.PlayerLoginRsp{
|
playerLoginRsp := &proto.PlayerLoginRsp{
|
||||||
IsUseAbilityHash: true,
|
IsUseAbilityHash: true,
|
||||||
AbilityHashCode: 0,
|
AbilityHashCode: 0,
|
||||||
GameBiz: "hk4e_cn",
|
GameBiz: "hk4e_global",
|
||||||
IsScOpen: false,
|
IsScOpen: false,
|
||||||
RegisterCps: "taptap",
|
RegisterCps: "mihoyo",
|
||||||
CountryCode: "CN",
|
CountryCode: "CN",
|
||||||
Birthday: "2000-01-01",
|
Birthday: "2000-01-01",
|
||||||
TotalTickTime: 0.0,
|
TotalTickTime: 0.0,
|
||||||
@@ -345,69 +423,3 @@ func (g *GameManager) PacketOpenStateUpdateNotify() *proto.OpenStateUpdateNotify
|
|||||||
}
|
}
|
||||||
return openStateUpdateNotify
|
return openStateUpdateNotify
|
||||||
}
|
}
|
||||||
|
|
||||||
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.HeadImage = mainCharAvatarId
|
|
||||||
player.Birthday = []uint8{0, 0}
|
|
||||||
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.SceneId = 3
|
|
||||||
|
|
||||||
player.PropertiesMap = make(map[uint16]uint32)
|
|
||||||
player.PropertiesMap[constant.PLAYER_PROP_PLAYER_LEVEL] = 1
|
|
||||||
player.PropertiesMap[constant.PLAYER_PROP_PLAYER_WORLD_LEVEL] = 0
|
|
||||||
player.PropertiesMap[constant.PLAYER_PROP_IS_SPRING_AUTO_USE] = 1
|
|
||||||
player.PropertiesMap[constant.PLAYER_PROP_SPRING_AUTO_USE_PERCENT] = 100
|
|
||||||
player.PropertiesMap[constant.PLAYER_PROP_IS_FLYABLE] = 1
|
|
||||||
player.PropertiesMap[constant.PLAYER_PROP_IS_TRANSFERABLE] = 1
|
|
||||||
player.PropertiesMap[constant.PLAYER_PROP_MAX_STAMINA] = 24000
|
|
||||||
player.PropertiesMap[constant.PLAYER_PROP_CUR_PERSIST_STAMINA] = 24000
|
|
||||||
player.PropertiesMap[constant.PLAYER_PROP_PLAYER_RESIN] = 160
|
|
||||||
player.PropertiesMap[constant.PLAYER_PROP_PLAYER_MP_SETTING_TYPE] = 2
|
|
||||||
player.PropertiesMap[constant.PLAYER_PROP_IS_MP_MODE_AVAILABLE] = 1
|
|
||||||
|
|
||||||
player.FlyCloakList = make([]uint32, 0)
|
|
||||||
player.CostumeList = make([]uint32, 0)
|
|
||||||
|
|
||||||
player.SafePos = &model.Vector{X: 2747, Y: 194, Z: -1719}
|
|
||||||
player.Pos = &model.Vector{X: 2747, Y: 194, Z: -1719}
|
|
||||||
player.Rot = &model.Vector{X: 0, Y: 307, Z: 0}
|
|
||||||
|
|
||||||
dbAvatar := player.GetDbAvatar()
|
|
||||||
dbAvatar.MainCharAvatarId = mainCharAvatarId
|
|
||||||
|
|
||||||
player.GameObjectGuidMap = make(map[uint64]model.GameObject)
|
|
||||||
player.GCGInfo = model.NewGCGInfo()
|
|
||||||
|
|
||||||
// 添加选定的主角
|
|
||||||
dbAvatar.AddAvatar(player, mainCharAvatarId)
|
|
||||||
// 添加主角初始武器
|
|
||||||
avatarDataConfig := gdconf.GetAvatarDataById(int32(mainCharAvatarId))
|
|
||||||
if avatarDataConfig == nil {
|
|
||||||
logger.Error("config is nil, mainCharAvatarId: %v", mainCharAvatarId)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
weaponId := uint64(g.snowflake.GenId())
|
|
||||||
dbWeapon := player.GetDbWeapon()
|
|
||||||
dbWeapon.AddWeapon(player, uint32(avatarDataConfig.InitialWeapon), weaponId)
|
|
||||||
weapon := dbWeapon.WeaponMap[weaponId]
|
|
||||||
dbAvatar.WearWeapon(mainCharAvatarId, weapon)
|
|
||||||
|
|
||||||
dbTeam := player.GetDbTeam()
|
|
||||||
dbTeam.GetActiveTeam().SetAvatarIdList([]uint32{mainCharAvatarId})
|
|
||||||
|
|
||||||
player.ChatMsgMap = make(map[uint32][]*model.ChatMsg)
|
|
||||||
|
|
||||||
g.AcceptQuest(player, false)
|
|
||||||
|
|
||||||
return player
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"hk4e/gdconf"
|
"hk4e/gdconf"
|
||||||
"hk4e/gs/model"
|
"hk4e/gs/model"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
"hk4e/pkg/random"
|
||||||
"hk4e/protocol/cmd"
|
"hk4e/protocol/cmd"
|
||||||
"hk4e/protocol/proto"
|
"hk4e/protocol/proto"
|
||||||
)
|
)
|
||||||
@@ -20,6 +21,29 @@ func (g *GameManager) GetAllReliquaryDataConfig() map[int32]*gdconf.ItemData {
|
|||||||
return allReliquaryDataConfig
|
return allReliquaryDataConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *GameManager) GetReliquaryMainDataRandomByDepotId(mainPropDepotId int32) *gdconf.ReliquaryMainData {
|
||||||
|
mainPropMap, exist := gdconf.GetReliquaryMainDataMap()[mainPropDepotId]
|
||||||
|
if !exist {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
weightAll := int32(0)
|
||||||
|
mainPropList := make([]*gdconf.ReliquaryMainData, 0)
|
||||||
|
for _, data := range mainPropMap {
|
||||||
|
weightAll += data.RandomWeight
|
||||||
|
mainPropList = append(mainPropList, data)
|
||||||
|
}
|
||||||
|
randNum := random.GetRandomInt32(0, weightAll-1)
|
||||||
|
sumWeight := int32(0)
|
||||||
|
// 轮盘选择法
|
||||||
|
for _, data := range mainPropList {
|
||||||
|
sumWeight += data.RandomWeight
|
||||||
|
if sumWeight > randNum {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (g *GameManager) AddUserReliquary(userId uint32, itemId uint32) uint64 {
|
func (g *GameManager) AddUserReliquary(userId uint32, itemId uint32) uint64 {
|
||||||
player := USER_MANAGER.GetOnlineUser(userId)
|
player := USER_MANAGER.GetOnlineUser(userId)
|
||||||
if player == nil {
|
if player == nil {
|
||||||
@@ -31,7 +55,7 @@ func (g *GameManager) AddUserReliquary(userId uint32, itemId uint32) uint64 {
|
|||||||
logger.Error("reliquary config error, itemId: %v", itemId)
|
logger.Error("reliquary config error, itemId: %v", itemId)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
reliquaryMainConfig := gdconf.GetReliquaryMainDataRandomByDepotId(reliquaryConfig.MainPropDepotId)
|
reliquaryMainConfig := g.GetReliquaryMainDataRandomByDepotId(reliquaryConfig.MainPropDepotId)
|
||||||
if reliquaryMainConfig == nil {
|
if reliquaryMainConfig == nil {
|
||||||
logger.Error("reliquary main config error, mainPropDepotId: %v", reliquaryConfig.MainPropDepotId)
|
logger.Error("reliquary main config error, mainPropDepotId: %v", reliquaryConfig.MainPropDepotId)
|
||||||
return 0
|
return 0
|
||||||
@@ -53,6 +77,40 @@ func (g *GameManager) AddUserReliquary(userId uint32, itemId uint32) uint64 {
|
|||||||
return reliquaryId
|
return reliquaryId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *GameManager) GetReliquaryAffixDataRandomByDepotId(appendPropDepotId int32, excludeTypeList ...uint32) *gdconf.ReliquaryAffixData {
|
||||||
|
appendPropMap, exist := gdconf.GetReliquaryAffixDataMap()[appendPropDepotId]
|
||||||
|
if !exist {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
weightAll := int32(0)
|
||||||
|
appendPropList := make([]*gdconf.ReliquaryAffixData, 0)
|
||||||
|
for _, data := range appendPropMap {
|
||||||
|
isBoth := false
|
||||||
|
// 排除列表中的属性类型是否相同
|
||||||
|
for _, propType := range excludeTypeList {
|
||||||
|
if propType == uint32(data.PropType) {
|
||||||
|
isBoth = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isBoth {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
weightAll += data.RandomWeight
|
||||||
|
appendPropList = append(appendPropList, data)
|
||||||
|
}
|
||||||
|
randNum := random.GetRandomInt32(0, weightAll-1)
|
||||||
|
sumWeight := int32(0)
|
||||||
|
// 轮盘选择法
|
||||||
|
for _, data := range appendPropList {
|
||||||
|
sumWeight += data.RandomWeight
|
||||||
|
if sumWeight > randNum {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AppendReliquaryProp 圣遗物追加属性
|
// AppendReliquaryProp 圣遗物追加属性
|
||||||
func (g *GameManager) AppendReliquaryProp(reliquary *model.Reliquary, count int32) {
|
func (g *GameManager) AppendReliquaryProp(reliquary *model.Reliquary, count int32) {
|
||||||
// 获取圣遗物配置表
|
// 获取圣遗物配置表
|
||||||
@@ -83,7 +141,7 @@ func (g *GameManager) AppendReliquaryProp(reliquary *model.Reliquary, count int3
|
|||||||
excludeTypeList = append(excludeTypeList, uint32(targetAffixConfig.PropType))
|
excludeTypeList = append(excludeTypeList, uint32(targetAffixConfig.PropType))
|
||||||
}
|
}
|
||||||
// 将要添加的属性
|
// 将要添加的属性
|
||||||
appendAffixConfig := gdconf.GetReliquaryAffixDataRandomByDepotId(reliquaryConfig.AppendPropDepotId, excludeTypeList...)
|
appendAffixConfig := g.GetReliquaryAffixDataRandomByDepotId(reliquaryConfig.AppendPropDepotId, excludeTypeList...)
|
||||||
if appendAffixConfig == nil {
|
if appendAffixConfig == nil {
|
||||||
logger.Error("append affix config error, appendPropDepotId: %v", reliquaryConfig.AppendPropDepotId)
|
logger.Error("append affix config error, appendPropDepotId: %v", reliquaryConfig.AppendPropDepotId)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hk4e/common/constant"
|
"hk4e/common/constant"
|
||||||
|
"hk4e/gdconf"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
"hk4e/pkg/random"
|
"hk4e/pkg/random"
|
||||||
"hk4e/protocol/cmd"
|
"hk4e/protocol/cmd"
|
||||||
@@ -186,6 +187,7 @@ func (t *TickManager) onTickHour(now int64) {
|
|||||||
|
|
||||||
func (t *TickManager) onTickMinute(now int64) {
|
func (t *TickManager) onTickMinute(now int64) {
|
||||||
// GAME_MANAGER.ServerAnnounceNotify(100, "test123")
|
// GAME_MANAGER.ServerAnnounceNotify(100, "test123")
|
||||||
|
gdconf.LuaStateLruRemove()
|
||||||
for _, world := range WORLD_MANAGER.GetAllWorld() {
|
for _, world := range WORLD_MANAGER.GetAllWorld() {
|
||||||
for _, player := range world.GetAllPlayer() {
|
for _, player := range world.GetAllPlayer() {
|
||||||
// 随机物品
|
// 随机物品
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ func (u *UserManager) CheckUserExistOnReg(userId uint32, req *proto.SetPlayerBor
|
|||||||
if player != nil {
|
if player != nil {
|
||||||
exist = true
|
exist = true
|
||||||
}
|
}
|
||||||
LOCAL_EVENT_MANAGER.localEventChan <- &LocalEvent{
|
LOCAL_EVENT_MANAGER.GetLocalEventChan() <- &LocalEvent{
|
||||||
EventId: CheckUserExistOnRegFromDbFinish,
|
EventId: CheckUserExistOnRegFromDbFinish,
|
||||||
Msg: &PlayerRegInfo{
|
Msg: &PlayerRegInfo{
|
||||||
Exist: exist,
|
Exist: exist,
|
||||||
@@ -113,7 +113,6 @@ func (u *UserManager) AddUser(player *model.Player) {
|
|||||||
if player == nil {
|
if player == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u.ChangeUserDbState(player, model.DbInsert)
|
|
||||||
u.playerMap[player.PlayerID] = player
|
u.playerMap[player.PlayerID] = player
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,15 +138,25 @@ func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32, gateAppId stri
|
|||||||
u.DeleteUser(userId)
|
u.DeleteUser(userId)
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
|
// 加离线玩家数据分布式锁
|
||||||
|
ok := u.dao.DistLockSync(userId)
|
||||||
|
if !ok {
|
||||||
|
logger.Error("lock redis offline player data error, uid: %v", userId)
|
||||||
|
return
|
||||||
|
}
|
||||||
player := u.LoadUserFromDbSync(userId)
|
player := u.LoadUserFromDbSync(userId)
|
||||||
if player != nil {
|
if player != nil {
|
||||||
u.SaveUserToRedisSync(player)
|
u.SaveUserToRedisSync(player)
|
||||||
|
}
|
||||||
|
// 解离线玩家数据分布式锁
|
||||||
|
u.dao.DistUnlock(player.PlayerID)
|
||||||
|
if player != nil {
|
||||||
u.ChangeUserDbState(player, model.DbNormal)
|
u.ChangeUserDbState(player, model.DbNormal)
|
||||||
player.ChatMsgMap = u.LoadUserChatMsgFromDbSync(userId)
|
player.ChatMsgMap = u.LoadUserChatMsgFromDbSync(userId)
|
||||||
} else {
|
} else {
|
||||||
logger.Error("can not find user from db, uid: %v", userId)
|
logger.Error("can not find user from db, uid: %v", userId)
|
||||||
}
|
}
|
||||||
LOCAL_EVENT_MANAGER.localEventChan <- &LocalEvent{
|
LOCAL_EVENT_MANAGER.GetLocalEventChan() <- &LocalEvent{
|
||||||
EventId: LoadLoginUserFromDbFinish,
|
EventId: LoadLoginUserFromDbFinish,
|
||||||
Msg: &PlayerLoginInfo{
|
Msg: &PlayerLoginInfo{
|
||||||
UserId: userId,
|
UserId: userId,
|
||||||
@@ -195,7 +204,7 @@ func (u *UserManager) OfflineUser(player *model.Player, changeGsInfo *ChangeGsIn
|
|||||||
playerCopy.DbState = player.DbState
|
playerCopy.DbState = player.DbState
|
||||||
u.SaveUserToDbSync(playerCopy)
|
u.SaveUserToDbSync(playerCopy)
|
||||||
u.SaveUserToRedisSync(playerCopy)
|
u.SaveUserToRedisSync(playerCopy)
|
||||||
LOCAL_EVENT_MANAGER.localEventChan <- &LocalEvent{
|
LOCAL_EVENT_MANAGER.GetLocalEventChan() <- &LocalEvent{
|
||||||
EventId: UserOfflineSaveToDbFinish,
|
EventId: UserOfflineSaveToDbFinish,
|
||||||
Msg: &PlayerOfflineInfo{
|
Msg: &PlayerOfflineInfo{
|
||||||
Player: player,
|
Player: player,
|
||||||
@@ -322,7 +331,7 @@ func (u *UserManager) LoadGlobalPlayer(userId uint32) (player *model.Player, onl
|
|||||||
// 正常情况速度较快可以同步阻塞调用
|
// 正常情况速度较快可以同步阻塞调用
|
||||||
func (u *UserManager) LoadTempOfflineUser(userId uint32, lock bool) *model.Player {
|
func (u *UserManager) LoadTempOfflineUser(userId uint32, lock bool) *model.Player {
|
||||||
player := u.GetOnlineUser(userId)
|
player := u.GetOnlineUser(userId)
|
||||||
if player != nil && player.Online {
|
if player != nil {
|
||||||
logger.Error("not allow get a online player as offline player, uid: %v", userId)
|
logger.Error("not allow get a online player as offline player, uid: %v", userId)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -343,7 +352,11 @@ func (u *UserManager) LoadTempOfflineUser(userId uint32, lock bool) *model.Playe
|
|||||||
logger.Error("try to load a not exist uid, uid: %v", userId)
|
logger.Error("try to load a not exist uid, uid: %v", userId)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
startTime := time.Now().UnixNano()
|
||||||
player = u.LoadUserFromDbSync(userId)
|
player = u.LoadUserFromDbSync(userId)
|
||||||
|
endTime := time.Now().UnixNano()
|
||||||
|
costTime := endTime - startTime
|
||||||
|
logger.Info("try to load player from db sync in game main loop, cost time: %v ns", costTime)
|
||||||
if player == nil {
|
if player == nil {
|
||||||
// 玩家根本就不存在
|
// 玩家根本就不存在
|
||||||
logger.Error("try to load a not exist player from db, uid: %v", userId)
|
logger.Error("try to load a not exist player from db, uid: %v", userId)
|
||||||
@@ -361,15 +374,19 @@ func (u *UserManager) LoadTempOfflineUser(userId uint32, lock bool) *model.Playe
|
|||||||
func (u *UserManager) SaveTempOfflineUser(player *model.Player) {
|
func (u *UserManager) SaveTempOfflineUser(player *model.Player) {
|
||||||
// 主协程同步写入redis
|
// 主协程同步写入redis
|
||||||
u.SaveUserToRedisSync(player)
|
u.SaveUserToRedisSync(player)
|
||||||
// 解离线玩家数据分布式锁
|
|
||||||
u.dao.DistUnlock(player.PlayerID)
|
|
||||||
// 另一个协程异步的写回db
|
// 另一个协程异步的写回db
|
||||||
playerData, err := msgpack.Marshal(player)
|
playerData, err := msgpack.Marshal(player)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("marshal player data error: %v", err)
|
logger.Error("marshal player data error: %v", err)
|
||||||
|
// 解离线玩家数据分布式锁
|
||||||
|
u.dao.DistUnlock(player.PlayerID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
// 解离线玩家数据分布式锁
|
||||||
|
u.dao.DistUnlock(player.PlayerID)
|
||||||
|
}()
|
||||||
playerCopy := new(model.Player)
|
playerCopy := new(model.Player)
|
||||||
err := msgpack.Unmarshal(playerData, playerCopy)
|
err := msgpack.Unmarshal(playerData, playerCopy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -383,6 +400,10 @@ func (u *UserManager) SaveTempOfflineUser(player *model.Player) {
|
|||||||
|
|
||||||
// db和redis相关操作
|
// db和redis相关操作
|
||||||
|
|
||||||
|
func (u *UserManager) GetSaveUserChan() chan *SaveUserData {
|
||||||
|
return u.saveUserChan
|
||||||
|
}
|
||||||
|
|
||||||
type SaveUserData struct {
|
type SaveUserData struct {
|
||||||
insertPlayerList [][]byte
|
insertPlayerList [][]byte
|
||||||
updatePlayerList [][]byte
|
updatePlayerList [][]byte
|
||||||
@@ -395,7 +416,7 @@ func (u *UserManager) saveUserHandle() {
|
|||||||
for {
|
for {
|
||||||
<-ticker.C
|
<-ticker.C
|
||||||
// 保存玩家数据
|
// 保存玩家数据
|
||||||
LOCAL_EVENT_MANAGER.localEventChan <- &LocalEvent{
|
LOCAL_EVENT_MANAGER.GetLocalEventChan() <- &LocalEvent{
|
||||||
EventId: RunUserCopyAndSave,
|
EventId: RunUserCopyAndSave,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,6 @@ func (w *WorldManager) GetAiWorld() *World {
|
|||||||
func (w *WorldManager) InitAiWorld(owner *model.Player) {
|
func (w *WorldManager) InitAiWorld(owner *model.Player) {
|
||||||
w.aiWorld = w.GetWorldByID(owner.WorldId)
|
w.aiWorld = w.GetWorldByID(owner.WorldId)
|
||||||
w.aiWorld.ChangeToMultiplayer()
|
w.aiWorld.ChangeToMultiplayer()
|
||||||
go RunPlayAudio()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorldManager) IsAiWorld(world *World) bool {
|
func (w *WorldManager) IsAiWorld(world *World) bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user