From 1ca0ff344e9acb7addfdbaf572eabc9dc60657dc Mon Sep 17 00:00:00 2001 From: xinian Date: Wed, 8 Apr 2026 15:49:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=99=A8=E5=86=A0=E5=90=8DCDK=E5=85=91=E6=8D=A2=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- logic/controller/inbound_user.go | 101 +++++++++++-------------------- logic/controller/user_cdk.go | 42 ++++++++++++- logic/service/user/cdk.go | 20 ++++-- modules/config/model/cdk.go | 1 + modules/config/service/cdk.go | 72 ++++++++++++++++++++++ modules/config/service/server.go | 30 +++++++++ 6 files changed, 194 insertions(+), 72 deletions(-) diff --git a/logic/controller/inbound_user.go b/logic/controller/inbound_user.go index c1e4fb58e..9f136667f 100644 --- a/logic/controller/inbound_user.go +++ b/logic/controller/inbound_user.go @@ -1,92 +1,56 @@ package controller -import ( - "blazing/cool" - "blazing/logic/service/common" - "blazing/modules/player/model" - "context" - "encoding/hex" - "fmt" - "hash/crc32" -) +import "blazing/logic/service/common" -// MAIN_LOGIN_IN 定义请求或响应数据结构。 -type MAIN_LOGIN_IN struct { +type Login struct { Head common.TomeeHeader `cmd:"1001" struc:"skip"` Sid []byte `struc:"[16]byte"` } -// CheakSession 处理控制器请求。 -func (l *MAIN_LOGIN_IN) CheakSession() (bool, uint32) { - t1 := hex.EncodeToString(l.Sid) - r, err := cool.CacheManager.Get(context.Background(), fmt.Sprintf("session:%d", l.Head.UserID)) - if err != nil { - return false, 0 - } - if r.String() != t1 { - return false, 0 - } - crc32Table := crc32.MakeTable(crc32.IEEE) - crcValue := crc32.Checksum([]byte(l.Sid), crc32Table) - cool.CacheManager.Remove(context.Background(), fmt.Sprintf("session:%d", l.Head.UserID)) - return true, crcValue +type HeartBeat struct { + Head common.TomeeHeader `cmd:"2051" struc:"skip"` + Time uint32 } -// SimUserInfoInboundInfo 定义请求或响应数据结构。 -type SimUserInfoInboundInfo struct { - Head common.TomeeHeader `cmd:"2051" struc:"skip"` - UserId uint32 `fieldDescription:"米米号" uint:"true" codec:"true"` +type KeepAlive struct { + Head common.TomeeHeader `cmd:"2052" struc:"skip"` + Time uint32 } -// MoreUserInfoInboundInfo 定义请求或响应数据结构。 -type MoreUserInfoInboundInfo struct { - Head common.TomeeHeader `cmd:"2052" struc:"skip"` - UserId uint32 `fieldDescription:"米米号" uint:"true" codec:"true"` -} - -// AimatInboundInfo 定义请求或响应数据结构。 -type AimatInboundInfo struct { +type UserInfo struct { Head common.TomeeHeader `cmd:"2104" struc:"skip"` - ItemId uint32 `description:"物品id 射击激光 物品id为0" codec:"auto" uint:"true"` - ShootType uint32 `description:"射击类型 未知 给0" codec:"auto" uint:"true"` - Point model.Pos `description:"射击的坐标 x y" codec:"auto"` + UserID uint32 + ShowNono uint8 + RoomStyle uint32 } -// ChatInboundInfo 定义请求或响应数据结构。 -type ChatInboundInfo struct { +type UserTalk struct { Head common.TomeeHeader `cmd:"2102" struc:"skip"` - Reserve uint32 `json:"reserve" fieldDescription:"填充 默认值为0" uint:"true"` - MessageLen uint32 `struc:"sizeof=Message"` - Message string `json:"message" fieldDescription:"消息内容, 结束符为utf-8的数字0"` + ReceiverID uint32 + MessageLen uint32 `struc:"sizeof=Message"` + Message []byte } -// ChangeColorInboundInfo 定义请求或响应数据结构。 -type ChangeColorInboundInfo struct { +type ChangeTitle struct { Head common.TomeeHeader `cmd:"2063" struc:"skip"` - Color uint32 `codec:"color"` + Title uint32 } -// ChangeDoodleInboundInfo 定义请求或响应数据结构。 -type ChangeDoodleInboundInfo struct { - Head common.TomeeHeader `cmd:"2062" struc:"skip"` - Id uint32 `codec:"id"` - Color uint32 `codec:"color"` +type ChangePlayerIcon struct { + Head common.TomeeHeader `cmd:"2062" struc:"skip"` + Icon uint32 } -// ChangeNONOColorInboundInfo 定义请求或响应数据结构。 -type ChangeNONOColorInboundInfo struct { - Head common.TomeeHeader `cmd:"9012" struc:"skip"` - Color uint32 `codec:"color"` +type GetMotto struct { + Head common.TomeeHeader `cmd:"9012" struc:"skip"` } -// C2SDanceAction 定义请求或响应数据结构。 -type C2SDanceAction struct { - Head common.TomeeHeader `cmd:"2103" struc:"skip"` - Reserve uint32 `struc:"uint32,big"` - Type uint32 `struc:"uint32,big"` +type GetTask struct { + Head common.TomeeHeader `cmd:"2103" struc:"skip"` + TaskLen uint32 `struc:"sizeof=TaskList"` + TaskList []uint32 } -// C2SPEOPLE_TRANSFROM 定义请求或响应数据结构。 type C2SPEOPLE_TRANSFROM struct { Head common.TomeeHeader `cmd:"2111" struc:"skip"` SuitID uint32 `struc:"uint32,big"` @@ -106,6 +70,13 @@ type ChangeTitleInboundInfo struct { // C2S_GET_GIFT_COMPLETE 定义请求或响应数据结构。 type C2S_GET_GIFT_COMPLETE struct { - Head common.TomeeHeader `cmd:"2801" struc:"skip"` - PassText string `struc:"[16]byte"` + Head common.TomeeHeader `cmd:"2801" struc:"skip"` + PassText string `struc:"[16]byte"` + Type uint32 + ServerID uint32 + ServerName string `struc:"[16]byte"` +} + +type C2S_GET_DONATION_SERVER_IDS struct { + Head common.TomeeHeader `cmd:"2802" struc:"skip"` } diff --git a/logic/controller/user_cdk.go b/logic/controller/user_cdk.go index f2a96a4a1..b5750b25e 100644 --- a/logic/controller/user_cdk.go +++ b/logic/controller/user_cdk.go @@ -2,21 +2,31 @@ package controller import ( "blazing/common/socket/errorcode" + "blazing/cool" logicplayer "blazing/logic/service/player" "blazing/logic/service/user" configservice "blazing/modules/config/service" playerservice "blazing/modules/player/service" + "strings" "time" ) +// DonationServerIDs 返回当前可用于捐赠冠名的服务器ID列表。 +func (h Controller) DonationServerIDs(data *C2S_GET_DONATION_SERVER_IDS, player *logicplayer.Player) (result *user.S2C_GET_DONATION_SERVER_IDS, err errorcode.ErrorCode) { + return &user.S2C_GET_DONATION_SERVER_IDS{ + ServerIDs: configservice.NewServerService().GetDonationAvailableServerIDs(), + }, 0 +} + // CDK 处理控制器请求。 func (h Controller) CDK(data *C2S_GET_GIFT_COMPLETE, player *logicplayer.Player) (result *user.S2C_GET_GIFT_COMPLETE, err errorcode.ErrorCode) { - result = &user.S2C_GET_GIFT_COMPLETE{} + result = &user.S2C_GET_GIFT_COMPLETE{Type: data.Type} + cdkCode := strings.Trim(data.PassText, "\x00") cdkService := configservice.NewCdkService() now := time.Now() - r := cdkService.Get(data.PassText) + r := cdkService.Get(cdkCode) if r == nil { return nil, errorcode.ErrorCodes.ErrMolecularCodeNotExists } @@ -29,7 +39,33 @@ func (h Controller) CDK(data *C2S_GET_GIFT_COMPLETE, player *logicplayer.Player) if !player.Service.Cdk.CanGet(uint32(r.ID)) { return } - if !cdkService.Set(data.PassText) { + + if r.CDKType == configservice.CDKTypeServerNaming { + if data.Type != configservice.CDKTypeServerNaming { + return nil, errorcode.ErrorCodes.ErrSystemError + } + + serverName := cool.Filter.Replace(strings.Trim(data.ServerName, "\x00"), '*') + if data.ServerID == 0 || serverName == "" { + return nil, errorcode.ErrorCodes.ErrSystemError + } + + serverInfo, useErr := cdkService.UseServerNamingCDK(nil, cdkCode, data.Head.UserID, data.ServerID, serverName) + if useErr != nil { + return nil, errorcode.ErrorCodes.ErrSystemError + } + + result.Flag = 1 + result.ServerID = serverInfo.OnlineID + result.ServerName = serverInfo.Name + player.Service.Cdk.Log(uint32(r.ID)) + return result, 0 + } + + if data.Type == configservice.CDKTypeServerNaming { + return nil, errorcode.ErrorCodes.ErrSystemError + } + if !cdkService.Set(cdkCode) { return nil, errorcode.ErrorCodes.ErrMolecularCodeGiftsGone } diff --git a/logic/service/user/cdk.go b/logic/service/user/cdk.go index 31e6e0934..dfcacdaf3 100644 --- a/logic/service/user/cdk.go +++ b/logic/service/user/cdk.go @@ -5,26 +5,38 @@ import "blazing/logic/service/common" // C2S_GET_GIFT_COMPLETE 礼品兑换完成协议 // 前端到后端 type C2S_GET_GIFT_COMPLETE struct { - Head common.TomeeHeader `cmd:"2801" struc:"skip"` - PassText string `struc:"[16]byte"` + Head common.TomeeHeader `cmd:"2801" struc:"skip"` + PassText string `struc:"[16]byte"` + Type uint32 + ServerID uint32 + ServerName string `struc:"[16]byte"` } // S2C_GET_GIFT_COMPLETE 礼品兑换完成协议 // 后端到前端 type S2C_GET_GIFT_COMPLETE struct { - Flag uint32 `json:"flag"` // 0 代表sdk已被使用 1 表示兑换成功 如果返回0 那么后续数组不需要返回 + Flag uint32 `json:"flag"` + Type uint32 `json:"type"` Tile uint32 `json:"tile"` + ServerID uint32 `json:"server_id"` + ServerName string `struc:"[16]byte" json:"server_name"` GiftListLen uint32 `struc:"sizeof=GiftList"` - GiftList []GiftInfo `json:"giftList"` // 物品id数组 + GiftList []GiftInfo `json:"giftList"` PetGiftLen uint32 `struc:"sizeof=PetGift"` PetGift []PetGiftInfo `json:"petGiftList"` } +type S2C_GET_DONATION_SERVER_IDS struct { + ServerIDsLen uint32 `struc:"sizeof=ServerIDs" json:"server_ids_len"` + ServerIDs []uint32 `json:"server_ids"` +} + // GiftInfo 礼品信息 type GiftInfo struct { GiftID int64 `struc:"uint32"` Count int64 `struc:"uint32"` } + type PetGiftInfo struct { PetID uint32 `json:"petID"` CacthTime uint32 `json:"catchTime"` diff --git a/modules/config/model/cdk.go b/modules/config/model/cdk.go index a62a2d7b4..db4fc2d33 100644 --- a/modules/config/model/cdk.go +++ b/modules/config/model/cdk.go @@ -16,6 +16,7 @@ type CDKConfig struct { // 核心字段 CDKCode string `gorm:"not null;size:16;uniqueIndex;comment:'CDK编号(唯一标识,用于玩家兑换)'" json:"cdk_code" description:"CDK编号"` + CDKType uint32 `gorm:"column:type;not null;default:0;comment:'CDK类型:0普通奖励,1服务器冠名'" json:"type" description:"CDK类型"` //cdk可兑换次数,where不等于0 ExchangeRemainCount int64 `gorm:"not null;default:1;comment:'CDK剩余可兑换次数(不能为0才允许兑换,支持查询where !=0)'" json:"exchange_remain_count" description:"剩余可兑换次数"` diff --git a/modules/config/service/cdk.go b/modules/config/service/cdk.go index b84d8e793..4bfa0f1ea 100644 --- a/modules/config/service/cdk.go +++ b/modules/config/service/cdk.go @@ -7,6 +7,7 @@ import ( "crypto/rand" "fmt" "math/big" + "time" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gerror" @@ -17,6 +18,9 @@ import ( const charsetWithSymbol = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz" const ( + CDKTypeReward uint32 = 0 + CDKTypeServerNaming uint32 = 1 + cdkCodeLength = 16 maxBatchGenerateCount = 5000 ) @@ -156,6 +160,74 @@ func (s *CdkService) Set(id string) bool { return true } +func (s *CdkService) UseServerNamingCDK(ctx context.Context, code string, ownerID, serverID uint32, serverName string) (*model.ServerList, error) { + if ctx == nil { + ctx = context.TODO() + } + now := time.Now() + serverService := NewServerService() + var updated model.ServerList + + err := g.DB(s.Model.GroupName()).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { + var cfg model.CDKConfig + if err := tx.Model(s.Model).Where("cdk_code", code).WhereNot("exchange_remain_count", 0).Scan(&cfg); err != nil { + return err + } + if cfg.ID == 0 { + return gerror.New("cdk不存在") + } + if cfg.CDKType != CDKTypeServerNaming { + return gerror.New("cdk类型不匹配") + } + if cfg.BindUserId != 0 && cfg.BindUserId != ownerID { + return gerror.New("cdk已绑定其他用户") + } + if !cfg.ValidEndTime.IsZero() && cfg.ValidEndTime.Before(now) { + return gerror.New("cdk已过期") + } + + var server model.ServerList + if err := tx.Model(model.NewServerList()).Where("online_id", serverID).Scan(&server); err != nil { + return err + } + if !serverService.CanUseDonationName(server, now) { + return gerror.New("服务器不可冠名") + } + + res, err := tx.Model(s.Model).Where("cdk_code", code).WhereNot("exchange_remain_count", 0).Decrement("exchange_remain_count", 1) + if err != nil { + return err + } + rows, _ := res.RowsAffected() + if rows == 0 { + return gerror.New("cdk已被使用") + } + + baseTime := now + if server.ExpireTime.After(now) { + baseTime = server.ExpireTime + } + updated = server + updated.Name = serverName + updated.Owner = ownerID + updated.ExpireTime = baseTime.AddDate(0, 1, 0) + + _, err = tx.Model(model.NewServerList()).Where("online_id", serverID).Data(g.Map{ + "name": updated.Name, + "owner": updated.Owner, + "expire_time": updated.ExpireTime, + }).Update() + return err + }) + if err != nil { + return nil, err + } + + g.DB(s.Model.GroupName()).GetCore().ClearCache(context.TODO(), s.Model.TableName()) + g.DB(model.NewServerList().GroupName()).GetCore().ClearCache(context.TODO(), model.NewServerList().TableName()) + return &updated, nil +} + func (s *CdkService) BatchGenerate(ctx context.Context, count int) (interface{}, error) { if count <= 0 { return nil, gerror.New("生成数量必须大于0") diff --git a/modules/config/service/server.go b/modules/config/service/server.go index 6a6e582f3..8b78a0e05 100644 --- a/modules/config/service/server.go +++ b/modules/config/service/server.go @@ -6,6 +6,7 @@ import ( "blazing/modules/config/model" "fmt" "sort" + "time" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/frame/g" @@ -130,6 +131,35 @@ func (s *ServerService) GetServerID(OnlineID uint32) model.ServerList { } +func (s *ServerService) GetDonationAvailableServerIDs() []uint32 { + now := time.Now() + builder := dbm_nocache_noenable(s.Model).Builder().Where("owner", 0).WhereOr("expire_time <= ?", now) + + var rows []struct { + OnlineID uint32 `json:"online_id"` + } + dbm_nocache_noenable(s.Model).Fields("online_id").Where(builder).OrderAsc("online_id").Scan(&rows) + + ids := make([]uint32, 0, len(rows)) + for _, row := range rows { + if row.OnlineID == 0 { + continue + } + ids = append(ids, row.OnlineID) + } + return ids +} + +func (s *ServerService) CanUseDonationName(server model.ServerList, now time.Time) bool { + if server.OnlineID == 0 { + return false + } + if server.Owner == 0 { + return true + } + return !server.ExpireTime.After(now) +} + // 保存版本号 func (s *ServerService) SetServerScreen(id uint32, name string) {