``feat(item): 新增物品出售价格属性(SellPrice)并实现物品出售功能,优化宠物面板计算和时区判断逻辑``

This commit is contained in:
1
2025-12-12 19:10:09 +00:00
parent 3242207f95
commit cedb02faf7
35 changed files with 172 additions and 152 deletions

View File

@@ -46,6 +46,7 @@ type Item struct {
DualEvTimes int `xml:"DualEvTimes,attr,omitempty"` // 双倍学习力次数(学习力双倍仪)
YuanshenDegrade int `xml:"YuanshenDegrade,attr,omitempty"` // 融合精灵还原标识(融合精灵还原药剂)
EvRemove int `xml:"EvRemove,attr,omitempty"` // 学习力遗忘类型(各类学习力遗忘剂)
SellPrice int `xml:"SellPrice,attr,omitempty"` // 出售价格(出售价格修正)
//bShowPetBag int `xml:"bShowPetBag,attr,omitempty"` // 宠物背包显示标识(副融合精灵保留药剂等)
Nature *string `xml:"Nature,attr"` // 指向int的指针无值时为nil
NatureSet *string `xml:"NatureSet,attr"` // 指向string的指针无值时为nil

View File

@@ -1,23 +0,0 @@
package controller
import (
"blazing/common/socket/errorcode"
"blazing/logic/service/item"
"blazing/logic/service/player"
)
func (h Controller) PlayerGoldCount(data *item.GoldOnlineRemainInboundInfo, c *player.Player) (result *item.GoldOnlineRemainOutboundInfo, err errorcode.ErrorCode) {
return &item.GoldOnlineRemainOutboundInfo{
GoldNumber: c.User.GetGold(uint(c.Info.UserID)),
Coin: c.Info.Coins,
}, 0
}
func (h Controller) PlayerExp(data *item.ExpTotalRemainInboundInfo, c *player.Player) (result *item.ExpTotalRemainOutboundInfo, err errorcode.ErrorCode) {
return &item.ExpTotalRemainOutboundInfo{
TotalExp: uint32(c.Info.ExpPool),
}, 0
}

View File

@@ -0,0 +1,21 @@
package controller
import (
"blazing/common/data/xmlres"
"blazing/common/socket/errorcode"
"blazing/logic/service/fight"
"blazing/logic/service/item"
"blazing/logic/service/player"
)
func (h Controller) ITEM_SALE(data *item.C2S_ITEM_SALE, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if c.Service.Item.CheakItem(data.ItemId) < data.Amount {
return nil, errorcode.ErrorCodes.ErrSystemError
}
if xmlres.ItemsMAP[int(data.ItemId)].SellPrice != 0 {
c.Info.Coins += uint32(int64(data.Amount) * int64(xmlres.ItemsMAP[int(data.ItemId)].SellPrice))
}
return result, 0
}

View File

@@ -11,7 +11,6 @@ import (
"blazing/logic/service/player"
"blazing/logic/service/space"
"blazing/modules/base/service"
blservice "blazing/modules/blazing/service"
"context"
"time"
@@ -19,16 +18,6 @@ import (
"github.com/panjf2000/gnet/v2"
)
func IsToday(t time.Time) bool {
// 获取当前时间
now := time.Now()
// 比较年、月、日是否相同
return t.Year() == now.Year() &&
t.Month() == now.Month() &&
t.Day() == now.Day()
}
// 处理命令: 1001
func (h *Controller) Login(data *user.MAIN_LOGIN_IN, c gnet.Conn) (result *user.LoginMSInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
tt := data.CheakSession()
@@ -38,15 +27,13 @@ func (h *Controller) Login(data *user.MAIN_LOGIN_IN, c gnet.Conn) (result *user.
return
}
cool.Loger.Info(context.TODO(), "准备踢人")
err1 := h.RPCClient.Kick(data.Head.UserID) //先踢人
if err1 != nil {
fmt.Println("踢人失败", err)
}
//player.KickPlayer(data.Head.UserID)
cool.Loger.Info(context.TODO(), "踢人请求完成,继续登录流程")
// <-time.After(time.Millisecond * 3000)
share.ShareManager.SetUserOnline(data.Head.UserID, h.Port) //设置用户登录服务器
t := player.GetPlayer(c, data.Head.UserID)
if t == nil {
@@ -56,7 +43,7 @@ func (h *Controller) Login(data *user.MAIN_LOGIN_IN, c gnet.Conn) (result *user.
return
}
t.Service = blservice.NewUserService(data.Head.UserID)
t.User = service.NewBaseSysUserService()
t.Info = t.Service.Info.Personself()
if t.Info == nil {
@@ -66,6 +53,7 @@ func (h *Controller) Login(data *user.MAIN_LOGIN_IN, c gnet.Conn) (result *user.
t.Info.UserID = data.Head.UserID
t.Logintime = uint32(time.Now().Unix()) //保存时间戳
t.CompleteLogin() //通知客户端登录成功
result = user.NewOutInfo() //设置登录消息

View File

@@ -6,15 +6,15 @@ import (
"blazing/logic/service/fight"
"blazing/logic/service/maphot"
"blazing/logic/service/maps"
"blazing/logic/service/maps/info"
"blazing/logic/service/space/info"
"blazing/logic/service/player"
"blazing/logic/service/space"
"github.com/jinzhu/copier"
)
func (h *Controller) MapEnter(data *maps.InInfo, c *player.Player) (result *info.OutInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
func (h *Controller) MapEnter(data *space.InInfo, c *player.Player) (result *info.OutInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
c.Info.MapID = data.MapId //登录地图
c.GetSpace().User.Store(c.Info.UserID, c) //添加玩家
@@ -36,7 +36,7 @@ func (h Controller) MapHot(data *maphot.InInfo, c *player.Player) (result *mapho
return
}
func (h *Controller) MapLeave(data *maps.LeaveMapInboundInfo, c *player.Player) (result *info.LeaveMapOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
func (h *Controller) MapLeave(data *space.LeaveMapInboundInfo, c *player.Player) (result *info.LeaveMapOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
//data.Broadcast(c.Info.MapID, info.LeaveMapOutboundInfo{UserID: c.Info.UserID}) //同步广播
result = &info.LeaveMapOutboundInfo{
@@ -49,7 +49,7 @@ func (h *Controller) MapLeave(data *maps.LeaveMapInboundInfo, c *player.Player)
//c.Info.MapID = 0 // 重置当前地图
return
}
func (h *Controller) MapList(data *maps.ListMapPlayerInboundInfo, c *player.Player) (result *info.ListMapPlayerOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
func (h *Controller) MapList(data *space.ListMapPlayerInboundInfo, c *player.Player) (result *info.ListMapPlayerOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
atomic.StoreUint32(&c.Canmon, 2)
result = &info.ListMapPlayerOutboundInfo{
@@ -58,7 +58,7 @@ func (h *Controller) MapList(data *maps.ListMapPlayerInboundInfo, c *player.Play
return
}
func (h *Controller) Attack_Boss(data *maps.AttackBossInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
func (h *Controller) Attack_Boss(data *space.AttackBossInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
if atomic.LoadInt32(&c.GetSpace().MapBossInfo.Hp) > 0 {
atomic.AddInt32(&c.GetSpace().MapBossInfo.Hp, -1)

View File

@@ -8,7 +8,7 @@ import (
"github.com/jinzhu/copier"
)
// 处理命令: 105
func (h *Controller) NonoFollowOrHome(data *nono.NonoFollowOrHomeInInfo, c *player.Player) (result *nono.NonoFollowOutInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
c.Info.NONO.Flag = data.Flag
result = &nono.NonoFollowOutInfo{

View File

@@ -237,6 +237,7 @@ func (h Controller) SetPetExp(data *pet.PetSetExpInboundInfo, c *player.Player)
}, 0
}
//精灵图鉴
func (h Controller) PetBargeList(data *pet.PetBargeListInboundInfo, c *player.Player) (result *pet.PetBargeListOutboundInfo, err errorcode.ErrorCode) {
return &pet.PetBargeListOutboundInfo{

View File

@@ -8,34 +8,8 @@ import (
"blazing/logic/service/player"
"blazing/logic/service/user"
"blazing/modules/blazing/model"
"github.com/jinzhu/copier"
)
// UserSimInfo 根据用户ID获取模拟用户信息
// data: 包含用户ID的输入信息
// c: 玩家对象
// 返回: 模拟用户信息及错误码
func (h Controller) UserSimInfo(data *user.SimUserInfoInboundInfo, c *player.Player) (result *user.SimUserInfoOutboundInfo, err errorcode.ErrorCode) {
ret := &user.SimUserInfoOutboundInfo{}
copier.Copy(ret, c.Service.Info.Person(data.UserId))
return ret, 0
}
// UserMoreInfo 获取用户的更多信息。
// data: 包含用户ID的输入信息。
// c: 当前玩家对象。
// 返回: 包含用户更多信息的输出结果和错误码。
func (h Controller) UserMoreInfo(data *user.MoreUserInfoInboundInfo, c *player.Player) (result *user.MoreUserInfoOutboundInfo, err errorcode.ErrorCode) {
ret := &user.MoreUserInfoOutboundInfo{}
info := c.Service.Info.Person(data.UserId)
copier.CopyWithOption(ret, info, copier.Option{IgnoreEmpty: true, DeepCopy: true})
//todo 待实现
return ret, 0
}
// 射击
func (h Controller) Aimat(data *user.AimatInboundInfo, c *player.Player) (result *user.AimatOutboundInfo, err errorcode.ErrorCode) {
result = &user.AimatOutboundInfo{

View File

@@ -0,0 +1,50 @@
package controller
import (
"blazing/common/socket/errorcode"
"blazing/logic/service/item"
"blazing/logic/service/player"
"blazing/logic/service/user"
"github.com/jinzhu/copier"
)
// UserSimInfo 根据用户ID获取模拟用户信息
// data: 包含用户ID的输入信息
// c: 玩家对象
// 返回: 模拟用户信息及错误码
func (h Controller) UserSimInfo(data *user.SimUserInfoInboundInfo, c *player.Player) (result *user.SimUserInfoOutboundInfo, err errorcode.ErrorCode) {
ret := &user.SimUserInfoOutboundInfo{}
copier.Copy(ret, c.Service.Info.Person(data.UserId))
return ret, 0
}
// UserMoreInfo 获取用户的更多信息。
// data: 包含用户ID的输入信息。
// c: 当前玩家对象。
// 返回: 包含用户更多信息的输出结果和错误码。
func (h Controller) UserMoreInfo(data *user.MoreUserInfoInboundInfo, c *player.Player) (result *user.MoreUserInfoOutboundInfo, err errorcode.ErrorCode) {
ret := &user.MoreUserInfoOutboundInfo{}
info := c.Service.Info.Person(data.UserId)
copier.CopyWithOption(ret, info, copier.Option{IgnoreEmpty: true, DeepCopy: true})
//todo 待实现
return ret, 0
}
func (h Controller) PlayerGoldCount(data *item.GoldOnlineRemainInboundInfo, c *player.Player) (result *item.GoldOnlineRemainOutboundInfo, err errorcode.ErrorCode) {
return &item.GoldOnlineRemainOutboundInfo{
GoldNumber: c.User.GetGold(uint(c.Info.UserID)),
Coin: c.Info.Coins,
}, 0
}
func (h Controller) PlayerExp(data *item.ExpTotalRemainInboundInfo, c *player.Player) (result *item.ExpTotalRemainOutboundInfo, err errorcode.ErrorCode) {
return &item.ExpTotalRemainOutboundInfo{
TotalExp: uint32(c.Info.ExpPool),
}, 0
}

View File

@@ -2,12 +2,12 @@ package controller
import (
"blazing/common/socket/errorcode"
"blazing/logic/service/maps"
"blazing/logic/service/maps/info"
"blazing/logic/service/player"
"blazing/logic/service/space"
"blazing/logic/service/space/info"
)
func (h Controller) Walk(data *maps.WalkInInfo, c *player.Player) (result *info.WalkOutInfo, err errorcode.ErrorCode) {
func (h Controller) Walk(data *space.WalkInInfo, c *player.Player) (result *info.WalkOutInfo, err errorcode.ErrorCode) {
result = &info.WalkOutInfo{
Flag: data.Flag,
Point: data.Point,

View File

@@ -37,3 +37,11 @@ type C2S_PET_RESET_NATURE struct {
Nature uint32 // 目标性格值
ItemId uint32 // 消耗的物品ID
}
// C2S_ITEM_SALE 物品出售/兑换请求结构体(对应原 C# 结构体)
// 字段注释保持与原逻辑一致,字段名遵循 Go 命名规范(首字母大写以支持序列化/反序列化)
type C2S_ITEM_SALE struct {
Head common.TomeeHeader `cmd:"2602" struc:"skip"`
ItemId uint32 // 兑换的物品id
Amount uint32 // 兑换的数量
}

View File

@@ -1,23 +0,0 @@
package maps
import (
"blazing/logic/service/common"
"blazing/modules/blazing/model"
)
type LeaveMapInboundInfo struct {
Head common.TomeeHeader `cmd:"2002" struc:"skip"` //切换地图
}
type InInfo struct {
Head common.TomeeHeader `cmd:"2001" struc:"skip"` //切换地图
// 地图类型
MapType uint32
MapId uint32
// Point: 直接给坐标xy
Point model.Pos `fieldDesc:"直接给坐标xy"`
// Reverse2: 暂定 占位字符2
//Reverse2 string `struc:"[2]byte"`
}

View File

@@ -1,11 +0,0 @@
package maps
import "blazing/logic/service/common"
type ListMapPlayerInboundInfo struct {
Head common.TomeeHeader `cmd:"2003" struc:"skip"` //切换地图
}
type AttackBossInboundInfo struct {
Head common.TomeeHeader `cmd:"2412" struc:"skip"` //切换地图
}

View File

@@ -1,18 +0,0 @@
package maps
import (
"blazing/logic/service/common"
"blazing/modules/blazing/model"
)
type WalkInInfo struct {
Head common.TomeeHeader `cmd:"2101" struc:"skip"` //走路包
// Flag: 0为走1为飞行模式@UInt long
Flag uint32
// Point: 直接给坐标xy
Point model.Pos `fieldDesc:"直接给坐标xy"`
PathLen uint32 `struc:"sizeof=Path" `
Path string
}

View File

@@ -3,6 +3,7 @@ package player
import (
"blazing/cool"
"blazing/logic/service/common"
"blazing/modules/base/service"
"blazing/modules/blazing/model"
"time"
)
@@ -14,6 +15,8 @@ func NewPlayer(opts ...PlayerOption) *Player {
HavePVPinfo: make([]common.PlayerI, 0),
baseplayer: newbaseplayer(),
}
p.User = service.NewBaseSysUserService()
p.monsters = generateThreeUniqueNumbers()
p.Done = NewDone(p) //发布订阅事件
p.StopChan = cool.Cron.ScheduleFunc(10*time.Second, func() {

View File

@@ -41,6 +41,7 @@ func (p *Player) AddPetExp(petinfo *model.PetInfo, addExp uint32) {
petinfo.CalculatePetPane(false)
petinfo.Cure()
p.Info.PetMaxLevel = utils.Max(petinfo.Level, p.Info.PetMaxLevel)
}
// 处理技能学习

View File

@@ -2,7 +2,7 @@ package space
import (
"blazing/cool"
"blazing/logic/service/maps/info"
"blazing/logic/service/space/info"
"sync/atomic"
"time"

View File

@@ -2,8 +2,9 @@ package space
import (
"blazing/logic/service/common"
"blazing/logic/service/maps/info"
maps "blazing/logic/service/maps/info"
"blazing/logic/service/space/info"
"sync/atomic"
"github.com/jinzhu/copier"
@@ -68,7 +69,7 @@ func (s *Space) EnterMap(c common.PlayerI) {
}
}
func (s *Space) GetInfo(c common.PlayerI) []maps.OutInfo {
func (s *Space) GetInfo(c common.PlayerI) []info.OutInfo {
if atomic.LoadUint32(&s.TimeBoss.Flag) == 1 {
defer c.SendPackCmd(2022, &s.TimeBoss)
@@ -80,8 +81,8 @@ func (s *Space) GetInfo(c common.PlayerI) []maps.OutInfo {
}
defer c.SendPackCmd(50004, &info.S2C_50004{Id: uint32(s.Weather)}) //获取天气
ret := make([]maps.OutInfo, 0)
s.UserInfo.Range(func(k uint32, v maps.OutInfo) (stop bool) {
ret := make([]info.OutInfo, 0)
s.UserInfo.Range(func(k uint32, v info.OutInfo) (stop bool) {
ret = append(ret, v)
return len(ret) > 30
})

View File

@@ -0,0 +1,41 @@
package space
import (
"blazing/logic/service/common"
"blazing/modules/blazing/model"
)
type ListMapPlayerInboundInfo struct {
Head common.TomeeHeader `cmd:"2003" struc:"skip"` //切换地图
}
type AttackBossInboundInfo struct {
Head common.TomeeHeader `cmd:"2412" struc:"skip"` //切换地图
}
type LeaveMapInboundInfo struct {
Head common.TomeeHeader `cmd:"2002" struc:"skip"` //切换地图
}
type InInfo struct {
Head common.TomeeHeader `cmd:"2001" struc:"skip"` //切换地图
// 地图类型
MapType uint32
MapId uint32
// Point: 直接给坐标xy
Point model.Pos `fieldDesc:"直接给坐标xy"`
// Reverse2: 暂定 占位字符2
//Reverse2 string `struc:"[2]byte"`
}
type WalkInInfo struct {
Head common.TomeeHeader `cmd:"2101" struc:"skip"` //走路包
// Flag: 0为走1为飞行模式@UInt long
Flag uint32
// Point: 直接给坐标xy
Point model.Pos `fieldDesc:"直接给坐标xy"`
PathLen uint32 `struc:"sizeof=Path" `
Path string
}

View File

@@ -6,8 +6,7 @@ import (
"blazing/cool"
"blazing/logic/service/common"
"blazing/logic/service/maps/info"
maps "blazing/logic/service/maps/info"
"blazing/logic/service/space/info"
csmap "github.com/mhmtszr/concurrent-swiss-map"
"github.com/tnnmigga/enum"
@@ -23,7 +22,7 @@ var WeatherStatus = enum.New[struct {
// Space 针对Player的并发安全map键为uint32类型
type Space struct {
User *csmap.CsMap[uint32, common.PlayerI] // 存储玩家数据的map键为玩家ID
UserInfo *csmap.CsMap[uint32, maps.OutInfo]
UserInfo *csmap.CsMap[uint32, info.OutInfo]
CanRefresh bool //是否能够刷怪
Super uint32
//SuperValue *int32
@@ -53,10 +52,10 @@ func NewSpace() *Space {
// set the total capacity, every shard map has total capacity/shard count capacity. the default value is 0.
// csmap.WithSize[string, int](1000),
),
UserInfo: csmap.New[uint32, maps.OutInfo](
UserInfo: csmap.New[uint32, info.OutInfo](
// set the number of map shards. the default value is 32.
csmap.WithShardCount[uint32, maps.OutInfo](32),
csmap.WithCustomHasher[uint32, maps.OutInfo](func(key uint32) uint64 {
csmap.WithShardCount[uint32, info.OutInfo](32),
csmap.WithCustomHasher[uint32, info.OutInfo](func(key uint32) uint64 {
return uint64(key)
}),

View File

@@ -1,7 +1,7 @@
package space
import (
"blazing/logic/service/maps/info"
"blazing/logic/service/space/info"
"sync/atomic"
"time"

View File

@@ -39,12 +39,7 @@ func (s *InfoService) Reg(nick string, color uint32) {
//设置用户信息
t.Data = model.NewPlayerInfo()
t.Data.Nick = nick
// for i := 0; i < 80; i++ { //超NO芯片填充
// t.Data.NonoChipList[i] = 255
// }
t.Data.UserID = s.userid
t.Data.Color = color
t.Data.RegisterTime = uint32(time.Now().Unix()) //写入注册时间
@@ -76,6 +71,8 @@ func (s *InfoService) Personself() *model.PlayerInfo {
if err != nil {
return nil
}
tt.Data.AllPetNumber = uint32(NewPetService(s.userid).PetCount(0))
if !IsToday(tt.LastResetTime) { //判断是否是今天
//每天login时候检查重置时间然后把电池任务挖矿重置

View File

@@ -25,6 +25,17 @@ func (s *PetService) PetInfo(flag int) []model.PetEX {
return tt
}
func (s *PetService) PetCount(flag int) int {
ret, err := cool.DBM(s.Model).Where("player_id", s.userid).Where("free", flag).Count()
if err != nil {
return 0
}
return ret
}
func (s *PetService) PetInfo_One_exec(cachetime uint32, t func(*model.PetEX)) {

View File

@@ -59,15 +59,14 @@ func IsToday(t1 *gtime.Time) bool {
if t1 == nil {
return false
}
t := t1.Time
// 获取当前时间
now := time.Now()
// 统一转换为 UTC 时区
tUTC := t1.Time.UTC()
// 截断 UTC 时间到当天 00:00:00
nowUTC := time.Now().UTC().Truncate(24 * time.Hour)
tTrunc := tUTC.Truncate(24 * time.Hour)
// 比较年、月、日是否相同
return t.Year() == now.Year() &&
t.Month() == now.Month() &&
t.Day() == now.Day()
return nowUTC.Equal(tTrunc)
}
type TaskService struct {