refactor(blazing): 重构任务系统并优化相关功能
- 重构了任务系统的数据结构和执行逻辑 - 优化了地图加载和怪物刷新机制 - 改进了宠物系统的基础架构 - 调整了玩家信息和背包的处理方式 - 统一了数据访问层的接口和实现
This commit is contained in:
@@ -5,7 +5,13 @@ import (
|
||||
)
|
||||
|
||||
type IModel interface {
|
||||
|
||||
TableName() string
|
||||
GroupName() string
|
||||
}
|
||||
|
||||
type UserModel interface {
|
||||
GetData() string
|
||||
SetData(data string)
|
||||
TableName() string
|
||||
GroupName() string
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package xmlres
|
||||
|
||||
import (
|
||||
"blazing/common/utils"
|
||||
"os"
|
||||
|
||||
"github.com/ECUST-XX/xml"
|
||||
@@ -23,11 +24,13 @@ func getXml[T any](path string) T {
|
||||
}
|
||||
|
||||
var (
|
||||
MapConfig Maps //地图配置
|
||||
ItemsConfig Items //物品配置
|
||||
TalkConfig TalkCount //任务配置
|
||||
Monster MonsterRoot //野怪配置
|
||||
Skill MovesTbl //技能配置
|
||||
MapConfig Maps //地图配置
|
||||
ItemsConfig Items //物品配置
|
||||
TalkConfig TalkCount //任务配置
|
||||
//Monster MonsterRoot //野怪配置
|
||||
MonsterMap map[int]TMapConfig
|
||||
//Skill MovesTbl //技能配置
|
||||
SkillMap map[int]Move
|
||||
)
|
||||
|
||||
func initfile() {
|
||||
@@ -36,8 +39,18 @@ func initfile() {
|
||||
MapConfig = getXml[Maps](path + "210.xml")
|
||||
ItemsConfig = getXml[Items](path + "43.xml")
|
||||
TalkConfig = getXml[TalkCount](path + "talk.xml")
|
||||
Monster = getXml[MonsterRoot](path + "地图配置野怪.xml")
|
||||
Skill = getXml[MovesTbl](path + "227.xml")
|
||||
Monster := getXml[MonsterRoot](path + "地图配置野怪.xml")
|
||||
|
||||
MonsterMap = utils.ToMap(Monster.Maps, func(m TMapConfig) int {
|
||||
return m.ID
|
||||
|
||||
})
|
||||
|
||||
Skill := getXml[MovesTbl](path + "227.xml")
|
||||
SkillMap = utils.ToMap[Move, int](Skill.Moves, func(m Move) int {
|
||||
return m.ID
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
@@ -87,31 +86,3 @@ func ReadHTTPFile(url string) ([]byte, error) {
|
||||
|
||||
return content, nil
|
||||
}
|
||||
func getxml() ([]byte, error) {
|
||||
|
||||
// 读取整个文件内容,返回字节切片和错误
|
||||
content, err := ReadHTTPFile("http://127.0.0.1:8080/assets/227.xml")
|
||||
if err != nil {
|
||||
// 处理错误(文件不存在、权限问题等)
|
||||
log.Fatalf("无法读取文件: %v", err)
|
||||
}
|
||||
return content, nil
|
||||
|
||||
}
|
||||
func getMoves() MovesMap {
|
||||
|
||||
// 解析XML到结构体
|
||||
var maps MovesTbl
|
||||
t1, _ := getxml()
|
||||
xml.Unmarshal(t1, &maps)
|
||||
var mapss MovesMap
|
||||
mapss.Moves = make(map[int]Move, 0)
|
||||
for _, v := range maps.Moves {
|
||||
mapss.Moves[int(v.ID)] = v
|
||||
}
|
||||
|
||||
return mapss
|
||||
}
|
||||
|
||||
// 全局函数配置
|
||||
var MovesConfig = getMoves()
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"blazing/common/data/share"
|
||||
"blazing/common/data/socket"
|
||||
"blazing/logic/service/maps"
|
||||
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/panjf2000/gnet/v2"
|
||||
@@ -49,6 +50,9 @@ func (s *Server) OnClose(c gnet.Conn, _ error) (action gnet.Action) {
|
||||
|
||||
if v.Player != nil {
|
||||
glog.Debug(context.Background(), v.Player.Info.UserID, "断开连接")
|
||||
|
||||
maps.LeaveMap(v.Player)
|
||||
|
||||
v.Player.IsLogin = false
|
||||
socket.Mainplayer.Delete(v.Player.Info.UserID)
|
||||
share.ShareManager.DeleteUserOnline(v.Player.Info.UserID) //设置用户登录服务器
|
||||
|
||||
22
common/utils/tomap.go
Normal file
22
common/utils/tomap.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package utils
|
||||
|
||||
// ToMap converts a slice to a map with the keyFunc determining what the key of a value should be.
|
||||
// Will override any double values.
|
||||
func ToMap[T any, K comparable](slice []T, keyFunc func(T) K) map[K]T {
|
||||
m := make(map[K]T, len(slice))
|
||||
for _, v := range slice {
|
||||
m[keyFunc(v)] = v
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// ToSliceMap converts a slice to a map with the keyFunc determining what the key of a value should be.
|
||||
// Will append to the slice if the key already exists.
|
||||
func ToSliceMap[T any, K comparable](slice []T, keyFunc func(T) K) map[K][]T {
|
||||
m := make(map[K][]T, len(slice))
|
||||
for _, v := range slice {
|
||||
key := keyFunc(v)
|
||||
m[key] = append(m[key], v)
|
||||
}
|
||||
return m
|
||||
}
|
||||
@@ -32,7 +32,10 @@ func (h *Controller) Login(data *login.InInfo, c *socket.Conn) (result *login.Ou
|
||||
glog.Debug(context.Background(), "登录成功,初始地图 人数:", space.GetSpace(t.Info.MapID).Len())
|
||||
|
||||
result = login.NewOutInfo() //设置登录消息
|
||||
|
||||
result.PlayerInfo = *t.Info
|
||||
//result.TaskList = blservice.NewUserService(t.Info.UserID).GenTask()
|
||||
result.PetList = blservice.NewUserService(t.Info.UserID).GetPetList()
|
||||
tt := maps.NewOutInfo()
|
||||
//copier.Copy(t.Info, tt)
|
||||
t1 := handler.NewTomeeHeader(2001, t.Info.UserID)
|
||||
|
||||
@@ -21,14 +21,17 @@ func (h *Controller) MapEnter(data *maps.InInfo, c *socket.Player) (result *maps
|
||||
|
||||
data.Broadcast(c.Info.MapID, *result) //同步广播
|
||||
// 如果是无怪地图,直接返回
|
||||
|
||||
if c.StopChan != nil {
|
||||
close(c.StopChan)
|
||||
c.StopChan = nil
|
||||
}
|
||||
// 创建新的停止通道
|
||||
c.StopChan = make(chan struct{})
|
||||
|
||||
// 启动刷怪协程
|
||||
go func(stopChan chan struct{}, currentMap int) {
|
||||
|
||||
time.After(5 * time.Second)
|
||||
<-time.After(5 * time.Second)
|
||||
// 首次刷新
|
||||
if !c.IsFighting && c.Info.MapID != 0 {
|
||||
data.SpawnMonsters(c, true)
|
||||
|
||||
@@ -4,38 +4,23 @@ import (
|
||||
"blazing/common/data/socket"
|
||||
"blazing/common/socket/errorcode"
|
||||
"blazing/logic/service/pet"
|
||||
"blazing/modules/blazing/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (h *Controller) GetPetInfo(data *pet.InInfo, c *socket.Player) (result *pet.OutInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||
// 获取精灵信息
|
||||
func (h *Controller) GetPetInfo(
|
||||
data *pet.InInfo,
|
||||
c *socket.Player) (result *pet.OutInfo,
|
||||
err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||
|
||||
t := model.PetInfo{
|
||||
ID: 300,
|
||||
Name: [16]byte{'1'},
|
||||
Dv: 1,
|
||||
Attack: 1000,
|
||||
Defence: 1000,
|
||||
SpecialAttack: 1000,
|
||||
CatchTime: uint32(time.Now().Unix()),
|
||||
Speed: 1000,
|
||||
Hp: 1000,
|
||||
MaxHp: 1000,
|
||||
Level: 1,
|
||||
LvExp: 1000,
|
||||
NextLvExp: 1000,
|
||||
Exp: 1000,
|
||||
//SkillList: [4]model.SkillInfo{{ID: 1, Pp: 1}},
|
||||
Nature: 1,
|
||||
Shiny: 1,
|
||||
}
|
||||
t.SkillListLen = 1
|
||||
for i := 0; i < 4; i++ {
|
||||
t.SkillList[i] = model.SkillInfo{ID: 10001, Pp: 10001}
|
||||
}
|
||||
t.EffectInfo = make([]model.PetEffectInfo, 0)
|
||||
t.EffectInfo = append(t.EffectInfo, model.PetEffectInfo{EffectID: 1, ItemID: 1, LeftCount: 1})
|
||||
return &pet.OutInfo{
|
||||
PetInfo: t,
|
||||
}, 0
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
// 精灵背包仓库切换
|
||||
func (h *Controller) PetRelease(
|
||||
data *pet.PetReleaseInboundInfo,
|
||||
c *socket.Player) (
|
||||
result *pet.PetReleaseOutboundInfo,
|
||||
err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
@@ -6,34 +6,22 @@ import (
|
||||
"blazing/logic/service/task"
|
||||
"blazing/modules/blazing/model"
|
||||
"blazing/modules/blazing/service"
|
||||
"time"
|
||||
)
|
||||
|
||||
/**
|
||||
* 接受任务
|
||||
*/
|
||||
func (h Controller) AcceptTask(data *task.AcceptTaskInboundInfo, c *socket.Player) (result *task.AcceptTaskOutboundInfo, err errorcode.ErrorCode) {
|
||||
isdaliy := false
|
||||
//isdaliy := false
|
||||
if data.Head.CMD != 2201 { //判断是每日任务
|
||||
isdaliy = true
|
||||
//isdaliy = true
|
||||
}
|
||||
service.NewUserService(c.Info.UserID).TaskExec(func(ttt map[uint32]model.TaskInfo) bool {
|
||||
ft, ok := ttt[data.TaskId]
|
||||
if ok { //如果找到任务
|
||||
if ft.Status == 0 { //可以接受
|
||||
ft.Status = 1 //接受
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
ttt[data.TaskId] = model.TaskInfo{
|
||||
Status: 1,
|
||||
}
|
||||
|
||||
}
|
||||
if c.Info.TaskList[data.TaskId] == 0 {
|
||||
c.Info.TaskList[data.TaskId] = 1
|
||||
}
|
||||
|
||||
return false
|
||||
}, isdaliy)
|
||||
result = &task.AcceptTaskOutboundInfo{}
|
||||
result.TaskId = data.TaskId
|
||||
return result, 0
|
||||
@@ -47,14 +35,17 @@ func (h Controller) AddTaskBuf(data *task.AddTaskBufInboundInfo, c *socket.Playe
|
||||
if data.Head.CMD != 2204 { //判断是每日任务
|
||||
isdaliy = true
|
||||
}
|
||||
service.NewUserService(c.Info.UserID).TaskExec(func(ttt map[uint32]model.TaskInfo) bool {
|
||||
if conditions, ok := ttt[data.TaskId]; ok {
|
||||
conditions.TaskInfo = data.TaskList
|
||||
ttt[data.TaskId] = conditions
|
||||
return true
|
||||
service.NewUserService(c.Info.UserID).TaskExec(func(ttt []model.TaskInfo) []model.TaskInfo {
|
||||
var ttt2 []model.TaskInfo
|
||||
for _, v := range ttt {
|
||||
|
||||
v.TaskInfo = data.TaskList
|
||||
|
||||
ttt2 = append(ttt2, v)
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
return ttt2
|
||||
}, isdaliy)
|
||||
|
||||
return &task.AddTaskBufOutboundInfo{}, 0
|
||||
@@ -65,25 +56,68 @@ func (h Controller) AddTaskBuf(data *task.AddTaskBufInboundInfo, c *socket.Playe
|
||||
*/
|
||||
func (h Controller) Complete_Task(data *task.CompleteTaskInboundInfo, c *socket.Player) (result *task.CompleteTaskOutboundInfo, err errorcode.ErrorCode) {
|
||||
|
||||
if data.Head.CMD == 2202 { //判断不是每日任务
|
||||
if c.Info.TaskList[data.TaskId] != 1 { //如果任务没有接受或者已经完成Complete_Task
|
||||
|
||||
} else {
|
||||
return result, 0
|
||||
|
||||
}
|
||||
c.Info.TaskList[data.TaskId] = 3
|
||||
result = &task.CompleteTaskOutboundInfo{}
|
||||
result.ItemList = make([]task.ItemInfo, 0)
|
||||
result.TaskId = data.TaskId
|
||||
if data.TaskId == 85 { //新手注册任务
|
||||
|
||||
return &task.CompleteTaskOutboundInfo{}, 0
|
||||
result.ItemList = append(result.ItemList, task.ItemInfo{ItemId: 100027, ItemCount: 1})
|
||||
result.ItemList = append(result.ItemList, task.ItemInfo{ItemId: 100028, ItemCount: 1})
|
||||
result.ItemList = append(result.ItemList, task.ItemInfo{ItemId: 500001, ItemCount: 1})
|
||||
result.ItemList = append(result.ItemList, task.ItemInfo{ItemId: 500502, ItemCount: 1})
|
||||
result.ItemList = append(result.ItemList, task.ItemInfo{ItemId: 500503, ItemCount: 1})
|
||||
|
||||
}
|
||||
if data.TaskId == 86 { //新手注册任务
|
||||
|
||||
result.CaptureTime = uint32(time.Now().Unix())
|
||||
result.PetTypeId = 1
|
||||
|
||||
}
|
||||
if data.TaskId == 87 { //新手注册任务
|
||||
|
||||
result.ItemList = append(result.ItemList, task.ItemInfo{ItemId: 300001, ItemCount: 10})
|
||||
result.ItemList = append(result.ItemList, task.ItemInfo{ItemId: 300011, ItemCount: 5})
|
||||
|
||||
}
|
||||
if data.TaskId == 88 { //新手注册任务
|
||||
|
||||
result.ItemList = append(result.ItemList, task.ItemInfo{ItemId: 1, ItemCount: 1000})
|
||||
|
||||
}
|
||||
return result, 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务状态
|
||||
*/
|
||||
func (h Controller) Get_Task_Buf(data *task.GetTaskBufInboundInfo, c *socket.Player) (result *task.GetTaskBufOutboundInfo, err errorcode.ErrorCode) {
|
||||
// isdaliy := false
|
||||
// if data.Head.CMD != 2203 { //判断是每日任务
|
||||
// isdaliy = true
|
||||
// }
|
||||
isdaliy := false
|
||||
if data.Head.CMD == 2203 { //判断不是每日任务
|
||||
isdaliy = true
|
||||
}
|
||||
|
||||
return &task.GetTaskBufOutboundInfo{}, 0
|
||||
service.NewUserService(c.Info.UserID).TaskExec(func(ttt []model.TaskInfo) []model.TaskInfo {
|
||||
var ttt2 = make([]model.TaskInfo, 500)
|
||||
for _, v := range ttt {
|
||||
if data.TaskId == v.TaskID {
|
||||
result = &task.GetTaskBufOutboundInfo{TaskId: data.TaskId, TaskList: v.TaskInfo}
|
||||
}
|
||||
|
||||
return ttt2
|
||||
|
||||
}
|
||||
|
||||
return ttt2
|
||||
}, isdaliy)
|
||||
|
||||
return result, 0
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,7 @@ func CreateBattleSkillWithInfinity(id int, pp int) *BattleSkillEntity {
|
||||
}
|
||||
|
||||
// 从资源仓库获取技能数据
|
||||
move, ok := xmlres.MovesConfig.Moves[id]
|
||||
move, ok := xmlres.SkillMap[id]
|
||||
if !ok {
|
||||
glog.Error(context.Background(), "技能ID无效", "id", id)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"blazing/modules/blazing/model"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
)
|
||||
@@ -42,32 +41,6 @@ func NewOutInfo() *OutInfo {
|
||||
l := &OutInfo{
|
||||
PlayerInfo: *model.NewPlayerInfo(),
|
||||
}
|
||||
t := model.PetInfo{
|
||||
ID: 300,
|
||||
Name: [16]byte{'1'},
|
||||
Dv: 1,
|
||||
Attack: 1000,
|
||||
Defence: 1000,
|
||||
SpecialAttack: 1000,
|
||||
CatchTime: uint32(time.Now().Unix()),
|
||||
Speed: 1000,
|
||||
Hp: 1000,
|
||||
MaxHp: 1000,
|
||||
Level: 1,
|
||||
LvExp: 1000,
|
||||
NextLvExp: 1000,
|
||||
Exp: 1000,
|
||||
//SkillList: [4]model.SkillInfo{{ID: 1, Pp: 1}},
|
||||
Nature: 1,
|
||||
Shiny: 1,
|
||||
}
|
||||
t.SkillListLen = 1
|
||||
for i := 0; i < 4; i++ {
|
||||
t.SkillList[i] = model.SkillInfo{ID: 10001, Pp: 10001}
|
||||
}
|
||||
t.EffectInfo = make([]model.PetEffectInfo, 0)
|
||||
t.EffectInfo = append(t.EffectInfo, model.PetEffectInfo{EffectID: 1, ItemID: 1, LeftCount: 1})
|
||||
l.PetList = append(l.PetList, t)
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
@@ -83,27 +83,25 @@ func RandomStringFromSlice(s []string) string {
|
||||
func (t *InInfo) genMonster(mapid uint32) *OgreInfo {
|
||||
// 设置怪物信息
|
||||
t1 := OgreInfo{}
|
||||
for _, tc := range xmlres.Monster.Maps {
|
||||
|
||||
if tc.ID == gconv.Int(mapid) && tc.Monsters != nil {
|
||||
|
||||
for i, m := range tc.Monsters.Monsters { //这里是9个
|
||||
id := strings.Split(m.ID, " ")
|
||||
lv := strings.Split(m.Lv, " ")
|
||||
ttt := OgrePetInfo{
|
||||
Id: gconv.Uint32(RandomStringFromSlice(id)),
|
||||
}
|
||||
if ttt.Id != 0 {
|
||||
ttt.Shiny = 0 //待确认是否刷新异色
|
||||
ttt.Lv = gconv.Uint32(RandomStringFromSlice(lv))
|
||||
}
|
||||
t1.Data[i] = ttt
|
||||
mapss, ok := xmlres.MonsterMap[gconv.Int(mapid)]
|
||||
|
||||
if ok && mapss.Monsters != nil {
|
||||
for i, m := range mapss.Monsters.Monsters { //这里是9个
|
||||
id := strings.Split(m.ID, " ")
|
||||
lv := strings.Split(m.Lv, " ")
|
||||
ttt := OgrePetInfo{
|
||||
Id: gconv.Uint32(RandomStringFromSlice(id)),
|
||||
}
|
||||
break
|
||||
if ttt.Id != 0 {
|
||||
ttt.Shiny = 0 //待确认是否刷新异色
|
||||
ttt.Lv = gconv.Uint32(RandomStringFromSlice(lv))
|
||||
}
|
||||
t1.Data[i] = ttt
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
t2 := OgreInfo{}
|
||||
for i := 0; i < 3; i++ {
|
||||
|
||||
@@ -292,3 +290,14 @@ func NewOutInfo() *OutInfo {
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func LeaveMap(c *socket.Player) {
|
||||
t := handler.NewTomeeHeader(2002, c.Info.UserID)
|
||||
|
||||
space.GetSpace(c.Info.MapID).Range(func(playerID uint32, player *socket.Player) bool {
|
||||
|
||||
player.SendPack(t.Pack(&LeaveMapOutboundInfo{UserID: c.Info.UserID}))
|
||||
return true
|
||||
})
|
||||
space.GetSpace(c.Info.MapID).Delete(c.Info.UserID)
|
||||
}
|
||||
|
||||
@@ -14,3 +14,17 @@ type InInfo struct {
|
||||
type OutInfo struct {
|
||||
model.PetInfo
|
||||
}
|
||||
|
||||
// PetReleaseOutboundInfo 宠物释放出站消息
|
||||
type PetReleaseOutboundInfo struct {
|
||||
HomeEnergy uint64 `json:"home_energy" fieldDescription:"暂定0" autoCodec:"true" uint:"true"`
|
||||
FirstPetTime uint64 `json:"first_pet_time" fieldDescription:"精灵生成时间" autoCodec:"true" uint:"true"`
|
||||
PetInfo []model.PetInfo `json:"pet_info" fieldDescription:"精灵信息" autoCodec:"true"`
|
||||
}
|
||||
|
||||
// 放入背包或者加入仓库
|
||||
type PetReleaseInboundInfo struct {
|
||||
Head handler.TomeeHeader `cmd:"2304" struc:"[0]pad"`
|
||||
CatchTime uint64 `json:"catch_time" fieldDescription:"精灵生成时间" autoCodec:"true" uint:"true"`
|
||||
Flag uint64 `json:"flag" fieldDescription:"0为放入仓库,1为放入背包" autoCodec:"true" uint:"true"`
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ import "blazing/common/socket/handler"
|
||||
|
||||
type CompleteTaskInboundInfo struct {
|
||||
Head handler.TomeeHeader `cmd:"2202|2233" struc:"[0]pad"`
|
||||
TaskId uint32 `json:"taskId" description:"任务ID"` // 任务ID,对应Java的@UInt long
|
||||
OutState uint32 `json:"outState" description:"当前状态, 1为完成任务"` // 当前状态,1表示完成任务,对应Java的@UInt long
|
||||
TaskId uint32 `json:"taskId" description:"任务ID"` // 任务ID,对应Java的@UInt long
|
||||
OutState uint32 `json:"outState" 分支"` // 当前状态,1表示完成任务,对应Java的@UInt long
|
||||
}
|
||||
type CompleteTaskOutboundInfo struct {
|
||||
TaskId uint32 `json:"taskId" description:"任务ID"` // 任务ID,对应Java的@UInt long
|
||||
@@ -18,6 +18,6 @@ type CompleteTaskOutboundInfo struct {
|
||||
// ItemInfo 对应Java的ItemInfo类
|
||||
// 用于表示发放物品的信息
|
||||
type ItemInfo struct {
|
||||
ItemId uint64 `json:"itemId" description:"发放物品ID"` // 发放物品ID,对应Java的@UInt long
|
||||
ItemCount uint64 `json:"itemCount" description:"发放物品的数量"` // 发放物品的数量,对应Java的@UInt long
|
||||
ItemId uint32 `json:"itemId" description:"发放物品ID"` // 发放物品ID,对应Java的@UInt long
|
||||
ItemCount uint32 `json:"itemCount" description:"发放物品的数量"` // 发放物品的数量,对应Java的@UInt long
|
||||
}
|
||||
|
||||
@@ -7,11 +7,16 @@ import (
|
||||
const TableNamePlayerBagItem = "player_bag_item"
|
||||
|
||||
// PlayerBagItem mapped from table <player_bag_item>
|
||||
type PlayerBagItem struct {
|
||||
type PlayerBag struct {
|
||||
*cool.Model
|
||||
PlayerID uint64 `gorm:"not null;index:idx_player_bag_item_by_player_id;comment:'所属玩家ID'" json:"player_id"`
|
||||
ItemID int32 `gorm:"not null;comment:'道具唯一编号'" json:"item_id"`
|
||||
Quantity int32 `gorm:"not null;default:0;comment:'拥有数量(uint16)'" json:"quantity"`
|
||||
Data string `gorm:"type:text;not null;comment:'全部数据'" json:"data"`
|
||||
}
|
||||
type PlayerBagItem struct {
|
||||
ID int32 `gorm:"not null;comment:'道具唯一编号'" json:"item_id"`
|
||||
Count int32 `gorm:"not null;default:0;comment:'拥有数量 '" json:"count"`
|
||||
Max int32 `gorm:"not null;default:0;comment:'最大数量 '" json:"max"`
|
||||
Total int32 `gorm:"not null;default:0;comment:'使用次数'" json:"total"`
|
||||
}
|
||||
|
||||
// TableName PlayerBagItem's table name
|
||||
@@ -25,13 +30,13 @@ func (*PlayerBagItem) GroupName() string {
|
||||
}
|
||||
|
||||
// NewPlayerBagItem create a new PlayerBagItem
|
||||
func NewPlayerBagItem() *PlayerBagItem {
|
||||
return &PlayerBagItem{
|
||||
func NewPlayerBag() *PlayerBag {
|
||||
return &PlayerBag{
|
||||
Model: cool.NewModel(),
|
||||
}
|
||||
}
|
||||
|
||||
// init 创建表
|
||||
func init() {
|
||||
cool.CreateTable(&PlayerBagItem{})
|
||||
cool.CreateTable(&PlayerBag{})
|
||||
}
|
||||
|
||||
@@ -12,15 +12,14 @@ const (
|
||||
// MonsterRefresh 怪物刷新规则模型(对应XML中的<monster>标签)
|
||||
type MonsterRefresh struct {
|
||||
*cool.Model
|
||||
MapID int32 `gorm:"not null;index:idx_refresh_by_map_id;comment:'所属地图ID'" json:"map_id"`
|
||||
MonsterID int32 `gorm:"not null;comment:'怪物唯一编号'" json:"monster_id"`
|
||||
//Desc string `gorm:"type:varchar(100);not null;comment:'怪物名称(如皮皮)'" json:"desc"`
|
||||
MinLevel int32 `gorm:"not null;comment:'最低等级'" json:"min_level"`
|
||||
MaxLevel int32 `gorm:"not null;comment:'最高等级'" json:"max_level"`
|
||||
Capturable bool `gorm:"not null;comment:'是否可捕捉'" json:"capturable"`
|
||||
|
||||
Rate float64 `gorm:"not null;comment:'刷新概率(百分比)'" json:"rate"` //未设置概率的就是默认刷新
|
||||
Value string `gorm:"type:text;not null;comment:'限制值(如19:00-24:00)'" json:"value"` //这里是js文本,暂定传入时间
|
||||
MonsterID int32 `gorm:"not null;comment:'对应原怪物唯一编号'" json:"monster_id"`
|
||||
ShinyID int32 `gorm:"not null;uniqueIndex;comment:'异色唯一标识ID'" json:"shiny_id"`
|
||||
RefreshScript string `gorm:"type:text;not null;comment:'刷新脚本(JS格式,可包含时间/天气/地形等条件)'" json:"refresh_script"`
|
||||
|
||||
ShinyFilter string `gorm:"type:text;not null;comment:'异色滤镜效果(文本描述或配置参数)'" json:"shiny_filter"`
|
||||
ShinyEffect string `gorm:"type:text;not null;comment:'异色光效效果(文本描述或配置参数)'" json:"shiny_effect"`
|
||||
// TODO: 增加ruffle的显示异色效果
|
||||
}
|
||||
|
||||
// TableName MonsterRefresh's table name
|
||||
|
||||
@@ -10,11 +10,13 @@ const TableNamePet = "pet"
|
||||
type Pet struct {
|
||||
*cool.Model
|
||||
PlayerID uint32 `gorm:"not null;index:idx_pet_by_player_id;comment:'所属玩家ID'" json:"player_id"`
|
||||
InBag bool `gorm:"not null;comment:'是否在背包中'" json:"in_bag"` //"0为放入仓库,1为放入背包
|
||||
Data string `gorm:"type:text;not null;comment:'精灵全部数据'" json:"data"`
|
||||
}
|
||||
|
||||
// PetInfo 精灵信息结构(合并后的优化版本)
|
||||
type PetInfo struct {
|
||||
Owner uint32 `struc:"skip"` //仅作为存储
|
||||
// 精灵编号(@UInt long → uint32)
|
||||
ID uint32 `fieldDesc:"精灵编号" `
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package model
|
||||
|
||||
import (
|
||||
"blazing/cool"
|
||||
"time"
|
||||
|
||||
"github.com/creasty/defaults"
|
||||
)
|
||||
@@ -40,37 +41,14 @@ func NewPlayerInfo() *PlayerInfo {
|
||||
panic(err) // 方便发现 default 设置错误
|
||||
}
|
||||
|
||||
// 填充需要重复值的数组
|
||||
fillBytes(&l.DailyResArr, 3)
|
||||
fillBytes(&l.Reserved1, 3)
|
||||
fillBytes(&l.TaskList, 3)
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// 工具函数:给数组/切片批量赋同一个 byte 值
|
||||
func fillBytes(arr any, val byte) {
|
||||
switch a := arr.(type) {
|
||||
case *[50]byte:
|
||||
for i := range a {
|
||||
a[i] = val
|
||||
}
|
||||
case *[27]byte:
|
||||
for i := range a {
|
||||
a[i] = val
|
||||
}
|
||||
case *[500]byte:
|
||||
for i := range a {
|
||||
a[i] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type PlayerInfo struct {
|
||||
GoldBean int32 `struc:"skip" json:"nieo_gold_bean"` // 金豆(特殊货币)
|
||||
|
||||
ExpPool int64 `struc:"skip" json:"exp_pool"` // 累计经验池
|
||||
|
||||
ExpPool int64 `struc:"skip" json:"exp_pool"` // 累计经验池
|
||||
LastResetTime time.Time `struc:"skip" json:"last_reset_time"` // 重置时间,比如电池和每日任务
|
||||
// OutInfo 字段
|
||||
UserID uint32 `struc:"uint32" json:"user_id"` // 米米号 通过sid拿到
|
||||
RegisterTime uint32 `struc:"uint32" json:"register_time"` // 注册时间(秒时间戳)
|
||||
@@ -136,7 +114,7 @@ type PlayerInfo struct {
|
||||
Reserved byte `struc:"byte" json:"reserved"` // 1字节无内容
|
||||
Badge uint32 `struc:"uint32" default:"0" json:"badge"` // 默认0
|
||||
Reserved1 [27]byte `struc:"[27]byte" default:"3" json:"reserved1"` // 27字节默认3
|
||||
TaskList [500]byte `struc:"[500]byte" default:"3" json:"task_list"` // 任务状态数组500字节,默认3
|
||||
TaskList [500]byte `struc:"[500]byte" default:"0" json:"task_list"` // 任务状态数组500字节,默认3
|
||||
PetListCount uint32 `struc:"sizeof=PetList" json:"pet_list_count"` // 精灵列表长度
|
||||
PetList []PetInfo ` json:"pet_list"` // 精灵背包内信息
|
||||
ClothesCount uint32 `struc:"sizeof=Clothes" json:"clothes_count"` // 穿戴装备数量
|
||||
|
||||
@@ -2,9 +2,9 @@ package model
|
||||
|
||||
import (
|
||||
"blazing/cool"
|
||||
"time"
|
||||
)
|
||||
|
||||
// todo 还需要做一个记录任务奖励的表
|
||||
const TableNameTask = "task"
|
||||
|
||||
// Task mapped from table <task>
|
||||
@@ -18,17 +18,17 @@ type Task struct {
|
||||
type TaskInfo struct {
|
||||
// TaskInfo 任务步骤信息,对应Java的@ArraySerialize(FIXED_LENGTH=20)注解
|
||||
// struc:"[20]byte" 确保二进制序列化时固定20字节长度,json标签指定JSON字段名
|
||||
TaskType uint32 `json:"task_type"` //区分是每日任务还是常规任务,常规为0,每日为1
|
||||
TaskInfo []uint32 `struc:"[20]byte" json:"task_info"`
|
||||
LastResetTime time.Time `gorm:"not null;comment:'上次重置时间(UTC)'" json:"last_reset_time"` //这里是每天重置
|
||||
TaskID uint32 `json:"task_id"` //区分是每日任务还是常规任务,常规为0,每日为1
|
||||
TaskInfo []uint32 `struc:"[20]byte" json:"task_info"`
|
||||
//LastResetTime time.Time `gorm:"not null;comment:'上次重置时间(UTC)'" json:"last_reset_time"` //这里是每天重置
|
||||
// Status 任务整体状态:0-未接受,1-已接受,2-已完成未领取,3-已完成已领取
|
||||
// json标签指定JSON字段名,与业务状态说明保持一致
|
||||
Status byte `json:"status"`
|
||||
//Status byte `json:"status"`
|
||||
}
|
||||
|
||||
// TableName PlayerInfo's table name
|
||||
func (*Task) TableName() string {
|
||||
return TableNamePlayerInfo
|
||||
return TableNameTask
|
||||
}
|
||||
|
||||
// GroupName PlayerInfo's table group
|
||||
@@ -36,6 +36,13 @@ func (*Task) GroupName() string {
|
||||
return "default"
|
||||
}
|
||||
|
||||
func (t *Task) GetData() string {
|
||||
return t.Data
|
||||
}
|
||||
func (t *Task) SetData(t1 string) {
|
||||
t.Data = t1
|
||||
}
|
||||
|
||||
// NewPlayerInfo create a new PlayerInfo
|
||||
func NewTask() *Task {
|
||||
return &Task{
|
||||
|
||||
19
modules/blazing/service/pet.go
Normal file
19
modules/blazing/service/pet.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"blazing/cool"
|
||||
"blazing/modules/blazing/model"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// 获取精灵信息
|
||||
func (s *UserService) GetPetList() (ret []model.PetInfo) {
|
||||
|
||||
m := cool.DBM(s.pet.Model).Where("player_id", s.userid)
|
||||
var tt model.Pet
|
||||
m.Scan(&tt)
|
||||
json.Unmarshal([]byte(tt.Data), &ret)
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func (s *UserService) Reg(nick string, color uint32) {
|
||||
t1.Nick = nick
|
||||
|
||||
t1.Color = color
|
||||
t1.RegisterTime = uint32(time.Now().Unix())//写入注册时间
|
||||
t1.RegisterTime = uint32(time.Now().Unix()) //写入注册时间
|
||||
t22, err := json.Marshal(t1)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -50,7 +50,7 @@ func (s *UserService) Reg(nick string, color uint32) {
|
||||
glog.Error(context.Background(), err)
|
||||
return
|
||||
}
|
||||
|
||||
go s.InitTask()
|
||||
}
|
||||
|
||||
func (s *UserService) Person() (ret *model.PlayerInfo) {
|
||||
@@ -72,7 +72,10 @@ func (s *UserService) Save(data *model.PlayerInfo) {
|
||||
|
||||
temp, _ := json.Marshal(data)
|
||||
tt.Data = string(temp)
|
||||
m.Save(tt)
|
||||
_, err := m.Update(tt)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
|
||||
@@ -4,54 +4,81 @@ import (
|
||||
"blazing/cool"
|
||||
"blazing/modules/blazing/model"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Exec[T, F any](userid uint32, s *cool.Service, processFunc func(F) bool) bool {
|
||||
func Exec[T cool.UserModel, F any](userid uint32, s *cool.Service, processFunc func(F) F) bool {
|
||||
//todo待测试
|
||||
var player T
|
||||
// 方法2:使用反射获取
|
||||
// 获取反射值对象
|
||||
val := reflect.ValueOf(player)
|
||||
var dataField reflect.Value
|
||||
// 检查是否为结构体
|
||||
if val.Kind() == reflect.Struct {
|
||||
// 通过字段名获取Data字段
|
||||
dataField = val.FieldByName("Data")
|
||||
|
||||
}
|
||||
|
||||
m1 := cool.DBM(s.Model).Where("player_id", userid)
|
||||
m1.Scan(&player)
|
||||
var tt F
|
||||
json.Unmarshal([]byte(dataField.Interface().(string)), &tt)
|
||||
processFunc(tt)
|
||||
tmep, _ := json.Marshal(tt)
|
||||
dataField.SetString(string(tmep))
|
||||
// 方法2:使用反射获取
|
||||
// 获取反射值对象
|
||||
|
||||
ttt := player
|
||||
|
||||
//fmt.Println(dataField.Interface().(string))
|
||||
var tt F
|
||||
err := json.Unmarshal([]byte(ttt.GetData()), &tt)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tt1 := processFunc(tt)
|
||||
tmep, err := json.Marshal(tt1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ttt.SetData(string(tmep))
|
||||
m1.Save(player)
|
||||
return false
|
||||
}
|
||||
func (s *UserService) TaskExec(t func(map[uint32]model.TaskInfo) bool, isdaliy bool) (ret bool) {
|
||||
|
||||
if isdaliy {
|
||||
Exec[model.Task](s.userid, s.task, func(tt map[uint32]model.TaskInfo) bool {
|
||||
func (s *UserService) InitTask() {
|
||||
|
||||
//先重置每日
|
||||
for _, v := range tt {
|
||||
if v.TaskType == 1 && !IsToday(v.LastResetTime) {
|
||||
tt := model.NewTask()
|
||||
tt.PlayerID = uint64(s.userid)
|
||||
|
||||
v.Status = 0 //重置+自动接受每日任务
|
||||
v.LastResetTime = time.Now().UTC()
|
||||
}
|
||||
var ggg []model.TaskInfo
|
||||
|
||||
}
|
||||
|
||||
return true
|
||||
for i := 0; i < 500; i++ {
|
||||
ggg = append(ggg, model.TaskInfo{
|
||||
TaskID: (uint32(i)),
|
||||
TaskInfo: make([]uint32, 0),
|
||||
})
|
||||
|
||||
}
|
||||
return Exec[model.Task](s.userid, s.task, t)
|
||||
ffgg, _ := json.Marshal(ggg)
|
||||
tt.Data = string(ffgg)
|
||||
_, err := cool.DBM(s.task.Model).Data(tt).FieldsEx("id").Insert()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
//panic(err)
|
||||
|
||||
}
|
||||
func (s *UserService) TaskExec(t func([]model.TaskInfo) []model.TaskInfo, isdaliy bool) (ret bool) {
|
||||
|
||||
//待实现检测是否为每日任务
|
||||
// if isdaliy {
|
||||
// Exec[*model.Task](s.userid, s.task, func(tt []model.TaskInfo) []model.TaskInfo {
|
||||
// var ttt = make([]model.TaskInfo, 500)
|
||||
// //先重置每日
|
||||
// for k, v := range tt {
|
||||
|
||||
// if k > 400 && !IsToday(v.LastResetTime) { //判断是每日任务
|
||||
|
||||
// v.Status = 0 //重置+自动接受每日任务
|
||||
// v.LastResetTime = time.Now()
|
||||
// }
|
||||
// ttt = append(ttt, v)
|
||||
// }
|
||||
|
||||
// return ttt
|
||||
// })
|
||||
// }
|
||||
return Exec[*model.Task](s.userid, s.task, t)
|
||||
// m := cool.DBM(s.task.Model).Where("player_id", s.userid)
|
||||
// var tt model.Task
|
||||
// m.Scan(&tt)
|
||||
@@ -102,6 +129,23 @@ func IsToday(t time.Time) bool {
|
||||
// return conditions.Status == 3
|
||||
// }
|
||||
|
||||
// return false
|
||||
// return false
|
||||
// })
|
||||
// }
|
||||
// func (s *UserService) GenTask() [500]byte {
|
||||
// ret := [500]byte{}
|
||||
// Exec[*model.Task](s.userid, s.task, func(tt []model.TaskInfo) []model.TaskInfo {
|
||||
|
||||
// //先重置每日
|
||||
// for _, v := range tt {
|
||||
|
||||
// ret[v.TaskID] = v.Status
|
||||
|
||||
// }
|
||||
|
||||
// return tt
|
||||
// })
|
||||
|
||||
// return ret
|
||||
|
||||
// }
|
||||
|
||||
@@ -10,6 +10,7 @@ type UserService struct {
|
||||
|
||||
task *cool.Service //任务
|
||||
reg *cool.Service //注册
|
||||
pet *cool.Service //精灵
|
||||
}
|
||||
|
||||
func NewUserService(id uint32) *UserService {
|
||||
@@ -21,6 +22,7 @@ func NewUserService(id uint32) *UserService {
|
||||
reg: &cool.Service{
|
||||
Model: model.NewPlayer(),
|
||||
},
|
||||
pet: &cool.Service{Model: model.NewPet()},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user