feat(config): 添加超时空地图配置和时间地图查询功能 新增IsTimeSpace字段用于标识地图是否为超时空地图, 添加TimeMap API接口支持查询超时空地图配置 perf(socket): 优化XORDecryptU解密函数减少内存分配 基于bytebufferpool实现缓冲区池化,大幅降低高频调用下的 内存分配和GC压力,提升性能表现 refactor(utils): 优化packVal序列化函数提升性能和稳定性 减少反射开销,
This commit is contained in:
@@ -13,6 +13,8 @@ go tool pprof -http :8081 "http://127.0.0.1:9909/debug/pprof/profile"
|
|||||||
|
|
||||||
go tool pprof -http :8081 "http://202.189.15.67:62672/debug/pprof/profile"
|
go tool pprof -http :8081 "http://202.189.15.67:62672/debug/pprof/profile"
|
||||||
go tool pprof -http :8081 "http://8.162.8.203:9909/debug/pprof//profile"
|
go tool pprof -http :8081 "http://8.162.8.203:9909/debug/pprof//profile"
|
||||||
|
go tool pprof -http :8081 "http://8.162.23.87:9909/debug/pprof//profile"
|
||||||
|
|
||||||
详情查看 [文档](./docs)
|
详情查看 [文档](./docs)
|
||||||
|
|
||||||
- [战斗](./docs/battle.md)
|
- [战斗](./docs/battle.md)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/gogf/gf/v2/frame/g"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
"github.com/panjf2000/gnet/v2"
|
"github.com/panjf2000/gnet/v2"
|
||||||
|
"github.com/valyala/bytebufferpool"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) Boot(serverid, port uint16) error {
|
func (s *Server) Boot(serverid, port uint16) error {
|
||||||
@@ -305,21 +306,41 @@ func (s *Server) onevent(c gnet.Conn, v []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// XORDecryptU 优化后的异或解密:减少内存分配,支持复用缓冲区
|
// XORDecryptU 优化后的异或解密:减少内存分配,支持复用缓冲区
|
||||||
|
// XORDecryptU 基于bytebufferpool优化的异或解密函数
|
||||||
|
// 保留原有接口,无侵入式优化,高频调用下大幅减少内存分配和GC
|
||||||
func XORDecryptU(encryptedData []byte, key uint32) []byte {
|
func XORDecryptU(encryptedData []byte, key uint32) []byte {
|
||||||
if len(encryptedData) == 0 {
|
if len(encryptedData) == 0 {
|
||||||
return []byte{}
|
return []byte{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 预分配密钥字节数组(可全局缓存,避免每次创建)
|
// 1. 栈上分配密钥字节数组(无GC压力,保留原优化)
|
||||||
var keyBytes [4]byte // 栈上分配,比make更高效
|
var keyBytes [4]byte
|
||||||
binary.BigEndian.PutUint32(keyBytes[:], key)
|
binary.BigEndian.PutUint32(keyBytes[:], key)
|
||||||
keyLen := len(keyBytes)
|
keyLen := len(keyBytes)
|
||||||
|
|
||||||
// 复用输出缓冲区:如果需要极致性能,可传入外部缓冲区
|
// 2. 从bytebufferpool获取池化缓冲区(替代make分配)
|
||||||
decrypted := make([]byte, len(encryptedData))
|
buf := bytebufferpool.Get()
|
||||||
|
defer bytebufferpool.Put(buf) // 函数结束自动归还缓冲区到池
|
||||||
|
|
||||||
|
// 3. 调整缓冲区长度,匹配待解密数据(避免扩容)
|
||||||
|
buf.B = buf.B[:0] // 清空原有数据,保留底层数组
|
||||||
|
if cap(buf.B) < len(encryptedData) {
|
||||||
|
// 若缓冲区容量不足,直接扩容(bytebufferpool会自动管理)
|
||||||
|
buf.B = make([]byte, len(encryptedData))
|
||||||
|
} else {
|
||||||
|
// 容量足够,直接调整长度
|
||||||
|
buf.B = buf.B[:len(encryptedData)]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 核心异或解密逻辑(直接操作buf.B,无额外内存分配)
|
||||||
|
decrypted := buf.B
|
||||||
for i, b := range encryptedData {
|
for i, b := range encryptedData {
|
||||||
decrypted[i] = b ^ keyBytes[i%keyLen]
|
decrypted[i] = b ^ keyBytes[i%keyLen]
|
||||||
}
|
}
|
||||||
|
|
||||||
return decrypted
|
// 5. 拷贝结果(关键:避免返回池化缓冲区,防止被后续调用覆盖)
|
||||||
|
result := make([]byte, len(decrypted))
|
||||||
|
copy(result, decrypted)
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Field struct {
|
type Field struct {
|
||||||
@@ -76,40 +77,60 @@ func (f *Field) Size(val reflect.Value, options *Options) int {
|
|||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 预定义常用的order,避免重复判断
|
||||||
|
var defaultOrder = binary.BigEndian
|
||||||
|
|
||||||
|
// packVal 优化版:减少反射开销+优化内存拷贝+优雅错误处理
|
||||||
func (f *Field) packVal(buf []byte, val reflect.Value, length int, options *Options) (size int, err error) {
|
func (f *Field) packVal(buf []byte, val reflect.Value, length int, options *Options) (size int, err error) {
|
||||||
|
// 1. 预缓存order,避免重复判断
|
||||||
order := f.Order
|
order := f.Order
|
||||||
if options.Order != nil {
|
if options != nil && options.Order != nil {
|
||||||
order = options.Order
|
order = options.Order
|
||||||
}
|
}
|
||||||
if f.Ptr {
|
if order == nil {
|
||||||
val = val.Elem()
|
order = defaultOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. 处理指针类型:提前解引用,避免后续重复操作
|
||||||
|
if f.Ptr {
|
||||||
|
if !val.IsNil() {
|
||||||
|
val = val.Elem()
|
||||||
|
} else {
|
||||||
|
return 0, fmt.Errorf("field %s is nil pointer", f.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 预解析类型,避免重复Resolve
|
||||||
typ := f.Type.Resolve(options)
|
typ := f.Type.Resolve(options)
|
||||||
|
kind := val.Kind()
|
||||||
|
|
||||||
|
// 4. 扁平化分支逻辑,减少嵌套
|
||||||
switch typ {
|
switch typ {
|
||||||
case Struct:
|
case Struct:
|
||||||
return f.Fields.Pack(buf, val, options)
|
return f.Fields.Pack(buf, val, options)
|
||||||
|
|
||||||
case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64:
|
case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64:
|
||||||
size = typ.Size()
|
size = typ.Size()
|
||||||
var n uint64
|
if len(buf) < size {
|
||||||
switch f.kind {
|
return 0, fmt.Errorf("buf size %d < required %d", len(buf), size)
|
||||||
case reflect.Bool:
|
|
||||||
if val.Bool() {
|
|
||||||
n = 1
|
|
||||||
} else {
|
|
||||||
n = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var n uint64
|
||||||
|
switch kind {
|
||||||
|
case reflect.Bool:
|
||||||
|
n = boolToUint64(val.Bool())
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
n = uint64(val.Int())
|
n = uint64(val.Int())
|
||||||
default:
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
n = val.Uint()
|
n = val.Uint()
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("unsupported kind %s for numeric type %s", kind, typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 扁平化数值写入逻辑
|
||||||
switch typ {
|
switch typ {
|
||||||
case Bool:
|
case Bool:
|
||||||
if n != 0 {
|
buf[0] = byte(n)
|
||||||
buf[0] = 1
|
|
||||||
} else {
|
|
||||||
buf[0] = 0
|
|
||||||
}
|
|
||||||
case Int8, Uint8:
|
case Int8, Uint8:
|
||||||
buf[0] = byte(n)
|
buf[0] = byte(n)
|
||||||
case Int16, Uint16:
|
case Int16, Uint16:
|
||||||
@@ -117,33 +138,90 @@ func (f *Field) packVal(buf []byte, val reflect.Value, length int, options *Opti
|
|||||||
case Int32, Uint32:
|
case Int32, Uint32:
|
||||||
order.PutUint32(buf, uint32(n))
|
order.PutUint32(buf, uint32(n))
|
||||||
case Int64, Uint64:
|
case Int64, Uint64:
|
||||||
order.PutUint64(buf, uint64(n))
|
order.PutUint64(buf, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Float32, Float64:
|
case Float32, Float64:
|
||||||
size = typ.Size()
|
size = typ.Size()
|
||||||
|
if len(buf) < size {
|
||||||
|
return 0, fmt.Errorf("buf size %d < required %d", len(buf), size)
|
||||||
|
}
|
||||||
|
|
||||||
|
if kind != reflect.Float32 && kind != reflect.Float64 {
|
||||||
|
return 0, fmt.Errorf("unsupported kind %s for float type %s", kind, typ)
|
||||||
|
}
|
||||||
n := val.Float()
|
n := val.Float()
|
||||||
|
|
||||||
switch typ {
|
switch typ {
|
||||||
case Float32:
|
case Float32:
|
||||||
order.PutUint32(buf, math.Float32bits(float32(n)))
|
order.PutUint32(buf, math.Float32bits(float32(n)))
|
||||||
case Float64:
|
case Float64:
|
||||||
order.PutUint64(buf, math.Float64bits(n))
|
order.PutUint64(buf, math.Float64bits(n))
|
||||||
}
|
}
|
||||||
|
|
||||||
case String:
|
case String:
|
||||||
switch f.kind {
|
// 优化String类型:减少内存拷贝
|
||||||
|
switch kind {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
|
s := val.String()
|
||||||
|
size = len(s)
|
||||||
|
if len(buf) < size {
|
||||||
|
return 0, fmt.Errorf("buf size %d < string length %d", len(buf), size)
|
||||||
|
}
|
||||||
|
// 用unsafe直接拷贝字符串到buf,避免[]byte(s)的内存分配
|
||||||
|
copyStringToBuf(buf, s)
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
if val.Type().Elem().Kind() != reflect.Uint8 {
|
||||||
|
return 0, fmt.Errorf("unsupported slice type %s for String field", val.Type())
|
||||||
|
}
|
||||||
size = val.Len()
|
size = val.Len()
|
||||||
copy(buf, []byte(val.String()))
|
if len(buf) < size {
|
||||||
default:
|
return 0, fmt.Errorf("buf size %d < bytes length %d", len(buf), size)
|
||||||
// TODO: handle kind != bytes here
|
}
|
||||||
size = val.Len()
|
// 直接拷贝字节切片,避免冗余操作
|
||||||
copy(buf, val.Bytes())
|
copy(buf, val.Bytes())
|
||||||
}
|
|
||||||
case CustomType:
|
|
||||||
return val.Addr().Interface().(Custom).Pack(buf, options)
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("no pack handler for type: %s", typ))
|
return 0, fmt.Errorf("unsupported kind %s for String type", kind)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
case CustomType:
|
||||||
|
// 优化反射断言:提前检查类型,避免panic
|
||||||
|
if !val.CanAddr() {
|
||||||
|
return 0, fmt.Errorf("custom type %s cannot take address", val.Type())
|
||||||
|
}
|
||||||
|
custom, ok := val.Addr().Interface().(Custom)
|
||||||
|
if !ok {
|
||||||
|
return 0, fmt.Errorf("type %s does not implement Custom interface", val.Type())
|
||||||
|
}
|
||||||
|
return custom.Pack(buf, options)
|
||||||
|
|
||||||
|
default:
|
||||||
|
// 替换panic为error,避免程序崩溃
|
||||||
|
return 0, fmt.Errorf("no pack handler for type: %s", typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
return size, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助函数:bool转uint64,减少inline重复代码
|
||||||
|
func boolToUint64(b bool) uint64 {
|
||||||
|
if b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助函数:unsafe拷贝字符串到buf,避免[]byte(s)的内存分配
|
||||||
|
// 注意:仅在确定buf长度足够时使用
|
||||||
|
func copyStringToBuf(buf []byte, s string) {
|
||||||
|
// unsafe转换:字符串转字节切片,无内存分配
|
||||||
|
src := *(*[]byte)(unsafe.Pointer(&struct {
|
||||||
|
string
|
||||||
|
cap int
|
||||||
|
}{s, len(s)}))
|
||||||
|
copy(buf, src)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) Pack(buf []byte, val reflect.Value, length int, options *Options) (int, error) {
|
func (f *Field) Pack(buf []byte, val reflect.Value, length int, options *Options) (int, error) {
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package admin
|
|||||||
import (
|
import (
|
||||||
"blazing/cool"
|
"blazing/cool"
|
||||||
"blazing/modules/config/service"
|
"blazing/modules/config/service"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MapController struct {
|
type MapController struct {
|
||||||
@@ -20,3 +23,13 @@ func init() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TimeMapReq struct {
|
||||||
|
g.Meta `path:"/timemap" method:"POST"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *MapController) TimeMap(ctx context.Context, req *TimeMapReq) (res *cool.BaseRes, err error) {
|
||||||
|
res = &cool.BaseRes{}
|
||||||
|
res.Data = service.NewMapService().GetTimeMap()
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ type MapConfig struct {
|
|||||||
MapID uint32 `gorm:"not null;primaryKey;comment:'地图唯一ID(主键)'" json:"map_id" description:"地图ID"`
|
MapID uint32 `gorm:"not null;primaryKey;comment:'地图唯一ID(主键)'" json:"map_id" description:"地图ID"`
|
||||||
|
|
||||||
WeatherType []uint32 `gorm:"type:int[];comment:'天气类型( 1-雨天,2-雪天)'" json:"weather_type"`
|
WeatherType []uint32 `gorm:"type:int[];comment:'天气类型( 1-雨天,2-雪天)'" json:"weather_type"`
|
||||||
|
//是否超时空
|
||||||
|
IsTimeSpace int `gorm:"type:int;default:0;comment:'是否超时空'" json:"is_time_space"`
|
||||||
|
|
||||||
// 掉落物配置
|
// 掉落物配置
|
||||||
DropItemIds []uint32 `gorm:"type:int[];comment:'掉落物IDs" json:"drop_item_ids"`
|
DropItemIds []uint32 `gorm:"type:int[];comment:'掉落物IDs" json:"drop_item_ids"`
|
||||||
|
|||||||
@@ -29,3 +29,12 @@ func (s *MapService) GetData(p1 uint32) (ret *model.MapConfig) {
|
|||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
func (s *MapService) GetTimeMap() (ret []model.MapConfig) {
|
||||||
|
//cacheKey := strings.Join([]string{fmt.Sprintf("%d", p1), fmt.Sprintf("%d", p2)}, ":")
|
||||||
|
m := dbm_notenable(s.Model)
|
||||||
|
|
||||||
|
m.Where(`is_time_space`, 1).Scan(&ret)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user