refactor(socket): 重构 ClientData 结构体并优化相关逻辑
- 简化 ClientData 结构体,移除不必要的方法 - 优化 Player 结构体,调整 Conn 类型 - 更新 wscodec.go 中的 Conn 结构体 - 删除未使用的 XML 相关文件和代码 - 调整 ServerEvent 和 controller 中的相关逻辑
This commit is contained in:
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -13,7 +13,7 @@
|
||||
"mode": "auto",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"program": "${workspaceFolder}/login",
|
||||
"console": "integratedTerminal"
|
||||
|
||||
|
||||
},
|
||||
{
|
||||
@@ -24,7 +24,7 @@
|
||||
"cwd": "${workspaceFolder}",
|
||||
"args": ["-port=1"],
|
||||
"program": "${workspaceFolder}/logic",
|
||||
"console": "integratedTerminal"
|
||||
|
||||
}, {
|
||||
"name": "Launch logic2",
|
||||
"type": "go",
|
||||
@@ -32,6 +32,7 @@
|
||||
"mode": "auto",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"args": ["-port=2"],
|
||||
|
||||
"program": "${workspaceFolder}/logic", "console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
@@ -41,7 +42,7 @@
|
||||
"mode": "auto",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"args": ["-port=0"],
|
||||
"program": "${workspaceFolder}/logic", "console": "integratedTerminal"
|
||||
"program": "${workspaceFolder}/logic",
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package socket
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
func ConutPlayer() int {
|
||||
|
||||
count := 0
|
||||
@@ -15,46 +11,19 @@ func ConutPlayer() int {
|
||||
}
|
||||
|
||||
type ClientData struct {
|
||||
isCrossDomain bool //是否跨域过
|
||||
player *Player //客户实体
|
||||
IsCrossDomain bool //是否跨域过
|
||||
Player *Player //客户实体
|
||||
//UserID uint32
|
||||
m sync.Mutex
|
||||
|
||||
wsmsg WsCodec
|
||||
}
|
||||
|
||||
func (cd *ClientData) SetPlayer(player *Player) {
|
||||
cd.m.Lock()
|
||||
defer cd.m.Unlock()
|
||||
cd.player = player
|
||||
}
|
||||
func (cd *ClientData) GetPlayer() *Player {
|
||||
cd.m.Lock()
|
||||
defer cd.m.Unlock()
|
||||
return cd.player
|
||||
}
|
||||
func (cd *ClientData) Getwsmsg() *WsCodec {
|
||||
cd.m.Lock()
|
||||
defer cd.m.Unlock()
|
||||
return &cd.wsmsg
|
||||
}
|
||||
func (cd *ClientData) SetCrossDomain(isCrossDomain bool) {
|
||||
cd.m.Lock()
|
||||
defer cd.m.Unlock()
|
||||
cd.isCrossDomain = isCrossDomain
|
||||
}
|
||||
func (cd *ClientData) GetIsCrossDomain() bool {
|
||||
cd.m.Lock()
|
||||
defer cd.m.Unlock()
|
||||
return cd.isCrossDomain
|
||||
Wsmsg *WsCodec
|
||||
}
|
||||
|
||||
func NewClientData() *ClientData {
|
||||
cd := ClientData{
|
||||
isCrossDomain: false,
|
||||
player: nil,
|
||||
m: sync.Mutex{},
|
||||
wsmsg: WsCodec{},
|
||||
IsCrossDomain: false,
|
||||
Player: nil,
|
||||
|
||||
Wsmsg: &WsCodec{},
|
||||
}
|
||||
return &cd
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ var Mainplayer = &utils.SyncMap[uint32, *Player]{} //玩家数据
|
||||
|
||||
func (c *Conn) SendPack(bytes []byte) error {
|
||||
if t, ok := c.MainConn.Context().(*ClientData); ok {
|
||||
if t.Getwsmsg().Upgraded {
|
||||
if t.Wsmsg.Upgraded {
|
||||
// This is the echo server
|
||||
err := wsutil.WriteServerMessage(c.MainConn, ws.OpBinary, bytes)
|
||||
if err != nil {
|
||||
@@ -41,7 +41,7 @@ func (c *Conn) SendPack(bytes []byte) error {
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
MainConn Conn
|
||||
MainConn *Conn
|
||||
|
||||
IsLogin bool //是否登录
|
||||
mu sync.Mutex
|
||||
@@ -58,7 +58,7 @@ type Player struct {
|
||||
// PlayerOption 定义配置 Player 的函数类型
|
||||
type PlayerOption func(*Player)
|
||||
|
||||
func WithConn(c Conn) PlayerOption {
|
||||
func WithConn(c *Conn) PlayerOption {
|
||||
return func(p *Player) {
|
||||
p.MainConn = c
|
||||
}
|
||||
@@ -76,7 +76,7 @@ func NewPlayer(opts ...PlayerOption) *Player {
|
||||
}
|
||||
|
||||
func (p *Player) SendPack(b []byte) error {
|
||||
fmt.Println("发送数据包", len(b))
|
||||
// fmt.Println("发送数据包", len(b))
|
||||
err := p.MainConn.SendPack(b)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/gobwas/ws"
|
||||
"github.com/gobwas/ws/wsutil"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
|
||||
type Conn struct {
|
||||
MainConn gnet.Conn `struc:"[0]pad"` //TODO 不序列化,,序列化下面的作为blob存数据库
|
||||
Mu sync.Mutex
|
||||
}
|
||||
|
||||
func NewConn(c gnet.Conn) *Conn {
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package xml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/ECUST-XX/xml"
|
||||
)
|
||||
|
||||
func Test_main(t *testing.T) {
|
||||
|
||||
// 解析XML到结构体
|
||||
var maps Items
|
||||
t1, _ := getItemsXML()
|
||||
xml.Unmarshal(t1, &maps)
|
||||
|
||||
//tf, _ := xml.MarshalIndentShortForm(tt, " ", " ")
|
||||
fmt.Println(maps)
|
||||
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package xml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/ECUST-XX/xml" // 保持与之前一致的XML库
|
||||
)
|
||||
|
||||
// Items 根节点,对应<Items>标签
|
||||
type Items struct {
|
||||
XMLName xml.Name `xml:"Items"`
|
||||
Items []Item `xml:"Item"` // 包含所有物品配置
|
||||
}
|
||||
|
||||
// Item 单个物品配置,对应<Item>标签
|
||||
type Item struct {
|
||||
ID int `xml:"ID,attr"` // 物品ID(与items.xml一致)
|
||||
Name string `xml:"Name,attr"` // 物品名称
|
||||
Rarity int `xml:"Rarity,attr,omitempty"` // 稀有度(可选)
|
||||
Price int `xml:"Price,attr"` // 价格
|
||||
Tradability int `xml:"Tradability,attr"` // 可交易性(0/1)
|
||||
VipTradability int `xml:"VipTradability,attr"` // VIP可交易性(0/1)
|
||||
DailyKey int `xml:"DailyKey,attr,omitempty"` // 每日限制键值(可选)
|
||||
DailyOutMax int `xml:"DailyOutMax,attr,omitempty"` // 每日最大产出(可选)
|
||||
Wd int `xml:"wd,attr"` // 未知属性(根据原XML保留)
|
||||
UseMax int `xml:"UseMax,attr"` // 最大使用次数
|
||||
LifeTime int `xml:"LifeTime,attr"` // 生命周期(0为永久)
|
||||
Purpose int `xml:"purpose,attr"` // 用途标识
|
||||
Bean int `xml:"Bean,attr,omitempty"` // 豆子数量(可选)
|
||||
Hide int `xml:"Hide,attr"` // 是否隐藏(0/1)
|
||||
Sort int `xml:"Sort,attr,omitempty"` // 排序序号(可选)
|
||||
Des string `xml:"des,attr"` // 物品用途(根据说明补充)
|
||||
Color string `xml:"color,attr,omitempty"` // 装备名字颜色(可选)
|
||||
Level int `xml:"level,attr,omitempty"` // 装备等级(星星,可选)
|
||||
|
||||
Pet *Pet `xml:"pet,omitempty"` // 精灵属性子节点(可选)
|
||||
TeamPK *TeamPK `xml:"teamPK,omitempty"` // 要塞保卫战子节点(可选)
|
||||
}
|
||||
|
||||
// Pet 精灵属性子节点,对应<pet>标签
|
||||
// 注:根据实际需求补充字段,这里以常见属性为例
|
||||
type Pet struct {
|
||||
Attack int `xml:"attack,attr,omitempty"` // 攻击加成
|
||||
Defense int `xml:"defense,attr,omitempty"` // 防御加成
|
||||
HP int `xml:"hp,attr,omitempty"` // 生命值加成
|
||||
Speed int `xml:"speed,attr,omitempty"` // 速度加成
|
||||
}
|
||||
|
||||
// TeamPK 要塞保卫战子节点,对应<teamPK>标签
|
||||
// 注:根据实际需求补充字段,这里以常见属性为例
|
||||
type TeamPK struct {
|
||||
FortBonus int `xml:"fortBonus,attr,omitempty"` // 要塞加成
|
||||
DefenseBonus int `xml:"defenseBonus,attr,omitempty"` // 防御加成
|
||||
AttackBonus int `xml:"attackBonus,attr,omitempty"` // 攻击加成
|
||||
}
|
||||
|
||||
// 复用HTTP文件读取函数
|
||||
func ReadHTTPFile(url string) ([]byte, error) {
|
||||
client := &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("请求失败: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("请求返回非成功状态码: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
content, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取内容失败: %w", err)
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// 获取物品XML内容
|
||||
func getItemsXML() ([]byte, error) {
|
||||
// 替换为实际的Items XML文件URL
|
||||
content, err := ReadHTTPFile("http://127.0.0.1:8080/assets/43.xml")
|
||||
if err != nil {
|
||||
log.Fatalf("无法读取物品文件: %v", err)
|
||||
}
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// 解析XML到结构体
|
||||
func getItems() Items {
|
||||
var items Items
|
||||
content, _ := getItemsXML()
|
||||
if err := xml.Unmarshal(content, &items); err != nil {
|
||||
log.Fatalf("物品XML解析失败: %v", err)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
// 全局物品配置变量
|
||||
var ItemsConfig = getItems()
|
||||
@@ -1,20 +0,0 @@
|
||||
package skill
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/ECUST-XX/xml"
|
||||
)
|
||||
|
||||
func Test_main(t *testing.T) {
|
||||
|
||||
// 解析XML到结构体
|
||||
var maps MovesTbl
|
||||
t1, _ := getxml()
|
||||
xml.Unmarshal(t1, &maps)
|
||||
|
||||
//tf, _ := xml.MarshalIndentShortForm(tt, " ", " ")
|
||||
fmt.Println(maps.Moves[4].SideEffect)
|
||||
fmt.Println(maps.Moves[4].SideEffectArg)
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package xml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/ECUST-XX/xml"
|
||||
)
|
||||
|
||||
func Test_main(t *testing.T) {
|
||||
|
||||
// 解析XML到结构体
|
||||
var maps TalkCount
|
||||
t1, _ := getxml()
|
||||
xml.Unmarshal(t1, &maps)
|
||||
|
||||
//tf, _ := xml.MarshalIndentShortForm(tt, " ", " ")
|
||||
fmt.Println(maps)
|
||||
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package xml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/ECUST-XX/xml" // 注意:需确保该xml库与示例中使用的一致
|
||||
)
|
||||
|
||||
func getxml() ([]byte, error) {
|
||||
|
||||
// 读取整个文件内容,返回字节切片和错误
|
||||
content, err := ReadHTTPFile("http://127.0.0.1:8080/assets/talk_count.xml")
|
||||
if err != nil {
|
||||
// 处理错误(文件不存在、权限问题等)
|
||||
log.Fatalf("无法读取文件: %v", err)
|
||||
}
|
||||
return content, nil
|
||||
|
||||
}
|
||||
|
||||
// TalkCount 根节点,对应<talk_count>标签
|
||||
// 注意:xml.Name需指定命名空间,与XML中的xmlns保持一致
|
||||
type TalkCount struct {
|
||||
XMLName xml.Name `xml:"nieo.seer.org.talk-count talk_count"`
|
||||
Entries []Entry `xml:"entry"` // 包含所有entry节点
|
||||
}
|
||||
|
||||
// Entry 单个条目配置,对应<entry>标签
|
||||
type Entry 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)
|
||||
}
|
||||
|
||||
// 复用示例中的ReadHTTPFile函数(读取远程文件)
|
||||
func ReadHTTPFile(url string) ([]byte, error) {
|
||||
client := &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("请求失败: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("请求返回非成功状态码: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
content, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取内容失败: %w", err)
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// 获取XML内容(可根据实际URL修改)
|
||||
func getTalkCountXML() ([]byte, error) {
|
||||
// 注意:此处URL需替换为实际的talk_count.xml文件地址
|
||||
content, err := ReadHTTPFile("http://127.0.0.1:8080/assets/talk_count.xml")
|
||||
if err != nil {
|
||||
log.Fatalf("无法读取文件: %v", err)
|
||||
}
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// 解析XML到结构体
|
||||
func getTalkCount() TalkCount {
|
||||
var talkCount TalkCount
|
||||
content, _ := getTalkCountXML()
|
||||
// 解析XML时需注意命名空间匹配
|
||||
if err := xml.Unmarshal(content, &talkCount); err != nil {
|
||||
log.Fatalf("XML解析失败: %v", err)
|
||||
}
|
||||
return talkCount
|
||||
}
|
||||
|
||||
// 全局配置变量,用于存储解析后的结果
|
||||
var TalkCountConfig = getTalkCount()
|
||||
84
common/data/xmlres/file.go
Normal file
84
common/data/xmlres/file.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package xmlres
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/ECUST-XX/xml"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gfsnotify"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
)
|
||||
|
||||
var path string
|
||||
|
||||
func getXml[T any](path string) T {
|
||||
|
||||
// 解析XML到结构体
|
||||
var xmls T
|
||||
t1 := gfile.GetBytes(path)
|
||||
xml.Unmarshal(t1, &xmls)
|
||||
|
||||
return xmls
|
||||
}
|
||||
|
||||
var (
|
||||
MapConfig Maps //地图配置
|
||||
ItemsConfig Items //物品配置
|
||||
TalkConfig TalkCount //任务配置
|
||||
Monster MonsterRoot //野怪配置
|
||||
Skill MovesTbl //技能配置
|
||||
)
|
||||
|
||||
func initfile() {
|
||||
path1, _ := os.Getwd()
|
||||
path = path1 + "/public/assets/"
|
||||
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")
|
||||
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
initfile() //先初始化一次
|
||||
|
||||
go func() {
|
||||
|
||||
if !gfile.Exists(path) {
|
||||
fileHandle, _ := gfile.Create(path)
|
||||
fileHandle.Close()
|
||||
}
|
||||
|
||||
//updatersares()
|
||||
ctx := gctx.New()
|
||||
_, err := gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
if event.IsCreate() {
|
||||
glog.Debug(ctx, "创建文件 : ", event.Path)
|
||||
}
|
||||
if event.IsWrite() {
|
||||
glog.Debug(ctx, "写入文件 : ", event.Path)
|
||||
initfile() //先初始化一次
|
||||
}
|
||||
if event.IsRemove() {
|
||||
glog.Debug(ctx, "删除文件 : ", event.Path)
|
||||
}
|
||||
if event.IsRename() {
|
||||
glog.Debug(ctx, "重命名文件 : ", event.Path)
|
||||
}
|
||||
if event.IsChmod() {
|
||||
glog.Debug(ctx, "修改权限 : ", event.Path)
|
||||
}
|
||||
glog.Debug(ctx, event)
|
||||
}, true)
|
||||
|
||||
if err != nil {
|
||||
glog.Fatal(ctx, err)
|
||||
} else {
|
||||
select {}
|
||||
}
|
||||
}()
|
||||
|
||||
}
|
||||
53
common/data/xmlres/item.go
Normal file
53
common/data/xmlres/item.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package xmlres
|
||||
|
||||
import (
|
||||
"github.com/ECUST-XX/xml" // 保持与之前一致的XML库
|
||||
)
|
||||
|
||||
// Items 根节点,对应<Items>标签
|
||||
type Items struct {
|
||||
XMLName xml.Name `xml:"Items"`
|
||||
Items []Item `xml:"Item"` // 包含所有物品配置
|
||||
}
|
||||
|
||||
// Item 单个物品配置,对应<Item>标签
|
||||
type Item struct {
|
||||
ID int `xml:"ID,attr"` // 物品ID(与items.xml一致)
|
||||
Name string `xml:"Name,attr"` // 物品名称
|
||||
Rarity int `xml:"Rarity,attr,omitempty"` // 稀有度(可选)
|
||||
Price int `xml:"Price,attr"` // 价格
|
||||
Tradability int `xml:"Tradability,attr"` // 可交易性(0/1)
|
||||
VipTradability int `xml:"VipTradability,attr"` // VIP可交易性(0/1)
|
||||
DailyKey int `xml:"DailyKey,attr,omitempty"` // 每日限制键值(可选)
|
||||
DailyOutMax int `xml:"DailyOutMax,attr,omitempty"` // 每日最大产出(可选)
|
||||
Wd int `xml:"wd,attr"` // 未知属性(根据原XML保留)
|
||||
UseMax int `xml:"UseMax,attr"` // 最大使用次数
|
||||
LifeTime int `xml:"LifeTime,attr"` // 生命周期(0为永久)
|
||||
Purpose int `xml:"purpose,attr"` // 用途标识
|
||||
Bean int `xml:"Bean,attr,omitempty"` // 豆子数量(可选)
|
||||
Hide int `xml:"Hide,attr"` // 是否隐藏(0/1)
|
||||
Sort int `xml:"Sort,attr,omitempty"` // 排序序号(可选)
|
||||
Des string `xml:"des,attr"` // 物品用途(根据说明补充)
|
||||
Color string `xml:"color,attr,omitempty"` // 装备名字颜色(可选)
|
||||
Level int `xml:"level,attr,omitempty"` // 装备等级(星星,可选)
|
||||
|
||||
Pet *Pet `xml:"pet,omitempty"` // 精灵属性子节点(可选)
|
||||
TeamPK *TeamPK `xml:"teamPK,omitempty"` // 要塞保卫战子节点(可选)
|
||||
}
|
||||
|
||||
// Pet 精灵属性子节点,对应<pet>标签
|
||||
// 注:根据实际需求补充字段,这里以常见属性为例
|
||||
type Pet struct {
|
||||
Attack int `xml:"attack,attr,omitempty"` // 攻击加成
|
||||
Defense int `xml:"defense,attr,omitempty"` // 防御加成
|
||||
HP int `xml:"hp,attr,omitempty"` // 生命值加成
|
||||
Speed int `xml:"speed,attr,omitempty"` // 速度加成
|
||||
}
|
||||
|
||||
// TeamPK 要塞保卫战子节点,对应<teamPK>标签
|
||||
// 注:根据实际需求补充字段,这里以常见属性为例
|
||||
type TeamPK struct {
|
||||
FortBonus int `xml:"fortBonus,attr,omitempty"` // 要塞加成
|
||||
DefenseBonus int `xml:"defenseBonus,attr,omitempty"` // 防御加成
|
||||
AttackBonus int `xml:"attackBonus,attr,omitempty"` // 攻击加成
|
||||
}
|
||||
@@ -1,12 +1,6 @@
|
||||
package xml
|
||||
package xmlres
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/ECUST-XX/xml"
|
||||
)
|
||||
|
||||
@@ -68,56 +62,3 @@ type Component struct {
|
||||
Des string `xml:"des,attr,omitempty"` // 鼠标提示文本(可选)
|
||||
IsStop int `xml:"isStop,attr,omitempty"` // 鼠标悬停是否跳帧(0/1,可选)
|
||||
}
|
||||
|
||||
// ReadHTTPFile 通过HTTP GET请求获取远程文件内容
|
||||
// url: 远程文件的URL地址
|
||||
// 返回文件内容字节流和可能的错误
|
||||
func ReadHTTPFile(url string) ([]byte, error) {
|
||||
// 创建HTTP客户端并设置超时时间(避免无限等待)
|
||||
client := &http.Client{
|
||||
Timeout: 30 * time.Second, // 30秒超时
|
||||
}
|
||||
|
||||
// 发送GET请求
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("请求失败: %w", err)
|
||||
}
|
||||
defer resp.Body.Close() // 确保响应体被关闭
|
||||
|
||||
// 检查响应状态码
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("请求返回非成功状态码: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// 读取响应体内容
|
||||
content, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取内容失败: %w", err)
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
func getxml() ([]byte, error) {
|
||||
|
||||
// 读取整个文件内容,返回字节切片和错误
|
||||
content, err := ReadHTTPFile("http://127.0.0.1:8080/assets/210.xml")
|
||||
if err != nil {
|
||||
// 处理错误(文件不存在、权限问题等)
|
||||
log.Fatalf("无法读取文件: %v", err)
|
||||
}
|
||||
return content, nil
|
||||
|
||||
}
|
||||
func getMaps() Maps {
|
||||
|
||||
// 解析XML到结构体
|
||||
var maps Maps
|
||||
t1, _ := getxml()
|
||||
xml.Unmarshal(t1, &maps)
|
||||
|
||||
return maps
|
||||
}
|
||||
|
||||
// 全局函数配置
|
||||
var MapConfig = getMaps()
|
||||
122
common/data/xmlres/mon.go
Normal file
122
common/data/xmlres/mon.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package xmlres
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
)
|
||||
|
||||
// 根结构体:对应 <Maps> 节点
|
||||
type MonsterRoot struct {
|
||||
XMLName xml.Name `xml:"Maps"`
|
||||
WorldWildMons WorldWildMons `xml:"WorldWildMons"` // 世界野怪配置
|
||||
Maps []TMapConfig `xml:"Map"` // 所有地图配置(多个<Map>)
|
||||
DefaultMaps DefaultMaps `xml:"DefaultMaps"` // 默认登录场景
|
||||
VersionNumber VersionNumber `xml:"VersionNumber"` // 版本信息
|
||||
}
|
||||
|
||||
// 世界野怪容器:对应 <WorldWildMons>
|
||||
type WorldWildMons struct {
|
||||
WorldWildMonsters []WorldWildMonster `xml:"WorldWildMonster"` // 多个<WorldWildMonster>
|
||||
}
|
||||
|
||||
// 世界野怪配置:对应 <WorldWildMonster>
|
||||
type WorldWildMonster struct {
|
||||
WorldWildProb int `xml:"WorldWildProb,attr"` // 变身概率(分子)
|
||||
WorldWildMonId int `xml:"WorldWildMonId,attr"` // 野怪ID
|
||||
WorldWildMonLv int `xml:"WorldWildMonLv,attr"` // 野怪等级
|
||||
WorldWildStart int `xml:"WorldWildStart,attr"` // 出现起始时间(0-23)
|
||||
WorldWildEnd int `xml:"WorldWildEnd,attr"` // 出现结束时间(0-23)
|
||||
NewSeIdxs string `xml:"NewSeIdxs,attr"` // 特效ID(可能多个,空格分隔)
|
||||
}
|
||||
|
||||
// 单张地图配置:对应 <Map>
|
||||
type TMapConfig struct {
|
||||
ID int `xml:"ID,attr"` // 地图ID
|
||||
Name string `xml:"Name,attr"` // 地图名称
|
||||
InitX int `xml:"InitX,attr"` // 玩家初始X坐标
|
||||
InitY int `xml:"InitY,attr"` // 玩家初始Y坐标
|
||||
GameTriggerGrps []GameTriggerGrp `xml:"GameTriggerGrp"` // 触发点组(多个)
|
||||
Monsters *MonstersC `xml:"Monsters"` // 新增:野怪配置(可选,用指针处理“无该节点”的情况)
|
||||
Bosses []BossConfig `xml:"Bosses>Boss"` // BOSS配置(<Bosses>下的<Boss>)
|
||||
}
|
||||
|
||||
// ########################### 关键新增:MonstersConfig(对应 <Monsters>) ###########################
|
||||
// 野怪配置容器:包含野怪奖励概率和多只野怪
|
||||
type MonstersC struct {
|
||||
WildBonusProb int `xml:"WildBonusProb,attr"` // 打赢野怪给奖励的概率(分子,如300)
|
||||
WildBonusTotalProb int `xml:"WildBonusTotalProb,attr"` // 打赢野怪给奖励的概率(分母,如1000)
|
||||
BonusID int `xml:"BonusID,attr"` // 奖励ID(如5239)
|
||||
ItemBonusID int `xml:"ItemBonusID,attr"` // 物品奖励ID(如1)
|
||||
Monsters []Monster1 `xml:"Monster"` // 多只野怪(<Monster>子节点)
|
||||
}
|
||||
|
||||
// ########################### 关键新增:Monster(对应 <Monster>) ###########################
|
||||
// 单只野怪配置:ID可能是多个值(空格分隔),Lv是等级范围(空格分隔)
|
||||
type Monster1 struct {
|
||||
ID string `xml:"ID,attr"` // 野怪ID(如"164 0 0..."或"10")
|
||||
Lv string `xml:"Lv,attr"` // 等级范围(如"1 2"表示1-2级)
|
||||
}
|
||||
|
||||
// 游戏触发点组:对应 <GameTriggerGrp>
|
||||
type GameTriggerGrp struct {
|
||||
GameID string `xml:"GameID,attr"` // 游戏ID
|
||||
TriggerPts []TriggerPt `xml:"TriggerPt"` // 触发点(多个)
|
||||
}
|
||||
|
||||
// 触发点:对应 <TriggerPt>
|
||||
type TriggerPt struct {
|
||||
ID int `xml:"ID,attr"` // 触发点ID
|
||||
Name string `xml:"Name,attr"` // 触发点名称(可选)
|
||||
}
|
||||
|
||||
// BOSS配置:对应 <Boss>
|
||||
type BossConfig struct {
|
||||
Id *int `xml:"Id,attr"` // BOSSID(可选,用指针处理空值)
|
||||
BossCatchable int `xml:"BossCatchable,attr"` // 是否可捕捉(0/1,默认0)
|
||||
AppearTime string `xml:"AppearTime,attr"` // 出现时间(如"0 23")
|
||||
BossVisible int `xml:"BossVisible,attr"` // 是否可见(0/1,默认0)
|
||||
Name string `xml:"Name,attr"` // BOSS名称(可选)
|
||||
DailyKey *string `xml:"DailyKey,attr"` // 每日挑战次数Key(可选)
|
||||
MaxTimes *int `xml:"MaxTimes,attr"` // 非VIP每日挑战上限(可选)
|
||||
VipMaxTimes *int `xml:"VipMaxTimes,attr"` // VIP每日挑战上限(可选)
|
||||
WinBonusId *string `xml:"WinBonusId,attr"` // 胜利奖励ID(可选)
|
||||
WinOutId *int `xml:"WinOutId,attr"` // 胜利输出ID(可选)
|
||||
FailBonusId *string `xml:"FailBonusId,attr"` // 失败奖励ID(可选)
|
||||
FailOutId *int `xml:"FailOutId,attr"` // 失败输出ID(可选)
|
||||
BossMon []BossMon `xml:"BossMon"` // BOSS对应的精灵(多个)
|
||||
}
|
||||
|
||||
// BOSS精灵配置:对应 <BossMon>
|
||||
type BossMon struct {
|
||||
MonID string `xml:"MonID,attr"` // 精灵ID(可能多个,空格分隔)
|
||||
Hp int `xml:"Hp,attr"` // 生命值
|
||||
Lv int `xml:"Lv,attr"` // 等级
|
||||
NewSeIdxs string `xml:"NewSeIdxs,attr"` // 特效ID(可选,空格分隔)
|
||||
Atk *int `xml:"Atk,attr"` // 攻击(可选)
|
||||
Def *int `xml:"Def,attr"` // 防御(可选)
|
||||
Spatk *int `xml:"Spatk,attr"` // 特攻(可选)
|
||||
Spdef *int `xml:"Spdef,attr"` // 特防(可选)
|
||||
Spd *int `xml:"Spd,attr"` // 速度(可选)
|
||||
}
|
||||
|
||||
// 默认登录场景容器:对应 <DefaultMaps>
|
||||
type DefaultMaps struct {
|
||||
DefaultMaps []DefaultMap `xml:"DefaultMap"` // 多个默认场景
|
||||
}
|
||||
|
||||
// 默认登录场景:对应 <DefaultMap>
|
||||
type DefaultMap struct {
|
||||
ID int `xml:"ID,attr"` // 场景ID
|
||||
RandMaps string `xml:"RandMaps,attr"` // 随机场景列表(逗号分隔)
|
||||
Desc string `xml:"Desc,attr"` // 场景描述
|
||||
}
|
||||
|
||||
// 版本信息容器:对应 <VersionNumber>
|
||||
type VersionNumber struct {
|
||||
Version Version `xml:"Version"` // 版本详情
|
||||
}
|
||||
|
||||
// 版本详情:对应 <Version>
|
||||
type Version struct {
|
||||
ID string `xml:"ID,attr"` // 版本号(如"20190614")
|
||||
Desc string `xml:"Desc,attr"` // 版本描述
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package skill
|
||||
package xmlres
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
23
common/data/xmlres/talk.go
Normal file
23
common/data/xmlres/talk.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package xmlres
|
||||
|
||||
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节点
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package xml
|
||||
package xmlres
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -49,13 +49,7 @@ var s = `
|
||||
|
||||
func Test_main(t *testing.T) {
|
||||
|
||||
// 解析XML到结构体
|
||||
var maps Maps
|
||||
t1, _ := getxml()
|
||||
xml.Unmarshal(t1, &maps)
|
||||
|
||||
//tf, _ := xml.MarshalIndentShortForm(tt, " ", " ")
|
||||
fmt.Println(maps)
|
||||
initfile()
|
||||
|
||||
}
|
||||
|
||||
@@ -46,13 +46,13 @@ func (s *Server) OnClose(c gnet.Conn, _ error) (action gnet.Action) {
|
||||
return
|
||||
|
||||
}
|
||||
t := v.GetPlayer()
|
||||
if v != nil {
|
||||
glog.Debug(context.Background(), t, "断开连接")
|
||||
t.IsLogin = false
|
||||
socket.Mainplayer.Delete(t.Info.UserID)
|
||||
share.ShareManager.DeleteUserOnline(t.Info.UserID) //设置用户登录服务器
|
||||
t.Save() //保存玩家数据
|
||||
|
||||
if v.Player != nil {
|
||||
glog.Debug(context.Background(), v.Player.Info.UserID, "断开连接")
|
||||
v.Player.IsLogin = false
|
||||
socket.Mainplayer.Delete(v.Player.Info.UserID)
|
||||
share.ShareManager.DeleteUserOnline(v.Player.Info.UserID) //设置用户登录服务器
|
||||
v.Player.Save() //保存玩家数据
|
||||
}
|
||||
|
||||
//}
|
||||
@@ -86,7 +86,7 @@ func (s *Server) OnTraffic(c gnet.Conn) (action gnet.Action) {
|
||||
return gnet.Close
|
||||
}
|
||||
|
||||
ws := c.Context().(*socket.ClientData).Getwsmsg()
|
||||
ws := c.Context().(*socket.ClientData).Wsmsg
|
||||
tt, len1 := ws.ReadBufferBytes(c)
|
||||
if tt == gnet.Close {
|
||||
|
||||
@@ -166,7 +166,7 @@ const TEXT = "<policy-file-request/>\x00"
|
||||
|
||||
func handle(c gnet.Conn) {
|
||||
clientdata := c.Context().(*socket.ClientData)
|
||||
if clientdata.GetIsCrossDomain() {
|
||||
if clientdata.IsCrossDomain {
|
||||
return
|
||||
|
||||
}
|
||||
@@ -183,7 +183,7 @@ func handle(c gnet.Conn) {
|
||||
c.Write([]byte(CROSS_DOMAIN))
|
||||
c.Discard(len(TEXT))
|
||||
|
||||
clientdata.SetCrossDomain(true) //= true //TODO 待修复未成功切换bug
|
||||
clientdata.IsCrossDomain = true
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ func init() { //默认初始化扫描
|
||||
method := typ.Method(i)
|
||||
|
||||
methodValue := value.MethodByName(method.Name)
|
||||
fmt.Println("找到注册方法", method.Name)
|
||||
//fmt.Println("找到注册方法", method.Name)
|
||||
methodValue.Type().NumIn()
|
||||
|
||||
for _, func_cmd := range getcmd(methodValue.Type().In(0)) {
|
||||
@@ -190,13 +190,14 @@ func Recv(c *socket.Conn, data handler.TomeeHeader) {
|
||||
nameField.Set(reflect.ValueOf(data))
|
||||
}
|
||||
if cmdlister.Type().In(1) == reflect.TypeOf(&socket.Player{}) {
|
||||
c1 := service.GetPlayer(c, data.UserID)
|
||||
err := c1.WaitForLoginWithCtx(context.Background())
|
||||
t := service.GetPlayer(c, data.UserID)
|
||||
// fmt.Println(data.CMD, "接收 变量的地址 ", &t.Info, t.Info.UserID)
|
||||
err := t.WaitForLoginWithCtx(context.Background())
|
||||
if err != nil {
|
||||
fmt.Println("登录失败")
|
||||
}
|
||||
|
||||
params = append(params, ptrValue1, reflect.ValueOf(c1))
|
||||
params = append(params, ptrValue1, reflect.ValueOf(t))
|
||||
} else {
|
||||
|
||||
params = append(params, ptrValue1, reflect.ValueOf(c))
|
||||
@@ -225,7 +226,7 @@ func Recv(c *socket.Conn, data handler.TomeeHeader) {
|
||||
}
|
||||
|
||||
data.Version = "7"
|
||||
glog.Debug(context.Background(), data.CMD, "回复数据")
|
||||
//glog.Debug(context.Background(), data.CMD, "回复数据")
|
||||
c.SendPack(data.Pack(ret[0].Interface()))
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
// 处理命令: 1001
|
||||
@@ -22,22 +21,23 @@ func (h *Controller) Login(data *login.InInfo, c *socket.Conn) (result *login.Ou
|
||||
|
||||
if tt := data.CheakSession(); tt { //说明sid正确
|
||||
h.RPCClient.Kick(data.Head.UserID) //先踢人
|
||||
playerinfo := blservice.NewUserService(data.Head.UserID).Person()
|
||||
t := service.SetPlayer(c, playerinfo)
|
||||
|
||||
t := service.GetPlayer(c, data.Head.UserID)
|
||||
t.Info = blservice.NewUserService(data.Head.UserID).Person()
|
||||
t.Info.UserID = data.Head.UserID
|
||||
t.Onlinetime = uint32(time.Now().Unix()) //保存时间戳
|
||||
copier.Copy(playerinfo, t) //先复制给内存信息
|
||||
share.ShareManager.SetUserOnline(data.Head.UserID, h.Port) //设置用户登录服务器
|
||||
t.CompleteLogin() //通知客户端登录成功
|
||||
|
||||
glog.Debug(context.Background(), "登录成功,初始地图 人数:", space.GetSpace(t.Info.MapID).Len())
|
||||
|
||||
result = login.NewOutInfo() //设置登录消息
|
||||
copier.Copy(playerinfo, result)
|
||||
|
||||
result.PlayerInfo = *t.Info
|
||||
tt := maps.NewOutInfo()
|
||||
//copier.Copy(t.Info, tt)
|
||||
t1 := handler.NewTomeeHeader(2001, t.Info.UserID)
|
||||
defer space.GetSpace(t.Info.MapID).Set(t.Info.UserID, t).Range(func(playerID uint32, player *socket.Player) bool {
|
||||
tt := maps.NewOutInfo()
|
||||
copier.Copy(playerinfo, tt)
|
||||
t1 := handler.NewTomeeHeader(2001, t.Info.UserID)
|
||||
|
||||
player.SendPack(t1.Pack(&tt))
|
||||
return true
|
||||
})
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"blazing/logic/service/maphot"
|
||||
"blazing/logic/service/maps"
|
||||
"blazing/logic/service/space"
|
||||
mservice "blazing/modules/blazing/service"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
@@ -18,15 +17,11 @@ func (h *Controller) MapEnter(data *maps.InInfo, c *socket.Player) (result *maps
|
||||
space.GetSpace(c.Info.MapID).Set(c.Info.UserID, c) //添加玩家
|
||||
result = maps.NewOutInfo()
|
||||
c.Info.Pos = data.Point
|
||||
copier.Copy(c.Info, result)
|
||||
copier.Copy(result, c.Info)
|
||||
|
||||
data.Broadcast(c.Info.MapID, *result) //同步广播
|
||||
// 如果是无怪地图,直接返回
|
||||
|
||||
if mservice.NewMonsterService().GetId(c.Info.MapID) == nil {
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
// 创建新的停止通道
|
||||
c.StopChan = make(chan struct{})
|
||||
|
||||
@@ -70,6 +65,7 @@ func (h Controller) MapHot(data *maphot.InInfo, c *socket.Player) (result *mapho
|
||||
}
|
||||
func (h *Controller) MapLeave(data *maps.LeaveMapInboundInfo, c *socket.Player) (result *maps.LeaveMapOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||
//result = &maps.LeaveMapOutboundInfo{UserID: c.GetUserID()}
|
||||
|
||||
data.Broadcast(c.Info.MapID, maps.LeaveMapOutboundInfo{UserID: c.Info.UserID}) //同步广播
|
||||
space.GetSpace(c.Info.MapID).Delete(c.Info.UserID)
|
||||
// 如果有正在运行的刷怪协程,发送停止信号
|
||||
@@ -87,7 +83,7 @@ func (h *Controller) MapList(data *maps.ListMapPlayerInboundInfo, c *socket.Play
|
||||
|
||||
space.GetSpace(c.Info.MapID).Range(func(userID uint32, player *socket.Player) bool {
|
||||
result1 := maps.NewOutInfo()
|
||||
copier.Copy(player.Info, result1)
|
||||
copier.Copy(result1, player.Info)
|
||||
result.Player = append(result.Player, *result1)
|
||||
return true
|
||||
})
|
||||
|
||||
@@ -12,47 +12,28 @@ import (
|
||||
* 接受任务
|
||||
*/
|
||||
func (h Controller) AcceptTask(data *task.AcceptTaskInboundInfo, c *socket.Player) (result *task.AcceptTaskOutboundInfo, err errorcode.ErrorCode) {
|
||||
|
||||
if data.Head.CMD == 2201 { //判断不是每日任务
|
||||
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,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
} else {
|
||||
service.NewUserService(c.Info.UserID).DailyTaskExec(func(ttt map[uint32]model.DailyTaskInfo) 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.DailyTaskInfo{
|
||||
Status: 1,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
isdaliy := false
|
||||
if data.Head.CMD != 2201 { //判断是每日任务
|
||||
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,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
}, isdaliy)
|
||||
result = &task.AcceptTaskOutboundInfo{}
|
||||
result.TaskId = data.TaskId
|
||||
return result, 0
|
||||
@@ -62,29 +43,19 @@ func (h Controller) AcceptTask(data *task.AcceptTaskInboundInfo, c *socket.Playe
|
||||
* 更新任务步骤
|
||||
*/
|
||||
func (h Controller) AddTaskBuf(data *task.AddTaskBufInboundInfo, c *socket.Player) (result *task.AddTaskBufOutboundInfo, err errorcode.ErrorCode) {
|
||||
|
||||
if data.Head.CMD == 2204 { //判断不是每日任务
|
||||
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
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
} else {
|
||||
service.NewUserService(c.Info.UserID).DailyTaskExec(func(ttt map[uint32]model.DailyTaskInfo) bool {
|
||||
if conditions, ok := ttt[data.TaskId]; ok {
|
||||
conditions.DailyTaskInfo = data.TaskList
|
||||
ttt[data.TaskId] = conditions
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
isdaliy := false
|
||||
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
|
||||
}
|
||||
|
||||
return false
|
||||
}, isdaliy)
|
||||
|
||||
return &task.AddTaskBufOutboundInfo{}, 0
|
||||
}
|
||||
@@ -107,12 +78,10 @@ func (h Controller) Complete_Task(data *task.CompleteTaskInboundInfo, c *socket.
|
||||
* 获取任务状态
|
||||
*/
|
||||
func (h Controller) Get_Task_Buf(data *task.GetTaskBufInboundInfo, c *socket.Player) (result *task.GetTaskBufOutboundInfo, err errorcode.ErrorCode) {
|
||||
|
||||
if data.Head.CMD == 2203 { //判断不是每日任务
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
// isdaliy := false
|
||||
// if data.Head.CMD != 2203 { //判断是每日任务
|
||||
// isdaliy = true
|
||||
// }
|
||||
|
||||
return &task.GetTaskBufOutboundInfo{}, 0
|
||||
}
|
||||
|
||||
@@ -4,14 +4,18 @@ import (
|
||||
"blazing/common/data/socket"
|
||||
"blazing/common/socket/errorcode"
|
||||
"blazing/logic/service/space"
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
func (h Controller) Walk(data *space.InInfo, c *socket.Player) (result *space.OutInfo, err errorcode.ErrorCode) {
|
||||
|
||||
data.Broadcast(c.Info.UserID, space.OutInfo{Flag: data.Flag,
|
||||
UserID: c.Info.UserID,
|
||||
Reserve2: data.Reverse2,
|
||||
Point: data.Point}) //走路的广播
|
||||
result = &space.OutInfo{}
|
||||
err1 := copier.Copy(result, data)
|
||||
result.UserID = data.Head.UserID
|
||||
glog.Debug(context.Background(), err1)
|
||||
data.Broadcast(c.Info.MapID, *result) //走路的广播
|
||||
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package info
|
||||
|
||||
import (
|
||||
element "blazing/common/data/Element"
|
||||
"blazing/common/data/xml/skill"
|
||||
"blazing/common/data/xmlres"
|
||||
"blazing/common/utils/random"
|
||||
|
||||
"context"
|
||||
@@ -35,7 +35,7 @@ var Category = enum.New[struct {
|
||||
// 实现了战斗中技能的所有属性和行为,包括PP管理、技能使用、属性获取等
|
||||
// 战斗中可以修改技能实体值,比如是否暴击,是否必中等
|
||||
type BattleSkillEntity struct {
|
||||
skill.Move
|
||||
xmlres.Move
|
||||
ctx context.Context
|
||||
SideEffects []int
|
||||
SideEffectArgs []int
|
||||
@@ -61,7 +61,7 @@ func CreateBattleSkillWithInfinity(id int, pp int) *BattleSkillEntity {
|
||||
}
|
||||
|
||||
// 从资源仓库获取技能数据
|
||||
move, ok := skill.MovesConfig.Moves[id]
|
||||
move, ok := xmlres.MovesConfig.Moves[id]
|
||||
if !ok {
|
||||
glog.Error(context.Background(), "技能ID无效", "id", id)
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@ type OgreInfo struct {
|
||||
type OgrePetInfo struct {
|
||||
Id uint32
|
||||
Shiny uint32
|
||||
Lv uint32 `struc:"skip"` //等级
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,16 @@ package maps
|
||||
|
||||
import (
|
||||
"blazing/common/data/socket"
|
||||
"blazing/common/data/xmlres"
|
||||
"blazing/common/socket/handler"
|
||||
"blazing/logic/service/space"
|
||||
"blazing/modules/blazing/model"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type InInfo struct {
|
||||
@@ -38,9 +41,9 @@ func (t *InInfo) Broadcast(mapid uint32, o OutInfo) {
|
||||
func (t *InInfo) SpawnMonsters(c *socket.Player, isfrist bool) {
|
||||
// 获取当前地图的怪物配置
|
||||
|
||||
// if c == nil || mservice.NewMonsterService().GetId(c.MapId) == 0 { //用户离线
|
||||
// return
|
||||
// }
|
||||
if c == nil || c.Info.MapID == 0 { //用户离线
|
||||
return
|
||||
}
|
||||
if !c.IsLogin {
|
||||
defer func() {
|
||||
|
||||
@@ -60,27 +63,54 @@ func (t *InInfo) SpawnMonsters(c *socket.Player, isfrist bool) {
|
||||
|
||||
t.monsters, _, _ = replaceOneNumber(t.monsters)
|
||||
}
|
||||
t1 := t.genMonster(c.Info.UserID)
|
||||
t1 := t.genMonster(c.Info.MapID)
|
||||
if t1 != nil {
|
||||
t1 := tt.Pack(t1)
|
||||
c.SendPack(t1)
|
||||
}
|
||||
|
||||
c.SendPack(tt.Pack(&t1))
|
||||
}
|
||||
|
||||
// 2. 从 string 类型 slice 随机选一个元素
|
||||
func RandomStringFromSlice(s []string) string {
|
||||
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
randomIdx := r.Intn(len(s))
|
||||
return s[randomIdx]
|
||||
}
|
||||
|
||||
// 应该根据怪物信息决定后端生成
|
||||
func (t *InInfo) genMonster(mapid uint32) OgreInfo {
|
||||
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
|
||||
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
t2 := OgreInfo{}
|
||||
for i := 0; i < 3; i++ {
|
||||
|
||||
ttt := OgrePetInfo{}
|
||||
// ttt.Id = mservice.NewMonsterService().GetId(mapid) //待修改成xml获取
|
||||
|
||||
ttt.Shiny = uint32(i + 1) //异色概率,待实现自定义
|
||||
//t1.Data[i] = mservice.NewMonsterService().GetId(c.MapId)
|
||||
t1.Data[t.monsters[i]] = ttt
|
||||
t2.Data[t.monsters[i]] = t1.Data[t.monsters[i]]
|
||||
}
|
||||
|
||||
return t1
|
||||
return &t2
|
||||
}
|
||||
|
||||
// 计算整数的二进制1的个数(Integer.bitCount)
|
||||
@@ -101,7 +131,7 @@ func generateThreeUniqueNumbers() [3]int {
|
||||
index := 0
|
||||
|
||||
for index < 3 {
|
||||
num := rand.Intn(10)
|
||||
num := rand.Intn(9)
|
||||
if !selected[num] {
|
||||
selected[num] = true
|
||||
result[index] = num
|
||||
@@ -124,7 +154,7 @@ func replaceOneNumber(original [3]int) ([3]int, int, int) {
|
||||
originalMap[num] = true
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
for i := 0; i < 8; i++ {
|
||||
if !originalMap[i] {
|
||||
candidates = append(candidates, i)
|
||||
}
|
||||
|
||||
@@ -4,24 +4,30 @@ import (
|
||||
"blazing/common/data/socket"
|
||||
"blazing/common/socket/errorcode"
|
||||
"blazing/common/socket/handler"
|
||||
"blazing/modules/blazing/model"
|
||||
)
|
||||
|
||||
func GetPlayer(c *socket.Conn, userid uint32) *socket.Player { //TODO 这里待优化,可能存在内存泄漏问题
|
||||
|
||||
c.Mu.Lock()
|
||||
defer c.Mu.Unlock()
|
||||
//检查player初始化,是否为conn初始后取map,防止二次连接后存在两个player
|
||||
|
||||
clientdata := c.MainConn.Context().(*socket.ClientData)
|
||||
if clientdata.GetPlayer() != nil {
|
||||
return clientdata.GetPlayer()
|
||||
}
|
||||
var player *socket.Player
|
||||
if player1, ok := socket.Mainplayer.Load((userid)); ok {
|
||||
|
||||
clientdata.SetPlayer(player1)
|
||||
if clientdata.Player != nil {
|
||||
return clientdata.Player
|
||||
}
|
||||
|
||||
return player
|
||||
clientdata.Player = socket.NewPlayer(
|
||||
|
||||
socket.WithConn(c), //注入conn
|
||||
)
|
||||
|
||||
// gff := socket.NewClientData()
|
||||
|
||||
// gff.Player = clientdata.Player
|
||||
// c.MainConn.SetContext(gff)
|
||||
socket.Mainplayer.Store(userid, clientdata.Player)
|
||||
|
||||
return clientdata.Player
|
||||
// return nil
|
||||
}
|
||||
func KickPlayer(userid uint32) { //踢出玩家
|
||||
@@ -40,19 +46,3 @@ func KickPlayer(userid uint32) { //踢出玩家
|
||||
//return player
|
||||
// return nil
|
||||
}
|
||||
func SetPlayer(c *socket.Conn, user *model.PlayerInfo) *socket.Player { //TODO 这里待优化,
|
||||
|
||||
clientdata := c.MainConn.Context().(*socket.ClientData)
|
||||
|
||||
player := socket.NewPlayer(
|
||||
|
||||
|
||||
socket.WithConn(*c), //注入conn
|
||||
)
|
||||
socket.Mainplayer.Store(user.UserID, player)
|
||||
|
||||
clientdata.SetPlayer(player) //= player
|
||||
|
||||
return player
|
||||
// return nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package space
|
||||
|
||||
import (
|
||||
xml "blazing/common/data/xml/map"
|
||||
"blazing/common/data/xmlres"
|
||||
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
@@ -19,7 +19,7 @@ func GetMapHot() []MapHotInfo {
|
||||
|
||||
tt := make(map[uint32]uint32)
|
||||
|
||||
for _, v := range xml.MapConfig.Maps {
|
||||
for _, v := range xmlres.MapConfig.Maps {
|
||||
|
||||
t1, ok := tt[uint32(v.Super)]
|
||||
if ok {
|
||||
@@ -41,5 +41,5 @@ func GetMapHot() []MapHotInfo {
|
||||
}
|
||||
return result, nil
|
||||
})
|
||||
return result1.([]MapHotInfo)
|
||||
return result1.([]MapHotInfo)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package space
|
||||
|
||||
import (
|
||||
"blazing/common/data/socket"
|
||||
xml "blazing/common/data/xml/map"
|
||||
"blazing/common/data/xmlres"
|
||||
"blazing/common/utils"
|
||||
"blazing/modules/blazing/model"
|
||||
"sync"
|
||||
@@ -37,7 +37,7 @@ func (m *Space) Get(playerID uint32) (*socket.Player, bool) {
|
||||
|
||||
// Set 存储玩家实例(按ID)
|
||||
// 写操作使用Lock,独占锁保证数据一致性
|
||||
func (m *Space) Set(playerID uint32, player *socket.Player)*Space {
|
||||
func (m *Space) Set(playerID uint32, player *socket.Player) *Space {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.data[playerID] = player
|
||||
@@ -90,7 +90,7 @@ func GetSpace(id uint32) *Space {
|
||||
}
|
||||
//如果不ok,说明星球未创建,那就新建星球
|
||||
|
||||
for _, v := range xml.MapConfig.Maps {
|
||||
for _, v := range xmlres.MapConfig.Maps {
|
||||
if v.ID == int(id) { //找到这个地图
|
||||
t := NewSpace()
|
||||
t.DefaultPos = model.Pos{X: uint32(v.X), Y: uint32(v.Y)}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package model
|
||||
|
||||
import "blazing/cool"
|
||||
import (
|
||||
"blazing/cool"
|
||||
"time"
|
||||
)
|
||||
|
||||
const TableNameTask = "task"
|
||||
|
||||
@@ -15,7 +18,9 @@ type Task struct {
|
||||
type TaskInfo struct {
|
||||
// TaskInfo 任务步骤信息,对应Java的@ArraySerialize(FIXED_LENGTH=20)注解
|
||||
// struc:"[20]byte" 确保二进制序列化时固定20字节长度,json标签指定JSON字段名
|
||||
TaskInfo []uint32 `struc:"[20]byte" json:"task_info"`
|
||||
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"` //这里是每天重置
|
||||
// Status 任务整体状态:0-未接受,1-已接受,2-已完成未领取,3-已完成已领取
|
||||
// json标签指定JSON字段名,与业务状态说明保持一致
|
||||
Status byte `json:"status"`
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"blazing/cool"
|
||||
"time"
|
||||
)
|
||||
|
||||
const TableNameDailyTask = "DailyTask"
|
||||
|
||||
// DailyTask mapped from table <DailyTask>
|
||||
type DailyTask struct {
|
||||
*cool.Model
|
||||
PlayerID uint64 `gorm:"not null;index:idx_DailyTask_by_player_id;comment:'所属玩家ID'" json:"player_id"`
|
||||
Data string `gorm:"type:text;not null;comment:'全部数据'" json:"data"`
|
||||
}
|
||||
|
||||
// DailyTaskInfo 单个任务的详细信息,包含任务步骤状态和整体状态
|
||||
type DailyTaskInfo struct {
|
||||
// DailyTaskInfo 任务步骤信息,对应Java的@ArraySerialize(FIXED_LENGTH=20)注解
|
||||
// struc:"[20]byte" 确保二进制序列化时固定20字节长度,json标签指定JSON字段名
|
||||
DailyTaskInfo []uint32 `struc:"[20]byte" json:"DailyTask_info"`
|
||||
LastResetTime time.Time `gorm:"not null;comment:'上次重置时间(UTC)'" json:"last_reset_time"` //这里是每天重置
|
||||
// Status 任务整体状态:0-未接受,1-已接受,2-已完成未领取,3-已完成已领取
|
||||
// json标签指定JSON字段名,与业务状态说明保持一致
|
||||
Status byte `json:"status"`
|
||||
}
|
||||
|
||||
// TableName PlayerInfo's table name
|
||||
func (*DailyTask) TableName() string {
|
||||
return TableNamePlayerInfo
|
||||
}
|
||||
|
||||
// GroupName PlayerInfo's table group
|
||||
func (*DailyTask) GroupName() string {
|
||||
return "default"
|
||||
}
|
||||
|
||||
// NewPlayerInfo create a new PlayerInfo
|
||||
func NewDailyTask() *DailyTask {
|
||||
return &DailyTask{
|
||||
Model: cool.NewModel(),
|
||||
}
|
||||
}
|
||||
|
||||
// init 创建表
|
||||
func init() {
|
||||
cool.CreateTable(&DailyTask{})
|
||||
}
|
||||
@@ -33,7 +33,24 @@ func Exec[T, F any](userid uint32, s *cool.Service, processFunc func(F) bool) bo
|
||||
m1.Save(player)
|
||||
return false
|
||||
}
|
||||
func (s *UserService) TaskExec(t func(map[uint32]model.TaskInfo) bool) (ret bool) {
|
||||
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 {
|
||||
|
||||
//先重置每日
|
||||
for _, v := range tt {
|
||||
if v.TaskType == 1 && !IsToday(v.LastResetTime) {
|
||||
|
||||
v.Status = 0 //重置+自动接受每日任务
|
||||
v.LastResetTime = time.Now().UTC()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
return Exec[model.Task](s.userid, s.task, t)
|
||||
// m := cool.DBM(s.task.Model).Where("player_id", s.userid)
|
||||
// var tt model.Task
|
||||
@@ -57,34 +74,6 @@ func IsToday(t time.Time) bool {
|
||||
t.Month() == now.Month() &&
|
||||
t.Day() == now.Day()
|
||||
}
|
||||
func (s *UserService) DailyTaskExec(t func(map[uint32]model.DailyTaskInfo) bool) (ret bool) {
|
||||
Exec[model.DailyTask](s.userid, s.task, func(tt map[uint32]model.DailyTaskInfo) bool {
|
||||
|
||||
//先重置每日
|
||||
for _, v := range tt {
|
||||
if !IsToday(v.LastResetTime) {
|
||||
|
||||
v.Status = 0 //重置+自动接受每日任务
|
||||
v.LastResetTime = time.Now().UTC()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
return Exec[model.DailyTask](s.userid, s.task, t)
|
||||
// m := cool.DBM(s.task.Model).Where("player_id", s.userid)
|
||||
// var tt model.Task
|
||||
// m.Scan(&tt)
|
||||
// var ttt map[uint32]model.TaskInfo
|
||||
// json.Unmarshal([]byte(tt.Data), &ttt)
|
||||
// ret = t(ttt)
|
||||
// t1, _ := json.Marshal(&ttt)
|
||||
// tt.Data = string(t1)
|
||||
// m.Save(&tt) //退出时保存
|
||||
// return
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 完成任务
|
||||
|
||||
Reference in New Issue
Block a user