feat(xml): 更新任务配置结构以支持新能量节点解析

将原先的 TalkCount 和 TalkEntry 结构替换为 TalkRoot 和 Energy,
以适配新的 XML 配置格式。同时更新了相关引用代码以确保类型一致性。

refactor(item): 优化物品添加方法支持可变参数传入

调整 ItemAdd 方法签名,从接收数组改为接收可变参数,
提升调用灵活性,并同步修改控制器中对物品添加逻辑的处理方式。

feat(login): 修复每日重置逻辑并引入 gtime 时间管理

修正登录时每日任务重置区间错误(400~100 改为 400~500),
并改用 gtime.Now().Time 提供更准确的时间戳记录与比较,
同时增强挖矿次数等
This commit is contained in:
2025-10-23 01:02:19 +08:00
parent 83fb06a229
commit 9739598df2
13 changed files with 228 additions and 42 deletions

View File

@@ -38,7 +38,7 @@ var (
MapConfig Maps //地图配置
ItemsConfig Items //物品配置
EffectArgsConfig EffectArg //arg参数
TalkConfig TalkCount //任务配置
TalkConfig TalkRoot //任务配置
//Monster MonsterRoot //野怪配置
MonsterMap map[int]TMapConfig
//Skill MovesTbl //技能配置
@@ -67,7 +67,7 @@ func initfile() {
})
TalkConfig = getXml[TalkCount](path + "talk.xml")
TalkConfig = getXml[TalkRoot](path + "talk.xml")
Monster := getXml[MonsterRoot](path + "地图配置野怪.xml")

View File

@@ -4,20 +4,21 @@ import (
"github.com/ECUST-XX/xml" // 注意需确保该xml库与示例中使用的一致
)
// TalkCount 根节点对应<talk_count>标签
// 注意xml.Name需指定命名空间与XML中的xmlns保持一致
type TalkCount struct {
XMLName xml.Name `xml:"nieo.seer.org.talk-count talk_count"`
Entries []TalkEntry `xml:"entry"` // 包含所有entry节点
// 定义XML根节点对应的结构体
// 根节点<root>包含多个<energy>子节点,用切片接收
type TalkRoot struct {
XMLName xml.Name `xml:"root"` // 指定根节点名称为root
Energies []Energy `xml:"energy"` // 子节点<energy>映射为切片,标签对应节点
}
// Entry 单个条目配置,对应<entry>标签
type TalkEntry struct {
ID int `xml:"id,attr"` // 条目ID
ItemID int `xml:"item_id,attr"` // 物品ID
ItemMinCount int `xml:"item_min_count,attr"` // 物品最小数量
ItemMaxCount int `xml:"item_max_count,attr"` // 物品最大数量
Desc string `xml:"desc,attr"` // 描述信息
Count int `xml:"count,attr"` // 计数
Policy string `xml:"policy,attr,omitempty"` // 策略可选如week
// 定义<energy>节点对应的结构体
// 每个字段对应<energy>的属性,用`xml:"属性名,attr"`标签标识
type Energy struct {
Type uint64 `xml:"type,attr"` // 类别ID服务器规定属性type
MapID uint64 `xml:"mapID,attr"` // 矿产所在地图ID属性mapID
Name string `xml:"name,attr"` // 矿产名字属性name
CollectType string `xml:"collectType,attr"` // 操作类型(挖掘/采集/采摘属性collectType
CollectCnt uint64 `xml:"collectCnt,attr"` // 每天采集次数属性collectCnt
Unit string `xml:"unit,attr"` // 单位(块/罐/个属性unit
Dir uint64 `xml:"dir,attr"` // 人模朝向方向属性dir
}

View File

@@ -1,10 +1,15 @@
package controller
import (
"blazing/common/data/xmlres"
"blazing/common/socket/errorcode"
"math/rand"
"time"
"blazing/logic/service/common"
"blazing/logic/service/item"
"blazing/logic/service/player"
"blazing/logic/service/space"
"blazing/modules/blazing/model"
)
@@ -38,3 +43,95 @@ func (h Controller) PlayerExp(data *item.ExpTotalRemainInboundInfo, c *player.Pl
TotalExp: uint32(c.Info.ExpPool),
}, 0
}
func (h Controller) BuyItem(data *item.BuyInboundInfo, c *player.Player) (result *item.BuyOutboundInfo, err errorcode.ErrorCode) {
tt, ok := xmlres.ItemsMAP[int(data.ItemId)]
if ok {
c.Info.Coins -= data.Count * uint32(tt.Price)
c.ItemAdd(model.SingleItemInfo{ItemId: data.ItemId, ItemCnt: data.Count})
return &item.BuyOutboundInfo{
ItemId: data.ItemId,
Level: 1,
Count: data.Count,
Coins: c.Info.Coins,
}, 0
}
return &item.BuyOutboundInfo{
Coins: c.Info.Coins,
}, 0
}
func (h Controller) ChangePlayerCloth(data *item.ChangePlayerClothInboundInfo, c *player.Player) (result *item.ChangePlayerClothOutboundInfo, err errorcode.ErrorCode) {
result = &item.ChangePlayerClothOutboundInfo{
UserID: c.Info.UserID,
ClothList: make([]model.PeopleItemInfo, 0),
}
for _, v := range data.ClothList {
result.ClothList = append(result.ClothList, model.PeopleItemInfo{ID: v, Level: 1})
}
c.Info.Clothes = result.ClothList
defer space.GetSpace(c.Info.MapID).User.IterCb(func(playerID uint32, player common.PlayerI) {
// fmt.Println("ChangePlayerCloth", playerID, data.Head.Pack(result))
player.SendPack(data.Head.Pack(result))
})
return nil, -1
}
func (h Controller) Talk(data *item.TalkCountInboundInfo, c *player.Player) (result *item.TalkCountOutboundInfo, err errorcode.ErrorCode) {
result = &item.TalkCountOutboundInfo{}
c.Service.Talk(func(t map[uint32]uint32) bool {
tt, ok := t[data.ID]
if ok {
result.GiftCount = tt
}
return false
})
return result, 0
}
var talkcacche = make(map[string]uint32)
func (h Controller) TalkCate(data *item.TalkCateInboundInfo, c *player.Player) (result *item.DayTalkInfo, err errorcode.ErrorCode) {
result = &item.DayTalkInfo{}
result.OutList = make([]item.CateInfo, 0)
for _, te := range xmlres.TalkConfig.Energies {
if te.MapID == uint64(c.Info.MapID) && te.Type == uint64(data.ID) { //
c.Service.Talk(func(t map[uint32]uint32) bool {
_, ok := t[data.ID]
if ok {
t[data.ID] += 1
}
return true
})
_, ok := talkcacche[te.Name]
if !ok {
for _, v := range xmlres.ItemsMAP {
if v.Name == te.Name {
talkcacche[te.Name] = uint32(v.ID)
}
}
}
rand.Seed(time.Now().UnixNano()) // UnixNano 精度更高,避免短时间内种子重复
// 2. 生成 1-10 的随机数rand.Intn(10) → 0-9+1 后范围变为 1-10
randomNum := rand.Intn(10) + 1
result.OutList = append(result.OutList, item.CateInfo{ID: uint32(talkcacche[te.Name]), Count: uint32(randomNum)})
c.ItemAdd(model.SingleItemInfo{ItemId: uint32(talkcacche[te.Name]), ItemCnt: uint32(randomNum)})
break
}
}
return result, 0
}

View File

@@ -20,6 +20,7 @@ import (
"time"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/gtime"
"github.com/jinzhu/copier"
"github.com/panjf2000/gnet/v2"
)
@@ -54,23 +55,26 @@ func (h *Controller) Login(data *user.MAIN_LOGIN_IN, c gnet.Conn) (result *user.
t.Info.UserID = data.Head.UserID
t.Onlinetime = uint32(time.Now().Unix()) //保存时间戳
t.Changemap = true
cool.Loger.Info(context.Background(), "用户上次重置日期", t.Info.LastResetTime.String())
if !IsToday(t.Info.LastResetTime) { //判断是否是今天
t.Info.LastResetTime = time.Now()
t.Info.LastResetTime = gtime.Now().Time
//每天login时候检查重置时间然后把电池任务挖矿重置
//挖矿需要单独存,因为防止多开挖矿
t.Info.TimeToday = 0 //重置电池
for i := 400; i < 100; i++ { //每日任务区段
for i := 400; i < 500; i++ { //每日任务区段
if xmlres.TaskMap[i].Type == 1 { //日常任务
t.Info.TaskList[i-1] = 0 //重置每日任务
t.Service.Task(uint32(i), func(t *model.TaskEX) bool {
t.Data = []uint32{}
tttL, ok := xmlres.TaskMap[i]
if ok {
if tttL.Type == 1 { //日常任务
t.Info.TaskList[i-1] = 0 //重置每日任务
t.Service.Task(uint32(i), func(t *model.TaskEX) bool {
t.Data = []uint32{}
return true
return true
})
})
}
}
}
@@ -78,8 +82,8 @@ func (h *Controller) Login(data *user.MAIN_LOGIN_IN, c gnet.Conn) (result *user.
t.Info.DailyResArr[i] = 0 //重置每日任务
}
t.Service.Talk(func(m *map[uint32]uint32) bool { //挖矿
m = &map[uint32]uint32{}
t.Service.Talk(func(m map[uint32]uint32) bool { //挖矿
m = map[uint32]uint32{}
return true
})

View File

@@ -542,7 +542,7 @@ func (h Controller) Complete_Task(data *task.CompleteTaskInboundInfo, c *player.
for _, v := range result.ItemList {
ttt = append(ttt, model.SingleItemInfo{ItemId: v.ItemId, ItemCnt: v.ItemCount})
}
c.ItemAdd(ttt)
c.ItemAdd(ttt...)
return result, 0
}

View File

@@ -50,3 +50,18 @@ func (h Controller) Aimat(data *user.AimatInboundInfo, c *player.Player) (result
return ret, -1
}
func (h Controller) Chat(data *user.ChatInboundInfo, c *player.Player) (result *user.ChatOutboundInfo, err errorcode.ErrorCode) {
result = &user.ChatOutboundInfo{
Message: data.Message,
SenderNickname: c.Info.Nick,
SenderId: c.Info.UserID,
}
defer space.GetSpace(c.Info.MapID).User.IterCb(func(playerID uint32, v common.PlayerI) {
v.SendPack(data.Head.Pack(result))
})
return nil, -1
}

View File

@@ -1,11 +0,0 @@
package chat
import "blazing/logic/service/player"
type ChatInboundInfo struct {
Head player.TomeeHeader `cmd:"2102" struc:"[0]pad"`
Reserve uint32 `json:"reserve" fieldDescription:"填充 默认值为0" uint:"true"` // @UInt long reserve无符号长整数
Message string `json:"message" fieldDescription:"消息内容, 结束符为utf-8的数字0"` // 消息内容包含utf-8空字符('\x00')作为结束符
}

21
logic/service/item/buy.go Normal file
View File

@@ -0,0 +1,21 @@
package item
import "blazing/logic/service/player"
type BuyInboundInfo struct {
Head player.TomeeHeader `cmd:"2601" struc:"[0]pad"`
//物品ID
ItemId uint32
//物品数量
Count uint32
}
type BuyOutboundInfo struct {
//剩余的数量
Coins uint32
//购买的物品ID
ItemId uint32
//购买数量
Count uint32
//购买的物品等级
Level uint32
}

View File

@@ -0,0 +1,17 @@
package item
import (
"blazing/logic/service/player"
"blazing/modules/blazing/model"
)
type ChangePlayerClothOutboundInfo struct {
UserID uint32 `description:"玩家id" codec:"uint"`
ClothesLen uint32 `struc:"sizeof=ClothList" fieldDesc:"穿戴装备的信息" json:"clothes_len"`
ClothList []model.PeopleItemInfo `description:"玩家装备列表" codec:"list"` // List<PeopleItemInfo> -> 指针切片
}
type ChangePlayerClothInboundInfo struct {
Head player.TomeeHeader `cmd:"2604" struc:"[0]pad"`
ClothesLen uint32 `struc:"sizeof=ClothList" fieldDesc:"穿戴装备的信息" json:"clothes_len"`
ClothList []uint32 `description:"玩家装备列表" codec:"list"`
}

View File

@@ -0,0 +1,25 @@
package item
import "blazing/logic/service/player"
type TalkCountInboundInfo struct {
Head player.TomeeHeader `cmd:"2701" struc:"[0]pad"`
ID uint32 `description:"奖品的Type, 即ID" codec:"uint"` // @UInt long -> uint64字段描述对应@FieldDescription
}
type TalkCountOutboundInfo struct {
GiftCount uint32 `description:"已领取奖励的次数" codec:"uint"` // @UInt long -> uint64字段描述对应@FieldDescription
}
type TalkCateInboundInfo struct {
Head player.TomeeHeader `cmd:"2702" struc:"[0]pad"`
ID uint32 `description:"奖品的Type, 即ID" codec:"uint"` // @UInt long -> uint64字段描述对应@FieldDescription
}
type DayTalkInfo struct {
CateList uint32 `description:"要序列list数量字段 只序列数量 结构体数据给null"` // 对应Java的cateList
OutListLen uint32 `struc:"sizeof=OutList"`
OutList []CateInfo `description:"实际发放奖励使用的是outlist"` // 对应Java的outList
}
type CateInfo struct {
// 示例字段,需替换为实际定义
ID uint32
Count uint32
}

View File

@@ -212,7 +212,7 @@ func replaceOneNumber(original [3]int) ([3]int, int, int) {
}
// 添加物品
func (p *Player) ItemAdd(t []model.SingleItemInfo) {
func (p *Player) ItemAdd(t ...model.SingleItemInfo) {
var ttt []model.SingleItemInfo
for _, v := range t {

View File

@@ -0,0 +1,17 @@
package user
import "blazing/logic/service/player"
type ChatInboundInfo struct {
Head player.TomeeHeader `cmd:"2102" struc:"[0]pad"`
Reserve uint32 `json:"reserve" fieldDescription:"填充 默认值为0" uint:"true"` // @UInt long reserve无符号长整数
MessageLen uint32 `struc:"sizeof=Message"`
Message string `json:"message" fieldDescription:"消息内容, 结束符为utf-8的数字0"` // 消息内容包含utf-8空字符('\x00')作为结束符
}
type ChatOutboundInfo struct {
SenderId uint32 `description:"发送人的米米号" codec:"uint"` // @UInt long -> uint64
SenderNickname string `struc:"[16]byte" default:"seer" json:"nick"` // 固定16字节的字符串对应@ArraySerialize注解
ToId uint32 `description:"可能是私聊用的 公屏发送时为0" codec:"uint"` // @UInt long -> uint64
MessageLen uint32 `struc:"sizeof=Message"`
Message string `description:"这里的内容没有结束符" codec:"string"` // String -> string
}

View File

@@ -6,14 +6,14 @@ import (
// TalkCheck 获取玩家当前的Talk数据
// todo 待实现xml解析判断是否溢出
func (s *UserService) Talk(t func(*map[uint32]uint32) bool) {
func (s *UserService) Talk(t func(map[uint32]uint32) bool) {
m1 := s.Model(s.talk.Model)
var talks model.TalkEX
m1.Scan(&talks)
ok := t(&talks.Data)
ok := t(talks.Data)
if ok {
m1.Update(talks)
}