From 806780b5b33e85618c353fcd86bd7320f3935798 Mon Sep 17 00:00:00 2001 From: hahwu <31872165+hahwu@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:51:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9E=B6=E6=9E=84=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/game/mod/playroom/playroom.go | 41 ++++---- src/server/game/player_data.go | 6 +- src/server/game/player_mod.go | 119 ++++++++++++++++------- src/server/game/unit_test.go | 2 - src/server/game_util/randUtil.go | 8 +- src/server/game_util/sliceUtil.go | 40 ++++++-- 6 files changed, 145 insertions(+), 71 deletions(-) diff --git a/src/server/game/mod/playroom/playroom.go b/src/server/game/mod/playroom/playroom.go index 624d1ddb..eb33e946 100644 --- a/src/server/game/mod/playroom/playroom.go +++ b/src/server/game/mod/playroom/playroom.go @@ -161,70 +161,71 @@ type Info struct { } func (p *PlayroomMod) InitData() { + InitCollect := playroomCfg.GetInitDecorate() + if p.Collect == nil { - p.Collect = make(map[int]int) + p.Collect = make(map[int]int, 16) } if p.Dress == nil { - p.Dress = make(map[int][]int) + p.Dress = make(map[int][]int, 8) } if p.DressSet == nil { - p.DressSet = make(map[int]int) + p.DressSet = make(map[int]int, 8) } if p.GameInfo == nil { - p.GameInfo = make(map[int]interface{}) + p.GameInfo = make(map[int]interface{}, 8) } if p.NewCollect == nil { - p.NewCollect = make(map[int]*CollectInfo) + p.NewCollect = make(map[int]*CollectInfo, len(InitCollect)) } - InitCollect := playroomCfg.GetInitDecorate() + if len(p.NewCollect) == 0 { + now := GoUtil.Now() for _, v := range InitCollect { p.NewCollect[v] = &CollectInfo{ Id: v, - AddTime: GoUtil.Now(), + AddTime: now, EndTime: 0, Num: 1, } } } if len(p.Collect) > 0 { + now := GoUtil.Now() for k, v := range p.Collect { p.NewCollect[k] = &CollectInfo{ Id: k, - AddTime: GoUtil.Now(), + AddTime: now, EndTime: 0, Num: v, } } - p.Collect = make(map[int]int) - } - for _, v := range InitCollect { - p.Collect[v] = 1 + p.Collect = nil } if p.Room == nil { - p.Room = make(map[int]int) + p.Room = make(map[int]int, 8) p.JackpotNum = playroomCfg.GetJackpotNum() } if p.Visitor == nil { - p.Visitor = make(map[int]*Info) + p.Visitor = make(map[int]*Info, 16) } if p.MoodInfo == nil { - p.MoodInfo = make(map[int]*Mood) + p.MoodInfo = make(map[int]*Mood, 4) } if p.Physiology == nil { - p.Physiology = make(map[int]*Physiology) + p.Physiology = make(map[int]*Physiology, 4) } if p.Reward == nil { - p.Reward = make([]*item.Item, 0) + p.Reward = make([]*item.Item, 0, 8) } if p.HasVisit == nil { - p.HasVisit = make(map[int]int64) + p.HasVisit = make(map[int]int64, 16) } if p.GameReward == nil { - p.GameReward = make(map[int]*item.Item) + p.GameReward = make(map[int]*item.Item, 4) } if p.LoseItem == nil { - p.LoseItem = make([]*item.Item, 0) + p.LoseItem = make([]*item.Item, 0, 8) } if p.Flip == nil { p.Flip = make(map[int]int) diff --git a/src/server/game/player_data.go b/src/server/game/player_data.go index 1fe85f8c..f6414c60 100644 --- a/src/server/game/player_data.go +++ b/src/server/game/player_data.go @@ -207,9 +207,9 @@ func (p *Player) InitPlayer(UserName string) error { p.lock.Lock() defer p.lock.Unlock() p.msgChan = make(chan *MsgMod.Msg, 100) - p.Msg = make([]PlayerMsg, 0) - p.args = make(map[string]interface{}) - p.timerList = make(map[string]*timer.Timer) + p.Msg = make([]PlayerMsg, 0, 16) // 添加容量提示 + p.args = make(map[string]interface{}, 8) // 添加容量提示 + p.timerList = make(map[string]*timer.Timer, 8) // 添加容量提示 p.MDispatr = timer.NewDispatcher(100) p.stopSignal = make(chan bool) Base := &PlayerBaseData{p: p} diff --git a/src/server/game/player_mod.go b/src/server/game/player_mod.go index 5f0330eb..9b0a3e4c 100644 --- a/src/server/game/player_mod.go +++ b/src/server/game/player_mod.go @@ -45,13 +45,64 @@ import ( "time" ) -// buffer 对象池,复用 bytes.Buffer 减少内存分配 -var bufferPool = sync.Pool{ +// encoderPair 封装 encoder 和 buffer +type encoderPair struct { + encoder *gob.Encoder + buffer *bytes.Buffer +} + +// decoderPair 封装 decoder 和 reader +type decoderPair struct { + decoder *gob.Decoder + reader *bytes.Reader +} + +// gob 编码器对象池,复用 Encoder 减少反射开销 +var gobEncoderPool = sync.Pool{ New: func() interface{} { - return bytes.NewBuffer(make([]byte, 0, 128*1024)) + buf := bytes.NewBuffer(make([]byte, 0, 128*1024)) + return &encoderPair{ + encoder: gob.NewEncoder(buf), + buffer: buf, + } }, } +// gob 解码器对象池,复用 Decoder 减少反射开销 +var gobDecoderPool = sync.Pool{ + New: func() interface{} { + reader := bytes.NewReader(nil) + return &decoderPair{ + decoder: gob.NewDecoder(reader), + reader: reader, + } + }, +} + +// getEncoder 从对象池获取 encoder +func getEncoder() *encoderPair { + pair := gobEncoderPool.Get().(*encoderPair) + pair.buffer.Reset() + return pair +} + +// putEncoder 归还 encoder 到对象池 +func putEncoder(pair *encoderPair) { + gobEncoderPool.Put(pair) +} + +// getDecoder 从对象池获取 decoder +func getDecoder(data []byte) *decoderPair { + pair := gobDecoderPool.Get().(*decoderPair) + pair.reader.Reset(data) + return pair +} + +// putDecoder 归还 decoder 到对象池 +func putDecoder(pair *decoderPair) { + gobDecoderPool.Put(pair) +} + type PlayerData struct { Name string IsHaveDataDb bool @@ -158,11 +209,13 @@ func (p *PlayerModData) Reconnect(b bool) []byte { func (p *PlayerModData) InitMod(player *Player) (bool, error) { playerModList := PlayerModList{} if len(p.Data.ModData) > 0 { - buf := bytes.NewBuffer(p.Data.ModData) - decoder := gob.NewDecoder(buf) - err := decoder.Decode(&playerModList) + // 从对象池获取 decoder + pair := getDecoder(p.Data.ModData) + defer putDecoder(pair) + + err := pair.decoder.Decode(&playerModList) if err != nil { - log.Debug("playmod get data failed, err:%v\n", err) + log.Debug("playmod get data failed, err:%v, uid=%d", err, player.M_DwUin) return false, fmt.Errorf("playmod get data failed, err:%v", err) } } @@ -241,64 +294,64 @@ func (p *PlayerMod) IsBlackList() bool { func (p *PlayerMod) ClearData(player *Player) { ChessMod := p.getChessMod() if len(ChessMod.ChessMap) > 0 && len(ChessMod.ChessList) != len(ChessMod.ChessMap) { - log.Debug("uid: %d, SaveData, chess error ", player.M_DwUin) + log.Debug("uid: %d, SaveData, chess error", player.M_DwUin) return } if p.is_update && !p.IsBlackList() { - //序列化模块 - buf := bufferPool.Get().(*bytes.Buffer) - buf.Reset() // 清空之前的数据 - encode := gob.NewEncoder(buf) - err := encode.Encode(p.mod_list) + // 从对象池获取 encoder + pair := getEncoder() + defer putEncoder(pair) + + // 序列化模块 + err := pair.encoder.Encode(p.mod_list) if err != nil { - bufferPool.Put(buf) // 即使出错也要归还 - log.Debug("uid: %d, SaveData, playmod error %v", player.M_DwUin, err) + log.Debug("uid: %d, SaveData, playmod encode error %v", player.M_DwUin, err) return } - // log.Debug("uid: %d, ClearData, playmod", player.M_DwUin) + + // 复制数据,避免 buf 放回池后数据被清空 + modDataBytes := make([]byte, pair.buffer.Len()) + copy(modDataBytes, pair.buffer.Bytes()) + modData := &db.SqlModStruct{ DwUin: player.M_DwUin, - ModData: buf.Bytes(), + ModData: modDataBytes, UpdataTime: int32(time.Now().Unix()), } err = db.SavePlayerModData(modData) if err != nil { - bufferPool.Put(buf) // 即使出错也要归还 - log.Debug("uid: %d, SaveData, playmod error %v", player.M_DwUin, err) + log.Debug("uid: %d, SaveData, db save error %v", player.M_DwUin, err) return } p.is_update = false - bufferPool.Put(buf) // 归还到对象池 } } func (p *PlayerMod) BackUp(B *PlayerBackUp) { - // 从对象池获取 buffer,复用以减少内存分配 - buf := bufferPool.Get().(*bytes.Buffer) - buf.Reset() // 清空之前的数据 + // 从对象池获取 encoder + pair := getEncoder() + defer putEncoder(pair) - encode := gob.NewEncoder(buf) - err := encode.Encode(p.mod_list) + err := pair.encoder.Encode(p.mod_list) if err != nil { log.Debug("Backup, playmod error %v", err) - bufferPool.Put(buf) // 即使出错也要归还 return } // 复制数据,因为 buf 会被放回池中 - B.PlayMod = append([]byte(nil), buf.Bytes()...) - - // 归还到对象池供下次使用 - bufferPool.Put(buf) + B.PlayMod = make([]byte, pair.buffer.Len()) + copy(B.PlayMod, pair.buffer.Bytes()) } func (p *PlayerMod) Recover(B *PlayerBackUp) { if len(B.PlayMod) > 0 { PlayMod := PlayerModList{} - buf := bytes.NewBuffer(B.PlayMod) - decoder := gob.NewDecoder(buf) - err := decoder.Decode(&PlayMod) + // 从对象池获取 decoder + pair := getDecoder(B.PlayMod) + defer putDecoder(pair) + + err := pair.decoder.Decode(&PlayMod) if err != nil { log.Debug("Recover, playmod error %v", err) return diff --git a/src/server/game/unit_test.go b/src/server/game/unit_test.go index ffa0d114..1a582325 100644 --- a/src/server/game/unit_test.go +++ b/src/server/game/unit_test.go @@ -339,8 +339,6 @@ func UnitDecoratePartCost(p *Player) error { fmt.Print(err) } return nil - ChessMod := p.PlayMod.getChessMod() - return ChessMod.PutPartInBag(1515) } func UnitOrderTrigger(p *Player) error { diff --git a/src/server/game_util/randUtil.go b/src/server/game_util/randUtil.go index 80e5ec4d..204315ce 100644 --- a/src/server/game_util/randUtil.go +++ b/src/server/game_util/randUtil.go @@ -52,13 +52,15 @@ func RandStringMap(d map[string]int) string { // 从d中随机选取n个元素 不放回 func RandMapNum(d map[int]int, n int) []int { - if n <= 0 || n > len(d) { + if n <= 0 { return nil } - if n == len(d) { + if n >= len(d) { + r := make([]int, 0, len(d)) for k := range d { - return []int{k} + r = append(r, k) } + return r } r := make([]int, 0, n) for i := 0; i < n; i++ { diff --git a/src/server/game_util/sliceUtil.go b/src/server/game_util/sliceUtil.go index 268c8402..ef93d136 100644 --- a/src/server/game_util/sliceUtil.go +++ b/src/server/game_util/sliceUtil.go @@ -12,13 +12,13 @@ import ( func IntSlice(d interface{}) []int { if d == nil { - return []int{} + return nil } // Type assertion with safety check result, ok := d.([]int) if !ok { - return []int{} + return nil } return result } @@ -77,12 +77,18 @@ func RandItem(slice []*item.Item) *item.Item { } func RandSliceNum(s []int, num int) []int { + if num <= 0 || len(s) == 0 { + return nil + } + if len(s) <= num { + result := make([]int, len(s)) + copy(result, s) + return result + } + slice := make([]int, len(s)) copy(slice, s) r := make([]int, 0, num) - if num <= 0 || len(slice) < num { - return slice - } for i := 0; i < num; i++ { Id := rand.Intn(len(slice)) @@ -93,12 +99,18 @@ func RandSliceNum(s []int, num int) []int { } func RandSliceNum2(s []interface{}, num int) []interface{} { + if num <= 0 || len(s) == 0 { + return nil + } + if len(s) <= num { + result := make([]interface{}, len(s)) + copy(result, s) + return result + } + slice := make([]interface{}, len(s)) copy(slice, s) r := make([]interface{}, 0, num) - if num <= 0 || len(slice) < num { - return slice - } for i := 0; i < num; i++ { Id := rand.Intn(len(slice)) @@ -125,7 +137,7 @@ func RandSliceNumNonAdjacent(s []int, num int) []int { } func SubAdjacentElemSlice(s []int, Id int) []int { - r := make([]int, 0, len(s)) + r := make([]int, 0) for k, v := range s { if k < Id-1 || k > Id+1 { r = append(r, v) @@ -145,7 +157,7 @@ func RandStringSlice(slice []string) string { func SliceStringToInt(s []string) []int { if len(s) == 0 { - return []int{} + return nil } r := make([]int, 0, len(s)) for _, v := range s { @@ -297,6 +309,7 @@ func SlicesEqualString(a, b []string) bool { } // IsContainSlice checks if all elements of s2 are contained in s. +// 注意:此函数会考虑重复元素,s2中的每个元素在s中必须有对应数量 func IsContainSlice(s []int, s2 []int) bool { if len(s2) == 0 { return true @@ -352,7 +365,14 @@ func ShuffleArray(s []int) []int { return r } +// IsContain 与 IsContainSlice 功能相同,建议使用 IsContainSlice func IsContain(s []int, s2 []int) bool { + if len(s2) == 0 { + return true + } + if len(s) < len(s2) { + return false + } for _, v := range s2 { if !InArray(v, s) { return false