世界怪物、NPC、装置等场景实体读取lua配置生成,实现AOI九宫格动态加载

This commit is contained in:
flswld
2023-01-15 05:30:49 +08:00
parent cd9ec6f55c
commit e3a2e0550e
20 changed files with 2133 additions and 219 deletions

View File

@@ -95,7 +95,10 @@ func NewGameManager(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32, gs
USER_MANAGER.SetRemoteUserOnlineState(BigWorldAiUid, true, mainGsAppid)
if r.IsMainGs() {
// TODO 测试
for i := 1; i < 8; i++ {
r.ai.Pos.X -= random.GetRandomFloat64(25.0, 35.0)
r.ai.Pos.Y += 1.0
r.ai.Pos.Z += random.GetRandomFloat64(25.0, 35.0)
for i := 1; i < 3; i++ {
uid := 1000000 + uint32(i)
avatarId := uint32(0)
for _, avatarData := range gdconf.CONF.AvatarDataMap {
@@ -109,8 +112,9 @@ func NewGameManager(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32, gs
AvatarTeamGuidList: []uint64{robot.AvatarMap[avatarId].Guid},
CurAvatarGuid: robot.AvatarMap[avatarId].Guid,
})
robot.Pos.X += random.GetRandomFloat64(0.0, 1.0)
robot.Pos.Z += random.GetRandomFloat64(0.0, 1.0)
robot.Pos.X -= random.GetRandomFloat64(25.0, 35.0)
robot.Pos.Y += 1.0
robot.Pos.Z += random.GetRandomFloat64(25.0, 35.0)
r.UserWorldAddPlayer(WORLD_MANAGER.GetAiWorld(), robot)
}
}
@@ -170,7 +174,7 @@ func (g *GameManager) gameMainLoop() {
logger.Error("error: %v", err)
logger.Error("stack: %v", logger.Stack())
motherfuckerPlayerInfo, _ := json.Marshal(SELF)
logger.Error("the motherfucker player info: %v", motherfuckerPlayerInfo)
logger.Error("the motherfucker player info: %v", string(motherfuckerPlayerInfo))
if SELF != nil {
GAME_MANAGER.DisconnectPlayer(SELF.PlayerID, kcp.EnetServerKick)
}

View File

@@ -128,6 +128,7 @@ func (r *RouteManager) initRoute() {
r.registerRouter(cmd.GCGAskDuelReq, GAME_MANAGER.GCGAskDuelReq)
r.registerRouter(cmd.GCGInitFinishReq, GAME_MANAGER.GCGInitFinishReq)
r.registerRouter(cmd.GCGOperationReq, GAME_MANAGER.GCGOperationReq)
r.registerRouter(cmd.ObstacleModifyNotify, GAME_MANAGER.ObstacleModifyNotify)
}
func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) {

View File

@@ -4,7 +4,6 @@ import (
"time"
"hk4e/common/constant"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/pkg/random"
"hk4e/protocol/cmd"
@@ -348,20 +347,6 @@ func (t *TickManager) onTickSecond(now int64) {
player.SafePos.Z = player.Pos.Z
}
}
// 刷怪
if !WORLD_MANAGER.IsRobotWorld(world) && world.owner.SceneLoadState == model.SceneEnterDone {
scene := world.GetSceneById(3)
monsterEntityCount := 0
for _, entity := range scene.entityMap {
if entity.entityType == uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER) {
monsterEntityCount++
}
}
if monsterEntityCount < 3 {
monsterEntityId := t.createMonster(scene)
GAME_MANAGER.AddSceneEntityNotify(world.owner, proto.VisionType_VISION_TYPE_BORN, []uint32{monsterEntityId}, true, false)
}
}
}
// GCG游戏Tick
for _, game := range GCG_MANAGER.gameMap {
@@ -396,30 +381,3 @@ func (t *TickManager) onTick50MilliSecond(now int64) {
})
}
}
func (t *TickManager) createMonster(scene *Scene) uint32 {
pos := &model.Vector{
X: 2747,
Y: 194,
Z: -1719,
}
fpm := map[uint32]float32{
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP): float32(72.91699),
uint32(constant.FightPropertyConst.FIGHT_PROP_PHYSICAL_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_DEFENSE): float32(505.0),
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK): float32(45.679916),
uint32(constant.FightPropertyConst.FIGHT_PROP_ICE_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_ATTACK): float32(45.679916),
uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP): float32(72.91699),
uint32(constant.FightPropertyConst.FIGHT_PROP_FIRE_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_ELEC_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_WIND_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_ROCK_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_GRASS_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_WATER_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_HP): float32(72.91699),
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_DEFENSE): float32(505.0),
}
entityId := scene.CreateEntityMonster(pos, 1, fpm)
return entityId
}

View File

@@ -168,3 +168,9 @@ func (g *GameManager) ServerAppidBindNotify(userId uint32, fightAppId string, jo
player.SceneLoadState = model.SceneNone
g.SendMsg(cmd.PlayerEnterSceneNotify, userId, player.ClientSeq, g.PacketPlayerEnterSceneNotifyLogin(player, proto.EnterType_ENTER_TYPE_SELF))
}
func (g *GameManager) ObstacleModifyNotify(player *model.Player, payloadMsg pb.Message) {
logger.Debug("user obstacle modify, uid: %v", player.PlayerID)
ntf := payloadMsg.(*proto.ObstacleModifyNotify)
logger.Debug("ObstacleModifyNotify: %v", ntf)
}

View File

@@ -132,7 +132,7 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
logger.Error("could not found target, defense id: %v", attackResult.DefenseId)
continue
}
attackResult.Damage *= 100
attackResult.Damage *= 10
damage := attackResult.Damage
attackerId := attackResult.AttackerId
_ = attackerId
@@ -150,6 +150,9 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
EntityId: target.id,
}
g.SendToWorldA(world, cmd.EntityFightPropUpdateNotify, player.ClientSeq, entityFightPropUpdateNotify)
if currHp == 0 && target.avatarEntity == nil {
scene.SetEntityLifeState(target, constant.LifeStateConst.LIFE_DEAD, proto.PlayerDieType_PLAYER_DIE_TYPE_GM)
}
combatData, err := pb.Marshal(hitInfo)
if err != nil {
logger.Error("create combat invocations entity hit info error: %v", err)
@@ -185,6 +188,11 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
}
if sceneEntity.avatarEntity != nil {
// 玩家实体在移动
g.AoiPlayerMove(player, player.Pos, &model.Vector{
X: float64(motionInfo.Pos.X),
Y: float64(motionInfo.Pos.Y),
Z: float64(motionInfo.Pos.Z),
})
// 更新玩家的位置信息
player.Pos.X = float64(motionInfo.Pos.X)
player.Pos.Y = float64(motionInfo.Pos.Y)
@@ -244,6 +252,61 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
}
}
func (g *GameManager) AoiPlayerMove(player *model.Player, oldPos *model.Vector, newPos *model.Vector) {
aoiManager, exist := WORLD_MANAGER.sceneBlockAoiMap[player.SceneId]
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId)
if exist {
oldGid := aoiManager.GetGidByPos(float32(oldPos.X), 0.0, float32(oldPos.Z))
newGid := aoiManager.GetGidByPos(float32(newPos.X), 0.0, float32(newPos.Z))
if oldGid != newGid {
// 跨越了格子
oldGridList := aoiManager.GetSurrGridListByGid(oldGid)
oldObjectMap := make(map[int64]any)
for _, grid := range oldGridList {
tmp := grid.GetObjectList()
for k, v := range tmp {
oldObjectMap[k] = v
}
}
newGridList := aoiManager.GetSurrGridListByGid(newGid)
newObjectMap := make(map[int64]any)
for _, grid := range newGridList {
tmp := grid.GetObjectList()
for k, v := range tmp {
newObjectMap[k] = v
}
}
delEntityIdList := make([]uint32, 0)
for oldObjectId := range oldObjectMap {
_, exist := newObjectMap[oldObjectId]
if exist {
continue
}
entity := scene.GetEntityByObjectId(oldObjectId)
if entity == nil {
continue
}
scene.DestroyEntity(entity.id)
delEntityIdList = append(delEntityIdList, entity.id)
}
addEntityIdList := make([]uint32, 0)
for newObjectId, newObject := range newObjectMap {
_, exist := oldObjectMap[newObjectId]
if exist {
continue
}
entityId := g.CreateConfigEntity(scene, newObjectId, newObject)
addEntityIdList = append(addEntityIdList, entityId)
}
// 发送已消失格子里的实体消失通知
g.RemoveSceneEntityNotifyToPlayer(player, proto.VisionType_VISION_TYPE_MISS, delEntityIdList)
// 发送新出现格子里的实体出现通知
g.AddSceneEntityNotify(player, proto.VisionType_VISION_TYPE_MEET, addEntityIdList, false, false)
}
}
}
func (g *GameManager) AbilityInvocationsNotify(player *model.Player, payloadMsg pb.Message) {
// logger.Debug("user ability invocations, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.AbilityInvocationsNotify)

View File

@@ -6,6 +6,7 @@ import (
"time"
"hk4e/common/constant"
"hk4e/gdconf"
gdc "hk4e/gs/config"
"hk4e/gs/model"
"hk4e/pkg/logger"
@@ -225,9 +226,50 @@ func (g *GameManager) SceneInitFinishReq(player *model.Player, payloadMsg pb.Mes
player.SceneLoadState = model.SceneInitFinish
}
func (g *GameManager) CreateConfigEntity(scene *Scene, objectId int64, entityConfig any) uint32 {
switch entityConfig.(type) {
case *gdconf.Monster:
monster := entityConfig.(*gdconf.Monster)
return scene.CreateEntityMonster(&model.Vector{
X: monster.Pos.X,
Y: monster.Pos.Y,
Z: monster.Pos.Z,
}, &model.Vector{
X: monster.Rot.X,
Y: monster.Rot.Y,
Z: monster.Rot.Z,
}, uint32(monster.MonsterId), uint8(monster.Level), g.GetTempFightPropMap(), uint32(monster.ConfigId), objectId)
case *gdconf.Npc:
npc := entityConfig.(*gdconf.Npc)
return scene.CreateEntityNpc(&model.Vector{
X: npc.Pos.X,
Y: npc.Pos.Y,
Z: npc.Pos.Z,
}, &model.Vector{
X: npc.Rot.X,
Y: npc.Rot.Y,
Z: npc.Rot.Z,
}, uint32(npc.NpcId), 0, 0, 0, uint32(npc.ConfigId), objectId)
case *gdconf.Gadget:
gadget := entityConfig.(*gdconf.Gadget)
return scene.CreateEntityGadgetNormal(&model.Vector{
X: gadget.Pos.X,
Y: gadget.Pos.Y,
Z: gadget.Pos.Z,
}, &model.Vector{
X: gadget.Rot.X,
Y: gadget.Rot.Y,
Z: gadget.Rot.Z,
}, uint32(gadget.GadgetId), uint32(gadget.ConfigId), objectId)
default:
return 0
}
}
func (g *GameManager) EnterSceneDoneReq(player *model.Player, payloadMsg pb.Message) {
logger.Debug("user enter scene done, uid: %v", player.PlayerID)
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId)
if world.multiplayer && world.IsPlayerFirstEnter(player) {
guestPostEnterSceneNotify := &proto.GuestPostEnterSceneNotify{
@@ -248,14 +290,19 @@ func (g *GameManager) EnterSceneDoneReq(player *model.Player, payloadMsg pb.Mess
activeAvatarEntityId := world.GetPlayerWorldAvatarEntityId(player, activeAvatarId)
g.AddSceneEntityNotify(player, visionType, []uint32{activeAvatarEntityId}, true, false)
// 通过aoi获取场景中在自己周围格子里的全部实体id
// entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
aoiManager, exist := WORLD_MANAGER.sceneBlockAoiMap[scene.id]
if exist {
objectList := aoiManager.GetObjectListByPos(float32(player.Pos.X), 0.0, float32(player.Pos.Z))
for objectId, entityConfig := range objectList {
g.CreateConfigEntity(scene, objectId, entityConfig)
}
}
if player.SceneJump {
visionType = proto.VisionType_VISION_TYPE_MEET
} else {
visionType = proto.VisionType_VISION_TYPE_TRANSPORT
}
entityIdList := world.GetSceneById(player.SceneId).GetEntityIdList()
entityIdList := scene.GetEntityIdList()
g.AddSceneEntityNotify(player, visionType, entityIdList, false, false)
sceneAreaWeatherNotify := &proto.SceneAreaWeatherNotify{
@@ -297,6 +344,8 @@ func (g *GameManager) EnterWorldAreaReq(player *model.Player, payloadMsg pb.Mess
logger.Debug("user enter world area, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.EnterWorldAreaReq)
logger.Debug("EnterWorldAreaReq: %v", req)
enterWorldAreaRsp := &proto.EnterWorldAreaRsp{
AreaType: req.AreaType,
AreaId: req.AreaId,
@@ -658,7 +707,7 @@ func (g *GameManager) PacketSceneEntityInfoMonster(scene *Scene, entityId uint32
LifeState: uint32(entity.lifeState),
AnimatorParaList: make([]*proto.AnimatorParameterValueInfoPair, 0),
Entity: &proto.SceneEntityInfo_Monster{
Monster: g.PacketSceneMonsterInfo(),
Monster: g.PacketSceneMonsterInfo(entity),
},
EntityClientData: new(proto.EntityClientData),
EntityAuthorityInfo: &proto.EntityAuthorityInfo{
@@ -767,11 +816,11 @@ func (g *GameManager) PacketSceneEntityInfoGadget(scene *Scene, entityId uint32)
switch entity.gadgetEntity.gadgetType {
case GADGET_TYPE_NORMAL:
sceneEntityInfo.Entity = &proto.SceneEntityInfo_Gadget{
Gadget: g.PacketSceneGadgetInfoNormal(entity.gadgetEntity.gadgetId),
Gadget: g.PacketSceneGadgetInfoNormal(entity),
}
case GADGET_TYPE_GATHER:
sceneEntityInfo.Entity = &proto.SceneEntityInfo_Gadget{
Gadget: g.PacketSceneGadgetInfoGather(entity.gadgetEntity.gadgetGatherEntity),
Gadget: g.PacketSceneGadgetInfoGather(entity),
}
case GADGET_TYPE_CLIENT:
sceneEntityInfo.Entity = &proto.SceneEntityInfo_Gadget{
@@ -821,14 +870,14 @@ func (g *GameManager) PacketSceneAvatarInfo(scene *Scene, player *model.Player,
return sceneAvatarInfo
}
func (g *GameManager) PacketSceneMonsterInfo() *proto.SceneMonsterInfo {
func (g *GameManager) PacketSceneMonsterInfo(entity *Entity) *proto.SceneMonsterInfo {
sceneMonsterInfo := &proto.SceneMonsterInfo{
MonsterId: 20011301,
MonsterId: entity.monsterEntity.monsterId,
AuthorityPeerId: 1,
BornType: proto.MonsterBornType_MONSTER_BORN_TYPE_DEFAULT,
BlockId: 3001,
TitleId: 3001,
SpecialNameId: 40,
// BlockId: 3001,
// TitleId: 3001,
// SpecialNameId: 40,
}
return sceneMonsterInfo
}
@@ -843,30 +892,30 @@ func (g *GameManager) PacketSceneNpcInfo(entity *NpcEntity) *proto.SceneNpcInfo
return sceneNpcInfo
}
func (g *GameManager) PacketSceneGadgetInfoNormal(gadgetId uint32) *proto.SceneGadgetInfo {
func (g *GameManager) PacketSceneGadgetInfoNormal(entity *Entity) *proto.SceneGadgetInfo {
sceneGadgetInfo := &proto.SceneGadgetInfo{
GadgetId: gadgetId,
GroupId: 133220271,
ConfigId: 271003,
GadgetState: 901,
GadgetId: entity.gadgetEntity.gadgetId,
GroupId: 0,
ConfigId: entity.configId,
GadgetState: 0,
IsEnableInteract: true,
AuthorityPeerId: 1,
}
return sceneGadgetInfo
}
func (g *GameManager) PacketSceneGadgetInfoGather(gadgetGatherEntity *GadgetGatherEntity) *proto.SceneGadgetInfo {
gather, ok := gdc.CONF.GatherDataMap[int32(gadgetGatherEntity.gatherId)]
func (g *GameManager) PacketSceneGadgetInfoGather(entity *Entity) *proto.SceneGadgetInfo {
gather, ok := gdc.CONF.GatherDataMap[int32(entity.gadgetEntity.gadgetGatherEntity.gatherId)]
if !ok {
logger.Error("gather data error, gatherId: %v", gadgetGatherEntity.gatherId)
logger.Error("gather data error, gatherId: %v", entity.gadgetEntity.gadgetGatherEntity.gatherId)
return new(proto.SceneGadgetInfo)
}
sceneGadgetInfo := &proto.SceneGadgetInfo{
GadgetId: uint32(gather.GadgetId),
// GroupId: 133003011,
// ConfigId: 11001,
GadgetId: entity.gadgetEntity.gadgetId,
GroupId: 0,
ConfigId: entity.configId,
GadgetState: 0,
IsEnableInteract: false,
IsEnableInteract: true,
AuthorityPeerId: 1,
Content: &proto.SceneGadgetInfo_GatherGadget{
GatherGadget: &proto.GatherGadgetInfo{
@@ -920,3 +969,24 @@ func (g *GameManager) PacketDelTeamEntityNotify(scene *Scene, player *model.Play
}
return delTeamEntityNotify
}
func (g *GameManager) GetTempFightPropMap() map[uint32]float32 {
fpm := map[uint32]float32{
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP): float32(72.91699),
uint32(constant.FightPropertyConst.FIGHT_PROP_PHYSICAL_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_DEFENSE): float32(505.0),
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK): float32(45.679916),
uint32(constant.FightPropertyConst.FIGHT_PROP_ICE_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_ATTACK): float32(45.679916),
uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP): float32(72.91699),
uint32(constant.FightPropertyConst.FIGHT_PROP_FIRE_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_ELEC_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_WIND_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_ROCK_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_GRASS_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_WATER_SUB_HURT): float32(0.1),
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_HP): float32(72.91699),
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_DEFENSE): float32(505.0),
}
return fpm
}

View File

@@ -4,6 +4,7 @@ import (
"image"
"image/color"
"image/jpeg"
"math"
"os"
"sort"
"strconv"
@@ -213,6 +214,8 @@ func LoadVideoPlayerFile() error {
return nil
}
var OBJECT_ID_COUNTER int64 = math.MaxUint32
func (g *GameManager) VideoPlayerUpdate(rgb bool) {
err := LoadVideoPlayerFile()
if err != nil {
@@ -233,12 +236,13 @@ func (g *GameManager) VideoPlayerUpdate(rgb bool) {
for w := 0; w < SCREEN_WIDTH; w++ {
for h := 0; h < SCREEN_HEIGHT; h++ {
// 创建像素点
OBJECT_ID_COUNTER++
if rgb {
entityId := scene.CreateEntityGadgetNormal(&model.Vector{
X: leftTopPos.X - float64(w)*SCREEN_DPI,
Y: leftTopPos.Y - float64(h)*SCREEN_DPI,
Z: leftTopPos.Z,
}, uint32(FRAME_COLOR[w][h]))
}, new(model.Vector), uint32(FRAME_COLOR[w][h]), 271003, OBJECT_ID_COUNTER)
SCREEN_ENTITY_ID_LIST = append(SCREEN_ENTITY_ID_LIST, entityId)
} else {
if !FRAME[w][h] {
@@ -246,7 +250,7 @@ func (g *GameManager) VideoPlayerUpdate(rgb bool) {
X: leftTopPos.X - float64(w)*SCREEN_DPI,
Y: leftTopPos.Y - float64(h)*SCREEN_DPI,
Z: leftTopPos.Z,
}, uint32(GADGET_ID))
}, new(model.Vector), uint32(GADGET_ID), 271003, OBJECT_ID_COUNTER)
SCREEN_ENTITY_ID_LIST = append(SCREEN_ENTITY_ID_LIST, entityId)
}
}

View File

@@ -6,6 +6,7 @@ import (
"hk4e/common/constant"
"hk4e/common/mq"
"hk4e/gdconf"
"hk4e/gs/model"
"hk4e/pkg/alg"
"hk4e/pkg/logger"
@@ -16,15 +17,125 @@ import (
// 世界管理器
type WorldManager struct {
worldMap map[uint32]*World
snowflake *alg.SnowflakeWorker
aiWorld *World // 本服的Ai玩家世界
worldMap map[uint32]*World
snowflake *alg.SnowflakeWorker
aiWorld *World // 本服的Ai玩家世界
sceneBlockAoiMap map[uint32]*alg.AoiManager // 全局各场景地图的aoi管理器
}
func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) {
r = new(WorldManager)
r.worldMap = make(map[uint32]*World)
r.snowflake = snowflake
r.sceneBlockAoiMap = make(map[uint32]*alg.AoiManager)
for _, sceneConfig := range gdconf.CONF.SceneMap {
minX := int16(0)
maxX := int16(0)
minZ := int16(0)
maxZ := int16(0)
blockXLen := int16(0)
blockYLen := int16(0)
blockZLen := int16(0)
ok := true
for _, blockConfig := range sceneConfig.BlockMap {
if int16(blockConfig.BlockRange.Min.X) < minX {
minX = int16(blockConfig.BlockRange.Min.X)
}
if int16(blockConfig.BlockRange.Max.X) > maxX {
maxX = int16(blockConfig.BlockRange.Max.X)
}
if int16(blockConfig.BlockRange.Min.Z) < minZ {
minZ = int16(blockConfig.BlockRange.Min.Z)
}
if int16(blockConfig.BlockRange.Max.Z) > maxZ {
maxZ = int16(blockConfig.BlockRange.Max.Z)
}
xLen := int16(blockConfig.BlockRange.Max.X - blockConfig.BlockRange.Min.X)
yLen := int16(blockConfig.BlockRange.Max.Y - blockConfig.BlockRange.Min.Y)
zLen := int16(blockConfig.BlockRange.Max.Z - blockConfig.BlockRange.Min.Z)
if blockXLen == 0 {
blockXLen = xLen
} else {
if blockXLen != xLen {
ok = false
break
}
}
if blockYLen == 0 {
blockYLen = yLen
} else {
if blockYLen != yLen {
ok = false
break
}
}
if blockZLen == 0 {
blockZLen = zLen
} else {
if blockZLen != zLen {
ok = false
break
}
}
}
if !ok {
continue
}
numX := int16(0)
if blockXLen != 0 {
if blockXLen > 32 {
blockXLen = 32
}
numX = (maxX - minX) / blockXLen
} else {
numX = 1
}
if numX == 0 {
numX = 1
}
numZ := int16(0)
if blockZLen != 0 {
if blockZLen > 32 {
blockZLen = 32
}
numZ = (maxZ - minZ) / blockZLen
} else {
numZ = 1
}
if numZ == 0 {
numZ = 1
}
aoiManager := alg.NewAoiManager()
aoiManager.SetAoiRange(minX, maxX, -1.0, 1.0, minZ, maxZ)
aoiManager.Init3DRectAoiManager(numX, 1, numZ)
for _, blockConfig := range sceneConfig.BlockMap {
for _, groupConfig := range blockConfig.GroupMap {
for _, monsterConfig := range groupConfig.MonsterList {
aoiManager.AddObjectToGridByPos(r.snowflake.GenId(), monsterConfig,
float32(monsterConfig.Pos.X),
float32(0.0),
float32(monsterConfig.Pos.Z))
}
for _, npcConfig := range groupConfig.NpcList {
aoiManager.AddObjectToGridByPos(r.snowflake.GenId(), npcConfig,
float32(npcConfig.Pos.X),
float32(0.0),
float32(npcConfig.Pos.Z))
}
for _, gadgetConfig := range groupConfig.GadgetList {
aoiManager.AddObjectToGridByPos(r.snowflake.GenId(), gadgetConfig,
float32(gadgetConfig.Pos.X),
float32(0.0),
float32(gadgetConfig.Pos.Z))
}
}
}
if sceneConfig.Id == 3 {
logger.Info("init scene aoi mgr, scene: %v", sceneConfig.Id)
aoiManager.AoiInfoLog(false)
}
r.sceneBlockAoiMap[uint32(sceneConfig.Id)] = aoiManager
}
return r
}
@@ -39,22 +150,15 @@ func (w *WorldManager) GetAllWorld() map[uint32]*World {
func (w *WorldManager) CreateWorld(owner *model.Player) *World {
worldId := uint32(w.snowflake.GenId())
world := &World{
id: worldId,
owner: owner,
playerMap: make(map[uint32]*model.Player),
sceneMap: make(map[uint32]*Scene),
entityIdCounter: 0,
worldLevel: 0,
multiplayer: false,
mpLevelEntityId: 0,
chatMsgList: make([]*proto.ChatInfo, 0),
// // aoi划分
// // TODO 为减少内存占用暂时去掉Y轴AOI格子划分 原来的Y轴格子数量为80
// aoiManager: aoi.NewAoiManager(
// -8000, 4000, 120,
// -2000, 2000, 1,
// -5500, 6500, 120,
// ),
id: worldId,
owner: owner,
playerMap: make(map[uint32]*model.Player),
sceneMap: make(map[uint32]*Scene),
entityIdCounter: 0,
worldLevel: 0,
multiplayer: false,
mpLevelEntityId: 0,
chatMsgList: make([]*proto.ChatInfo, 0),
playerFirstEnterMap: make(map[uint32]int64),
waitEnterPlayerMap: make(map[uint32]int64),
multiplayerTeam: CreateMultiplayerTeam(),
@@ -101,18 +205,17 @@ func (w *WorldManager) IsBigWorld(world *World) bool {
// 世界数据结构
type World struct {
id uint32
owner *model.Player
playerMap map[uint32]*model.Player
sceneMap map[uint32]*Scene
entityIdCounter uint32 // 世界的实体id生成计数器
worldLevel uint8 // 世界等级
multiplayer bool // 是否多人世界
mpLevelEntityId uint32
chatMsgList []*proto.ChatInfo // 世界聊天消息列表
// aoiManager *aoi.AoiManager // 当前世界地图的aoi管理器
playerFirstEnterMap map[uint32]int64 // 玩家第一次进入世界的时间 key:uid value:进入时间
waitEnterPlayerMap map[uint32]int64 // 进入世界的玩家等待列表 key:uid value:开始时间
id uint32
owner *model.Player
playerMap map[uint32]*model.Player
sceneMap map[uint32]*Scene
entityIdCounter uint32 // 世界的实体id生成计数器
worldLevel uint8 // 世界等级
multiplayer bool // 是否多人世界
mpLevelEntityId uint32
chatMsgList []*proto.ChatInfo // 世界聊天消息列表
playerFirstEnterMap map[uint32]int64 // 玩家第一次进入世界的时间 key:uid value:进入时间
waitEnterPlayerMap map[uint32]int64 // 进入世界的玩家等待列表 key:uid value:开始时间
multiplayerTeam *MultiplayerTeam
peerList []*model.Player // 玩家编号列表
}
@@ -534,13 +637,14 @@ func (w *World) PlayerEnter(player *model.Player) {
func (w *World) CreateScene(sceneId uint32) *Scene {
scene := &Scene{
id: sceneId,
world: w,
playerMap: make(map[uint32]*model.Player),
entityMap: make(map[uint32]*Entity),
gameTime: 18 * 60,
createTime: time.Now().UnixMilli(),
meeoIndex: 0,
id: sceneId,
world: w,
playerMap: make(map[uint32]*model.Player),
entityMap: make(map[uint32]*Entity),
objectIdEntityMap: make(map[int64]*Entity),
gameTime: 18 * 60,
createTime: time.Now().UnixMilli(),
meeoIndex: 0,
}
w.sceneMap[sceneId] = scene
return scene
@@ -557,13 +661,14 @@ func (w *World) GetSceneById(sceneId uint32) *Scene {
// 场景数据结构
type Scene struct {
id uint32
world *World
playerMap map[uint32]*model.Player
entityMap map[uint32]*Entity
gameTime uint32 // 游戏内提瓦特大陆的时间
createTime int64
meeoIndex uint32 // 客户端风元素染色同步协议的计数器
id uint32
world *World
playerMap map[uint32]*model.Player
entityMap map[uint32]*Entity
objectIdEntityMap map[int64]*Entity
gameTime uint32 // 游戏内提瓦特大陆的时间
createTime int64
meeoIndex uint32 // 客户端风元素染色同步协议的计数器
}
func (s *Scene) GetAllPlayer() map[uint32]*model.Player {
@@ -580,6 +685,7 @@ type AvatarEntity struct {
}
type MonsterEntity struct {
monsterId uint32
}
type NpcEntity struct {
@@ -643,6 +749,8 @@ type Entity struct {
monsterEntity *MonsterEntity
npcEntity *NpcEntity
gadgetEntity *GadgetEntity
configId uint32
objectId int64
}
type Attack struct {
@@ -761,9 +869,6 @@ func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32
},
}
s.entityMap[entity.id] = entity
// if avatarId == s.world.GetPlayerActiveAvatarId(player) {
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
// }
MESSAGE_QUEUE.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight,
EventId: mq.FightRoutineAddEntity,
@@ -797,24 +902,32 @@ func (s *Scene) CreateEntityWeapon() uint32 {
return entity.id
}
func (s *Scene) CreateEntityMonster(pos *model.Vector, level uint8, fightProp map[uint32]float32) uint32 {
func (s *Scene) CreateEntityMonster(pos, rot *model.Vector, monsterId uint32, level uint8, fightProp map[uint32]float32, configId uint32, objectId int64) uint32 {
_, exist := s.objectIdEntityMap[objectId]
if exist {
return 0
}
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.MONSTER)
entity := &Entity{
id: entityId,
scene: s,
lifeState: constant.LifeStateConst.LIFE_ALIVE,
pos: pos,
rot: new(model.Vector),
rot: rot,
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
fightProp: fightProp,
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER),
level: level,
monsterEntity: &MonsterEntity{},
monsterEntity: &MonsterEntity{
monsterId: monsterId,
},
configId: configId,
objectId: objectId,
}
s.entityMap[entity.id] = entity
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
s.objectIdEntityMap[objectId] = entity
MESSAGE_QUEUE.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight,
EventId: mq.FightRoutineAddEntity,
@@ -827,7 +940,11 @@ func (s *Scene) CreateEntityMonster(pos *model.Vector, level uint8, fightProp ma
return entity.id
}
func (s *Scene) CreateEntityNpc(pos, rot *model.Vector, npcId, roomId, parentQuestId, blockId uint32) uint32 {
func (s *Scene) CreateEntityNpc(pos, rot *model.Vector, npcId, roomId, parentQuestId, blockId, configId uint32, objectId int64) uint32 {
_, exist := s.objectIdEntityMap[objectId]
if exist {
return 0
}
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.NPC)
entity := &Entity{
id: entityId,
@@ -851,20 +968,26 @@ func (s *Scene) CreateEntityNpc(pos, rot *model.Vector, npcId, roomId, parentQue
ParentQuestId: parentQuestId,
BlockId: blockId,
},
configId: configId,
objectId: objectId,
}
s.entityMap[entity.id] = entity
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
s.objectIdEntityMap[objectId] = entity
return entity.id
}
func (s *Scene) CreateEntityGadgetNormal(pos *model.Vector, gadgetId uint32) uint32 {
func (s *Scene) CreateEntityGadgetNormal(pos, rot *model.Vector, gadgetId uint32, configId uint32, objectId int64) uint32 {
_, exist := s.objectIdEntityMap[objectId]
if exist {
return 0
}
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.GADGET)
entity := &Entity{
id: entityId,
scene: s,
lifeState: constant.LifeStateConst.LIFE_ALIVE,
pos: pos,
rot: new(model.Vector),
rot: rot,
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
@@ -879,20 +1002,26 @@ func (s *Scene) CreateEntityGadgetNormal(pos *model.Vector, gadgetId uint32) uin
gadgetId: gadgetId,
gadgetType: GADGET_TYPE_NORMAL,
},
configId: configId,
objectId: objectId,
}
s.entityMap[entity.id] = entity
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
s.objectIdEntityMap[objectId] = entity
return entity.id
}
func (s *Scene) CreateEntityGadgetGather(pos *model.Vector, gatherId uint32) uint32 {
func (s *Scene) CreateEntityGadgetGather(pos, rot *model.Vector, gadgetId uint32, gatherId uint32, configId uint32, objectId int64) uint32 {
_, exist := s.objectIdEntityMap[objectId]
if exist {
return 0
}
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.GADGET)
entity := &Entity{
id: entityId,
scene: s,
lifeState: constant.LifeStateConst.LIFE_ALIVE,
pos: pos,
rot: new(model.Vector),
rot: rot,
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
@@ -904,14 +1033,17 @@ func (s *Scene) CreateEntityGadgetGather(pos *model.Vector, gatherId uint32) uin
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_GADGET),
level: 0,
gadgetEntity: &GadgetEntity{
gadgetId: gadgetId,
gadgetType: GADGET_TYPE_GATHER,
gadgetGatherEntity: &GadgetGatherEntity{
gatherId: gatherId,
},
},
configId: configId,
objectId: objectId,
}
s.entityMap[entity.id] = entity
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
s.objectIdEntityMap[objectId] = entity
return entity.id
}
@@ -945,7 +1077,6 @@ func (s *Scene) CreateEntityGadgetClient(pos, rot *model.Vector, entityId uint32
},
}
s.entityMap[entity.id] = entity
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
}
func (s *Scene) CreateEntityGadgetVehicle(uid uint32, pos, rot *model.Vector, vehicleId uint32) uint32 {
@@ -984,7 +1115,6 @@ func (s *Scene) CreateEntityGadgetVehicle(uid uint32, pos, rot *model.Vector, ve
},
}
s.entityMap[entity.id] = entity
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
return entity.id
}
@@ -993,8 +1123,8 @@ func (s *Scene) DestroyEntity(entityId uint32) {
if entity == nil {
return
}
// s.world.aoiManager.RemoveEntityIdFromGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
delete(s.entityMap, entityId)
delete(s.entityMap, entity.id)
delete(s.objectIdEntityMap, entity.objectId)
MESSAGE_QUEUE.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight,
EventId: mq.FightRoutineDelEntity,
@@ -1009,6 +1139,10 @@ func (s *Scene) GetEntity(entityId uint32) *Entity {
return s.entityMap[entityId]
}
func (s *Scene) GetEntityByObjectId(objectId int64) *Entity {
return s.objectIdEntityMap[objectId]
}
func (s *Scene) GetEntityIdList() []uint32 {
entityIdList := make([]uint32, 0)
for k := range s.entityMap {