feat(model): 新增地图配置、BOSS数据和怪物刷新模块

This commit is contained in:
1
2025-08-16 02:39:25 +00:00
parent d34ec2eed1
commit caa901d208
9 changed files with 389 additions and 2 deletions

View File

@@ -0,0 +1,58 @@
package xml
import (
"fmt"
"testing"
"github.com/ECUST-XX/xml"
)
var s = `
<?xml version="1.0" encoding="UTF-8" ?>
<!--
多个地图ID归属于一个星球
此XML表主要配置一些各个星球有可能需要用到的共用信息, 比如目前在世界地图上显示玩家所在位置
-->
<superMaps>
<maps id="1" name="传送舱" x="" y=""/>
<maps id="4" name="船长室" x="" y=""/>
<maps id="5" name="实验室" x="" y=""/>
<maps id="6" name="动力室" x="" y=""/>
<maps id="7" name="瞭望舱" x="" y=""/>
<maps id="8" name="机械室" x="" y=""/>
<maps id="9" name="资料室" x="" y=""/>
<maps id="19" name="太空站" x="" y=""/>
<maps id="101" name="教官办公室" x="" y=""/>
<maps id="103" name="瞭望露台" x="" y=""/>
<maps id="107" name="发明室" x="" y=""/>
<!--星球-->
<maps id="10 11 12 13" name="克洛斯星" galaxy="1" x="358" y="46"/>
<maps id="15 16 17" name="火山星" galaxy="1" x="533" y="46"/>
<maps id="20 21 22" name="海洋星" galaxy="1" x="190" y="11"/>
<maps id="25 26 27" name="云霄星" galaxy="1" x="652" y="24"/>
<maps id="30 31 32 33 34 35 36" name="赫尔卡星" galaxy="1" x="45" y="34"/>
<maps id="40 41 42 43" name="塞西利亚星" galaxy="1" x="1012" y="30"/>
<maps id="17" name="双子阿尔法星" galaxy="1" x="822" y="96"/>
<maps id="47 49" name="双子贝塔星" galaxy="1" x="883" y="63"/>
<maps id="51 52 53" name="斯诺星" galaxy="1" x="1290" y="15"/>
<maps id="54 55 56" name="露西欧星" galaxy="1" x="1405" y="120"/>
<maps id="57 58 59" name="尼古尔星" galaxy="2" x="30" y="50"/>
<maps id="60 61 62 63 64" name="塔克星" galaxy="2" x="135" y="44"/>
<maps id="325 326 327" name="艾迪星" galaxy="2" x="250" y="30"/>
<maps id="328" name="斯科尔星" galaxy="2" x="375" y="40"/>
<maps id="333 334" name="普雷空间站" galaxy="2" x="500" y="50"/>
<maps id="338 339" name="哈默星" galaxy="2" x="590" y="70"/>
<maps id="314" name="拜伦号" galaxy="1" x="1160" y="55"/>
</superMaps>`
func Test_main(t *testing.T) {
// 解析XML到结构体
var maps TalkCount
t1, _ := getxml()
xml.Unmarshal(t1, &maps)
//tf, _ := xml.MarshalIndentShortForm(tt, " ", " ")
fmt.Println(maps)
}

View File

@@ -0,0 +1,89 @@
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()

View File

@@ -2,7 +2,7 @@ package space
import (
"blazing/common/data/entity"
"blazing/common/data/xml"
xml "blazing/common/data/xml/map"
"blazing/common/socket/handler"
"blazing/common/utils"
"blazing/modules/blazing/model"

View File

@@ -0,0 +1,192 @@
package model
import (
"blazing/cool"
"encoding/json"
)
// ------------------------------
// 1. BOSS主表结构核心ID与关联
// ------------------------------
const TableNameBoss = "boss"
// Boss 主表仅存储核心索引和JSON数据
type Boss struct {
*cool.Model
PlanetID int32 `gorm:"not null;index:idx_boss_planet;comment:'所属星球/地图ID'" json:"planet_id"`
BossID int32 `gorm:"not null;comment:'BOSS序号同星球内唯一'" json:"boss_id"`
Data string `gorm:"type:text;not null;comment:'BOSS详细数据(JSON格式)'" json:"data"`
Galaxy string `gorm:"type:varchar(50);comment:'所属星系(如帕诺星系)'" json:"galaxy"`
}
// 联合唯一索引:确保星球+BOSS序号唯一
func (b *Boss) Indexes() map[string]string {
return map[string]string{
"idx_planet_boss_unique": "planet_id,boss_id",
}
}
// TableName 定义表名
func (*Boss) TableName() string {
return TableNameBoss
}
// GroupName 定义分组名
func (*Boss) GroupName() string {
return "default"
}
// NewBoss 创建新的BOSS主表实例
func NewBoss() *Boss {
return &Boss{
Model: cool.NewModel(),
}
}
// ------------------------------
// 2. BOSS详细数据结构JSON存储
// ------------------------------
// BossData 封装BOSS所有详细属性用于JSON序列化
type BossData struct {
// 基础信息
EncyclopediaID int32 `json:"encyclopedia_id"` // BOSS图鉴ID
Desc string `json:"desc"` // BOSS名称描述
Level int32 `json:"level"` // 等级
Capturable bool `json:"capturable"` // 是否可捕捉
// 战斗属性
MaxHP int32 `json:"max_hp"` // 最大血量(-1使用默认公式)
Attack int32 `json:"attack"` // 攻击属性
Defense int32 `json:"defense"` // 防御属性
SpecialAttack int32 `json:"special_attack"` // 特攻属性
SpecialDefense int32 `json:"special_defense"` // 特防属性
Speed int32 `json:"speed"` // 速度属性
Definitely int32 `json:"definitely"` // 必定命中率(默认5)
Dodge int32 `json:"dodge"` // 闪避率(默认5)
Stat string `json:"stat"` // 开局属性变化(攻击,特攻,防御,特防,速度,命中)
// 技能列表
Skills []BossSkill `json:"skills"`
// 免疫效果
ImmunityEffectIDs []int32 `json:"immunity_effect_ids"` // 免疫效果ID列表
ImmunityBuffNames []string `json:"immunity_buff_names"` // 免疫Buff名称列表
// 特殊Buff
SpecialBuffs []SpecialBuff `json:"special_buffs"`
}
// BossSkill 技能详情结构
type BossSkill struct {
ID int32 `json:"id"` // 技能ID
Desc string `json:"desc"` // 技能描述
InfinityPP bool `json:"infinity_pp"` // 是否PP无限
}
// SpecialBuff 特殊Buff结构
type SpecialBuff struct {
Value string `json:"value"` // Buff标识(如boss://map314-boss0)
Params string `json:"params"` // 附加参数(空格分隔)
}
// ------------------------------
// 3. JSON序列化/反序列化工具方法
// ------------------------------
// ToJSON 将BossData转为JSON字符串
func (d *BossData) ToJSON() (string, error) {
data, err := json.Marshal(d)
if err != nil {
return "", err
}
return string(data), nil
}
// ParseBossData 从JSON字符串解析BossData
func ParseBossData(jsonStr string) (*BossData, error) {
var data BossData
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
return nil, err
}
return &data, nil
}
// ------------------------------
// 4. 表初始化
// ------------------------------
func init() {
// 创建BOSS主表
cool.CreateTable(&Boss{})
}
// ------------------------------
// 5. 使用示例
// ------------------------------
/*
// 存储BOSS数据示例
func ExampleSaveBoss() {
// 1. 构建详细数据
skills := []BossSkill{
{ID: 10001, Desc: "撞击", InfinityPP: true},
{ID: 20020, Desc: "毒粉", InfinityPP: true},
}
immunityEffects := []int32{7, 36}
immunityBuffs := []string{"condition://brun", "condition://poison"}
specialBuffs := []SpecialBuff{
{Value: "boss://map59-boss0", Params: ""},
}
bossData := &BossData{
EncyclopediaID: 347,
Desc: "远古鱼龙",
Level: 100,
Capturable: false,
MaxHP: 3000,
Attack: 280,
SpecialAttack: 417,
Defense: 350,
SpecialDefense: 317,
Speed: 264,
Definitely: 45,
Stat: "0 0 0 0 0 0",
Skills: skills,
ImmunityEffectIDs: immunityEffects,
ImmunityBuffNames: immunityBuffs,
SpecialBuffs: specialBuffs,
}
// 2. 序列化为JSON
dataJSON, _ := bossData.ToJSON()
// 3. 存储到主表
boss := NewBoss()
boss.PlanetID = 59
boss.BossID = 0
boss.Galaxy = "卡兰星系"
boss.Data = dataJSON
// 实际项目中使用GORM保存
// db.Create(boss)
}
// 查询BOSS数据示例
func ExampleGetBoss() {
// 1. 从数据库查询主表
var boss Boss
// db.Where("planet_id = ? AND boss_id = ?", 59, 0).First(&boss)
// 2. 解析JSON数据
bossData, _ := ParseBossData(boss.Data)
// 3. 使用数据
println("BOSS名称:", bossData.Desc)
println("等级:", bossData.Level)
println("技能数量:", len(bossData.Skills))
}
*/

View File

@@ -0,0 +1,47 @@
package model
import (
"blazing/cool"
)
const (
TableNameMonsterRefresh = "monster_refresh" // 怪物刷新规则表
)
// 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文本暂定传入时间
}
// TableName MonsterRefresh's table name
func (*MonsterRefresh) TableName() string {
return TableNameMonsterRefresh
}
// GroupName MonsterRefresh's table group
func (*MonsterRefresh) GroupName() string {
return "default"
}
// NewMonsterRefresh create a new MonsterRefresh
func NewMonsterRefresh() *MonsterRefresh {
return &MonsterRefresh{
Model: cool.NewModel(),
}
}
// 初始化表结构
func init() {
cool.CreateTable(&MonsterRefresh{})
}

View File

@@ -18,7 +18,7 @@ type Pos struct {
// PeopleItemInfo 穿戴装备信息结构对应Java的PeopleItemInfo
type PeopleItemInfo struct {
ID uint32 `struc:"uint32"` // 装备id对应Java的@UInt long
ID uint32 `struc:"uint32"` // 装备id
Level uint32 `struc:"uint32" default:"1"` // 未知字段默认值1对应Java的@Builder.Default
}

View File

@@ -0,0 +1 @@
package model