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 { Head handler.TomeeHeader `cmd:"2001" struc:"[0]pad"` //切换地图 // 地图类型 MapType uint32 MapId uint32 // Point: 直接给坐标x,y Point model.Pos `fieldDesc:"直接给坐标x,y"` monsters [3]int // Reverse2: 暂定 占位字符2 //Reverse2 string `struc:"[2]byte"` } func (t *InInfo) Broadcast(mapid uint32, o OutInfo) { space.GetSpace(mapid).Range(func(playerID uint32, player *socket.Player) bool { t.Head.Result = 0 player.SendPack(t.Head.Pack(&o)) return true }) } // 刷怪具体实现 func (t *InInfo) SpawnMonsters(c *socket.Player, isfrist bool) { // 获取当前地图的怪物配置 if c == nil || c.Info.MapID == 0 { //用户离线 return } if !c.IsLogin { defer func() { if c.StopChan != nil { close(c.StopChan) c.StopChan = nil } }() } // 创建数据包 tt := handler.NewTomeeHeader(2004, c.Info.UserID) if isfrist { t.monsters = generateThreeUniqueNumbers() } else { t.monsters, _, _ = replaceOneNumber(t.monsters) } t1 := t.genMonster(c.Info.MapID) if t1 != nil { c.OgreInfo = t1 t1 := tt.Pack(t1) c.SendPack(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) *socket.OgreInfo { // 设置怪物信息 t1 := socket.OgreInfo{} 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 := socket.OgrePetInfo{ Id: gconv.Uint32(RandomStringFromSlice(id)), } if ttt.Id != 0 { ttt.Shiny = 0 //待确认是否刷新异色 ttt.Lv = gconv.Uint32(RandomStringFromSlice(lv)) } t1.Data[i] = ttt } } t2 := socket.OgreInfo{} for i := 0; i < 3; i++ { t2.Data[t.monsters[i]] = t1.Data[t.monsters[i]] } return &t2 } // 计算整数的二进制1的个数(Integer.bitCount) func bitsCount(n int) int { count := 0 for n > 0 { count += n & 1 n >>= 1 } return count } // 生成0-9之间三个不重复的随机数 进地图5s func generateThreeUniqueNumbers() [3]int { rand.Seed(time.Now().UnixNano()) selected := make(map[int]bool) var result [3]int index := 0 for index < 3 { num := rand.Intn(9) if !selected[num] { selected[num] = true result[index] = num index++ } } return result } // 从三个数字中移除一个,并从剩余6个数字中选一个补充 10s func replaceOneNumber(original [3]int) ([3]int, int, int) { // 随机选择要移除的索引(0-2) removeIndex := rand.Intn(3) removedNum := original[removeIndex] // 找出所有不在原始数组中的数字(候选数字) candidates := []int{} originalMap := make(map[int]bool) for _, num := range original { originalMap[num] = true } for i := 0; i < 8; i++ { if !originalMap[i] { candidates = append(candidates, i) } } // 从候选数字中随机选择一个 newNum := candidates[rand.Intn(len(candidates))] // 创建新数组并替换数字 newNumbers := original newNumbers[removeIndex] = newNum return newNumbers, removedNum, newNum } // 这里存储星球的map //var planetmap utils.SyncMap[] //= space.NewSyncMap() // PeopleInfo PeopleInfo类,实现OutboundMessage接口 type OutInfo struct { UserID uint32 `struc:"uint32" fieldDesc:"米米号" json:"user_id"` // 16字节昵称 Nick string `struc:"[16]byte" fieldDesc:"16字节昵称" json:"nick"` // 机器人人物颜色 00 rgb Color uint32 `struc:"uint32" fieldDesc:"机器人人物颜色 00 rgb" json:"color"` // 固定值0 Texture uint32 `struc:"uint32" fieldDesc:"固定值0" json:"texture"` // 暂时不明建议先给固定值0 Vip uint16 ` json:"vip"` // 暂时不明建议先给固定值15 Viped uint16 ` default:"15" json:"viped"` // 暂时不明建议先给固定值1 VipStage uint32 `struc:"uint32" fieldDesc:"暂时不明建议先给固定值1" json:"vip_stage"` // 人物状态 =0 步行 !=0 飞行 ActionType uint32 `struc:"uint32" fieldDesc:"人物状态 =0 步行 !=0 飞行" json:"action_type"` // 上线的地图id Pos model.Pos `fieldDesc:"上线的地图id" json:"pos"` // 暂时不明给0 Action uint32 `struc:"uint32" fieldDesc:"暂时不明给0" json:"action"` // 暂时不明给2 Direction uint32 `struc:"uint32" default:"2" fieldDesc:"暂时不明给2" json:"direction"` // 暂时不明给0 ChangeShape uint32 `struc:"uint32" fieldDesc:"暂时不明给0" json:"change_shape"` // 暂时不明给0 SpiritTime uint32 `struc:"uint32" fieldDesc:"暂时不明给0" json:"spirit_time"` // 暂时不明给0 SpiritID uint32 `struc:"uint32" fieldDesc:"暂时不明给0" json:"spirit_id"` // 宠物 ID 暂时无法测试,给 0 PetDV uint32 `struc:"uint32" fieldDesc:"宠物ID暂时无法测试, 给0" json:"pet_dv"` // 宠物闪光暂时无法测试,给 0 PetShiny uint32 `struc:"uint32" fieldDesc:"宠物闪光暂时无法测试, 给0" json:"pet_shiny"` // 宠物皮肤暂时无法测试,给 0 PetSkin uint32 `struc:"uint32" fieldDesc:"宠物皮肤暂时无法测试, 给0" json:"pet_skin"` // 填充字符 Reserved uint32 `struc:"uint32" fieldDesc:"填充字符" json:"reserved"` // 填充字符 Reserved1 uint32 `struc:"uint32" fieldDesc:"填充字符" json:"reserved1"` // 填充字符 Reserved2 uint32 `struc:"uint32" fieldDesc:"填充字符" json:"reserved2"` // 暂时不明给0 FightFlag uint32 `struc:"uint32" fieldDesc:"暂时不明给0" json:"fight_flag"` // 教官ID TeacherID uint32 `struc:"uint32" fieldDesc:"教官ID" json:"teacher_id"` // 学员ID StudentID uint32 `struc:"uint32" fieldDesc:"学员ID" json:"student_id"` // nono状态 固定值-1 NonoState uint32 `struc:"uint32" default:"0xFFFFFFFF" fieldDesc:"nono状态 固定值-1" json:"nono_state"` // nono颜色 00 FF FF FF NonoColor uint32 `struc:"uint32" fieldDesc:"nono颜色 00 FF FF FF" json:"nono_color"` // 是不是超能nono 固定值1 SuperNono uint32 `struc:"uint32" default:"1" fieldDesc:"是不是超能nono 固定值1" json:"super_nono"` // 暂时不明给0 PlayerForm uint32 `struc:"uint32" fieldDesc:"暂时不明给0" json:"player_form"` // 暂时不明给0 TransTime uint32 `struc:"uint32" fieldDesc:"暂时不明给0" json:"trans_time"` // 暂时不明给0 TeamID uint32 `struc:"uint32" fieldDesc:"暂时不明给0" json:"team_id"` // 暂时不明给0 TeamCoreCount uint32 `struc:"uint32" fieldDesc:"暂时不明给0" json:"team_core_count"` // 暂时不明给0 TeamIsShow uint32 `struc:"uint32" fieldDesc:"暂时不明给0" json:"team_is_show"` // 暂时不明给0 LogoBg uint16 `json:"logo_bg"` // 暂时不明给0 LogoIcon uint16 ` json:"logo_icon"` // 暂时不明给0 LogoColor uint16 `json:"logo_color"` // 暂时不明给0 TxtColor uint16 `json:"txt_color"` // 4字节 LogoWord [4]byte `struc:"[4]byte" fieldDesc:"4字节" json:"logo_word"` ClothesLen uint32 `struc:"sizeof=Clothes" fieldDesc:"穿戴装备的信息" json:"clothes_len"` // 穿戴装备的信息 Clothes []model.PeopleItemInfo `fieldDesc:"穿戴装备的信息" json:"clothes"` } func NewOutInfo() *OutInfo { l := &OutInfo{} // 自动填充 struct tag 里的 default 值 if err := defaults.Set(l); err != nil { panic(err) // 方便发现 default 设置错误 } 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) }