From 2b3a152af6b154d4edc7c488ff7641220a103828 Mon Sep 17 00:00:00 2001 From: huangxiaolei <1782360262@qq.com> Date: Thu, 24 Nov 2022 14:17:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dispatch/cmd/application.toml | 2 +- gate/cmd/application.toml | 2 +- gs/game/game_manager.go | 8 +- gs/game/local_event_manager.go | 2 + gs/game/route_manager.go | 2 + gs/game/tick_manager.go | 10 +- gs/game/user_combat.go | 86 +++++----- ...mmon_handler.go => user_common_handler.go} | 0 gs/game/user_gacha.go | 6 +- gs/game/user_login.go | 22 +-- gs/game/user_map.go | 2 +- gs/game/world_manager.go | 160 +---------------- gs/game/world_static.go | 162 ++++++++++++++++++ 13 files changed, 242 insertions(+), 222 deletions(-) rename gs/game/{msg_common_handler.go => user_common_handler.go} (100%) create mode 100644 gs/game/world_static.go diff --git a/dispatch/cmd/application.toml b/dispatch/cmd/application.toml index 00121f43..08c2cd5a 100644 --- a/dispatch/cmd/application.toml +++ b/dispatch/cmd/application.toml @@ -1,7 +1,7 @@ http_port = 8080 [hk4e] -kcp_addr = "hk4e.flswld.com" +kcp_addr = "127.0.0.1" kcp_port = 22103 login_sdk_url = "https://api.flswld.com/api/v1/auth/login" diff --git a/gate/cmd/application.toml b/gate/cmd/application.toml index a5f21056..d0ba5cb2 100644 --- a/gate/cmd/application.toml +++ b/gate/cmd/application.toml @@ -1,5 +1,5 @@ [hk4e] -kcp_addr = "hk4e.flswld.com" +kcp_addr = "127.0.0.1" kcp_port = 22103 [logger] diff --git a/gs/game/game_manager.go b/gs/game/game_manager.go index 99f8dbb9..a0dd4b55 100644 --- a/gs/game/game_manager.go +++ b/gs/game/game_manager.go @@ -25,7 +25,7 @@ type GameManager struct { userManager *UserManager // 世界管理器 worldManager *WorldManager - // 游戏服务器tick + // 游戏服务器定时帧管理器 tickManager *TickManager } @@ -41,11 +41,7 @@ func NewGameManager(dao *dao.Dao, netMsgInput chan *cmd.NetMsg, netMsgOutput cha r.worldManager = NewWorldManager(r.snowflake) r.tickManager = NewTickManager(r) - //r.worldManager.worldStatic.InitTerrain() - //r.worldManager.worldStatic.Pathfinding() - //r.worldManager.worldStatic.ConvPathVectorListToAiMoveVectorList() - - // 大世界的主人 + // 创建一个公共的开放世界的AI r.OnRegOk(false, &proto.SetPlayerBornDataReq{AvatarId: 10000007, NickName: "大世界的主人"}, 1, 0) bigWorldOwner := r.userManager.GetOnlineUser(1) bigWorldOwner.SceneLoadState = model.SceneEnterDone diff --git a/gs/game/local_event_manager.go b/gs/game/local_event_manager.go index 7288e790..e2a89f40 100644 --- a/gs/game/local_event_manager.go +++ b/gs/game/local_event_manager.go @@ -1,5 +1,7 @@ package game +// 本地事件队列管理器 + const ( LoadLoginUserFromDbFinish = iota CheckUserExistOnRegFromDbFinish diff --git a/gs/game/route_manager.go b/gs/game/route_manager.go index d9bc979e..3ef5d4de 100644 --- a/gs/game/route_manager.go +++ b/gs/game/route_manager.go @@ -7,6 +7,8 @@ import ( "hk4e/protocol/cmd" ) +// 接口路由管理器 + type HandlerFunc func(player *model.Player, payloadMsg pb.Message) type RouteManager struct { diff --git a/gs/game/tick_manager.go b/gs/game/tick_manager.go index b1527743..96d6c562 100644 --- a/gs/game/tick_manager.go +++ b/gs/game/tick_manager.go @@ -10,6 +10,8 @@ import ( "time" ) +// 游戏服务器定时帧管理器 + type TickManager struct { ticker *time.Ticker tickCount uint64 @@ -77,7 +79,7 @@ func (t *TickManager) onTick10Minute(now int64) { } func (t *TickManager) onTickMinute(now int64) { - t.gameManager.ServerAnnounceNotify(100, "test123") + //t.gameManager.ServerAnnounceNotify(100, "test123") for _, world := range t.gameManager.worldManager.worldMap { for _, player := range world.playerMap { // 随机物品 @@ -149,6 +151,7 @@ func (t *TickManager) onTick5Second(now int64) { } for _, player := range world.playerMap { if world.multiplayer { + // 多人世界其他玩家的坐标位置广播 // PacketWorldPlayerLocationNotify worldPlayerLocationNotify := new(proto.WorldPlayerLocationNotify) for _, worldPlayer := range world.playerMap { @@ -201,6 +204,7 @@ func (t *TickManager) onTick5Second(now int64) { func (t *TickManager) onTickSecond(now int64) { for _, world := range t.gameManager.worldManager.worldMap { for _, player := range world.playerMap { + // 世界里所有玩家的网络延迟广播 // PacketWorldPlayerRTTNotify worldPlayerRTTNotify := new(proto.WorldPlayerRTTNotify) worldPlayerRTTNotify.PlayerRttList = make([]*proto.PlayerRTTInfo, 0) @@ -214,13 +218,15 @@ func (t *TickManager) onTickSecond(now int64) { } func (t *TickManager) onTick100MilliSecond(now int64) { - // AttackHandler + // 伤害处理和转发 for _, world := range t.gameManager.worldManager.worldMap { for _, scene := range world.sceneMap { scene.AttackHandler(t.gameManager) } } + // 服务器控制的模拟AI移动 + //bigWorldOwner := t.gameManager.userManager.GetOnlineUser(1) //bigWorld := t.gameManager.worldManager.GetBigWorld() //bigWorldScene := bigWorld.GetSceneById(3) diff --git a/gs/game/user_combat.go b/gs/game/user_combat.go index efc2cf80..3f4c61d6 100644 --- a/gs/game/user_combat.go +++ b/gs/game/user_combat.go @@ -9,7 +9,7 @@ import ( ) func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg pb.Message) { - //logger.LOG.Debug("user combat invocations, uid: %v", player.PlayerID) + logger.LOG.Debug("user combat invocations, uid: %v", player.PlayerID) req := payloadMsg.(*proto.CombatInvocationsNotify) world := g.worldManager.GetWorldByID(player.WorldId) if world == nil { @@ -18,7 +18,7 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p scene := world.GetSceneById(player.SceneId) invokeHandler := NewInvokeHandler[proto.CombatInvokeEntry]() for _, entry := range req.InvokeList { - //logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID) + logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID) switch entry.ArgumentType { case proto.CombatTypeArgument_COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT: scene.AddAttack(&Attack{ @@ -145,42 +145,42 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p player.Rot.X = float64(motionInfo.Rot.X) player.Rot.Y = float64(motionInfo.Rot.Y) player.Rot.Z = float64(motionInfo.Rot.Z) - // TODO 采集大地图地形数据 - if world.IsBigWorld() && scene.id == 3 && player.PlayerID != 1 { - if motionInfo.State == proto.MotionState_MOTION_STATE_WALK || - motionInfo.State == proto.MotionState_MOTION_STATE_RUN || - motionInfo.State == proto.MotionState_MOTION_STATE_DASH || - motionInfo.State == proto.MotionState_MOTION_STATE_CLIMB { - logger.LOG.Debug("set terr motionInfo: %v", motionInfo) - exist := g.worldManager.worldStatic.GetTerrain(int16(motionInfo.Pos.X), int16(motionInfo.Pos.Y), int16(motionInfo.Pos.Z)) - g.worldManager.worldStatic.SetTerrain(int16(motionInfo.Pos.X), int16(motionInfo.Pos.Y), int16(motionInfo.Pos.Z)) - if !exist { - // TODO 薄荷标记 - // 只给附近aoi区域的玩家广播消息 - surrPlayerList := make([]*model.Player, 0) - entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z)) - for _, entityId := range entityIdList { - entity := scene.GetEntity(entityId) - if entity == nil { - continue - } - if entity.avatarEntity != nil { - otherPlayer := g.userManager.GetOnlineUser(entity.avatarEntity.uid) - surrPlayerList = append(surrPlayerList, otherPlayer) - } - } - pos := &model.Vector{ - X: float64(int16(motionInfo.Pos.X)), - Y: float64(int16(motionInfo.Pos.Y)), - Z: float64(int16(motionInfo.Pos.Z)), - } - gadgetEntityId := scene.CreateEntityGadget(pos, 3003009) - for _, otherPlayer := range surrPlayerList { - g.AddSceneEntityNotify(otherPlayer, proto.VisionType_VISION_TYPE_BORN, []uint32{gadgetEntityId}, false) - } - } - } - } + //// TODO 采集大地图地形数据 + //if world.IsBigWorld() && scene.id == 3 && player.PlayerID != 1 { + // if motionInfo.State == proto.MotionState_MOTION_STATE_WALK || + // motionInfo.State == proto.MotionState_MOTION_STATE_RUN || + // motionInfo.State == proto.MotionState_MOTION_STATE_DASH || + // motionInfo.State == proto.MotionState_MOTION_STATE_CLIMB { + // logger.LOG.Debug("set terr motionInfo: %v", motionInfo) + // exist := g.worldManager.worldStatic.GetTerrain(int16(motionInfo.Pos.X), int16(motionInfo.Pos.Y), int16(motionInfo.Pos.Z)) + // g.worldManager.worldStatic.SetTerrain(int16(motionInfo.Pos.X), int16(motionInfo.Pos.Y), int16(motionInfo.Pos.Z)) + // if !exist { + // // TODO 薄荷标记 + // // 只给附近aoi区域的玩家广播消息 + // surrPlayerList := make([]*model.Player, 0) + // entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z)) + // for _, entityId := range entityIdList { + // entity := scene.GetEntity(entityId) + // if entity == nil { + // continue + // } + // if entity.avatarEntity != nil { + // otherPlayer := g.userManager.GetOnlineUser(entity.avatarEntity.uid) + // surrPlayerList = append(surrPlayerList, otherPlayer) + // } + // } + // pos := &model.Vector{ + // X: float64(int16(motionInfo.Pos.X)), + // Y: float64(int16(motionInfo.Pos.Y)), + // Z: float64(int16(motionInfo.Pos.Z)), + // } + // gadgetEntityId := scene.CreateEntityGadget(pos, 3003009) + // for _, otherPlayer := range surrPlayerList { + // g.AddSceneEntityNotify(otherPlayer, proto.VisionType_VISION_TYPE_BORN, []uint32{gadgetEntityId}, false) + // } + // } + // } + //} } // 更新场景实体的位置信息 sceneEntity := scene.GetEntity(entityMoveInfo.EntityId) @@ -198,7 +198,7 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p sceneEntity.moveState = uint16(motionInfo.State) sceneEntity.lastMoveSceneTimeMs = entityMoveInfo.SceneTime sceneEntity.lastMoveReliableSeq = entityMoveInfo.ReliableSeq - //logger.LOG.Debug("entity move, id: %v, pos: %v, uid: %v", sceneEntity.id, sceneEntity.pos, player.PlayerID) + logger.LOG.Debug("entity move, id: %v, pos: %v, uid: %v", sceneEntity.id, sceneEntity.pos, player.PlayerID) } invokeHandler.addEntry(entry.ForwardType, entry) default: @@ -246,7 +246,7 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p } func (g *GameManager) AbilityInvocationsNotify(player *model.Player, payloadMsg pb.Message) { - //logger.LOG.Debug("user ability invocations, uid: %v", player.PlayerID) + logger.LOG.Debug("user ability invocations, uid: %v", player.PlayerID) req := payloadMsg.(*proto.AbilityInvocationsNotify) world := g.worldManager.GetWorldByID(player.WorldId) if world == nil { @@ -255,7 +255,7 @@ func (g *GameManager) AbilityInvocationsNotify(player *model.Player, payloadMsg scene := world.GetSceneById(player.SceneId) invokeHandler := NewInvokeHandler[proto.AbilityInvokeEntry]() for _, entry := range req.Invokes { - //logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID) + logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID) invokeHandler.addEntry(entry.ForwardType, entry) } @@ -299,7 +299,7 @@ func (g *GameManager) AbilityInvocationsNotify(player *model.Player, payloadMsg } func (g *GameManager) ClientAbilityInitFinishNotify(player *model.Player, payloadMsg pb.Message) { - //logger.LOG.Debug("user client ability ok, uid: %v", player.PlayerID) + logger.LOG.Debug("user client ability ok, uid: %v", player.PlayerID) req := payloadMsg.(*proto.ClientAbilityInitFinishNotify) world := g.worldManager.GetWorldByID(player.WorldId) if world == nil { @@ -308,7 +308,7 @@ func (g *GameManager) ClientAbilityInitFinishNotify(player *model.Player, payloa scene := world.GetSceneById(player.SceneId) invokeHandler := NewInvokeHandler[proto.AbilityInvokeEntry]() for _, entry := range req.Invokes { - //logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID) + logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID) invokeHandler.addEntry(entry.ForwardType, entry) } diff --git a/gs/game/msg_common_handler.go b/gs/game/user_common_handler.go similarity index 100% rename from gs/game/msg_common_handler.go rename to gs/game/user_common_handler.go diff --git a/gs/game/user_gacha.go b/gs/game/user_gacha.go index 7a8604e5..cf8118fa 100644 --- a/gs/game/user_gacha.go +++ b/gs/game/user_gacha.go @@ -286,10 +286,10 @@ func (g *GameManager) DoGachaReq(player *model.Player, payloadMsg pb.Message) { xh := uint32(random.GetRandomInt32(0, 10)) gachaItem := new(proto.GachaItem) - gachaItem.TokenItemList = []*proto.ItemParam{{ + gachaItem.GachaItem = &proto.ItemParam{ ItemId: itemId, Count: 1, - }} + } // 星尘 if xc != 0 { g.AddUserItem(player.PlayerID, []*UserItem{{ @@ -317,7 +317,7 @@ func (g *GameManager) DoGachaReq(player *model.Player, payloadMsg pb.Message) { doGachaRsp.GachaItemList = append(doGachaRsp.GachaItemList, gachaItem) } - //logger.LOG.Debug("doGachaRsp: %v", doGachaRsp.String()) + logger.LOG.Debug("doGachaRsp: %v", doGachaRsp.String()) g.SendMsg(cmd.DoGachaRsp, player.PlayerID, player.ClientSeq, doGachaRsp) } diff --git a/gs/game/user_login.go b/gs/game/user_login.go index d89a9560..7242d388 100644 --- a/gs/game/user_login.go +++ b/gs/game/user_login.go @@ -42,17 +42,17 @@ func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq u world.AddPlayer(player, player.SceneId) player.WorldId = world.id - // TODO 薄荷标记 - if world.IsBigWorld() { - bigWorld := world.GetSceneById(3) - for pos := range g.worldManager.worldStatic.terrain { - bigWorld.CreateEntityGadget(&model.Vector{ - X: float64(pos.X), - Y: float64(pos.Y), - Z: float64(pos.Z), - }, 3003009) - } - } + //// TODO 薄荷标记 + //if world.IsBigWorld() { + // bigWorld := world.GetSceneById(3) + // for pos := range g.worldManager.worldStatic.terrain { + // bigWorld.CreateEntityGadget(&model.Vector{ + // X: float64(pos.X), + // Y: float64(pos.Y), + // Z: float64(pos.Z), + // }, 3003009) + // } + //} // PacketPlayerDataNotify playerDataNotify := new(proto.PlayerDataNotify) diff --git a/gs/game/user_map.go b/gs/game/user_map.go index 9d5ed21c..4c5bd701 100644 --- a/gs/game/user_map.go +++ b/gs/game/user_map.go @@ -147,7 +147,7 @@ func (g *GameManager) PathfindingEnterSceneReq(player *model.Player, payloadMsg } func (g *GameManager) QueryPathReq(player *model.Player, payloadMsg pb.Message) { - //logger.LOG.Debug("user query path, uid: %v", player.PlayerID) + logger.LOG.Debug("user query path, uid: %v", player.PlayerID) req := payloadMsg.(*proto.QueryPathReq) // PacketQueryPathRsp diff --git a/gs/game/world_manager.go b/gs/game/world_manager.go index 623f063e..54eebeca 100644 --- a/gs/game/world_manager.go +++ b/gs/game/world_manager.go @@ -1,11 +1,8 @@ package game import ( - "bytes" - "encoding/gob" pb "google.golang.org/protobuf/proto" "hk4e/common/utils/alg" - gdc "hk4e/gs/config" "hk4e/gs/constant" "hk4e/gs/game/aoi" "hk4e/gs/model" @@ -14,160 +11,10 @@ import ( "hk4e/protocol/proto" "math" "time" - "unsafe" ) // 世界管理器 -type MeshMapPos struct { - X int16 - Y int16 - Z int16 -} - -type WorldStatic struct { - // x y z -> if terrain exist - terrain map[MeshMapPos]bool - // x y z -> gather id - gather map[MeshMapPos]uint32 - pathfindingStartPos MeshMapPos - pathfindingEndPos MeshMapPos - pathVectorList []MeshMapPos - aiMoveMeshSpeedParam int - aiMoveVectorList []*model.Vector - aiMoveCurrIndex int -} - -func NewWorldStatic() (r *WorldStatic) { - r = new(WorldStatic) - r.terrain = make(map[MeshMapPos]bool) - r.gather = make(map[MeshMapPos]uint32) - r.InitGather() - r.pathfindingStartPos = MeshMapPos{ - X: 2747, - Y: 194, - Z: -1719, - } - r.pathfindingEndPos = MeshMapPos{ - X: 2588, - Y: 211, - Z: -1349, - } - r.pathVectorList = make([]MeshMapPos, 0) - r.aiMoveMeshSpeedParam = 3 - r.aiMoveVectorList = make([]*model.Vector, 0) - r.aiMoveCurrIndex = 0 - return r -} - -func (w *WorldStatic) ConvWSTMapToPFMap() map[alg.MeshMapPos]bool { - return *(*map[alg.MeshMapPos]bool)(unsafe.Pointer(&w.terrain)) -} - -func (w *WorldStatic) ConvWSPosToPFPos(v MeshMapPos) alg.MeshMapPos { - return alg.MeshMapPos(v) -} - -func (w *WorldStatic) ConvPFPVLToWSPVL(v []alg.MeshMapPos) []MeshMapPos { - return *(*[]MeshMapPos)(unsafe.Pointer(&v)) -} - -func (w *WorldStatic) Pathfinding() { - bfs := alg.NewBFS() - bfs.InitMap( - w.ConvWSTMapToPFMap(), - w.ConvWSPosToPFPos(w.pathfindingStartPos), - w.ConvWSPosToPFPos(w.pathfindingEndPos), - 100, - ) - pathVectorList := bfs.Pathfinding() - if pathVectorList == nil { - logger.LOG.Error("could not find path") - return - } - logger.LOG.Debug("find path success, path: %v", pathVectorList) - w.pathVectorList = w.ConvPFPVLToWSPVL(pathVectorList) -} - -func (w *WorldStatic) ConvPathVectorListToAiMoveVectorList() { - for index, currPathVector := range w.pathVectorList { - if index > 0 { - lastPathVector := w.pathVectorList[index-1] - for i := 0; i < w.aiMoveMeshSpeedParam; i++ { - w.aiMoveVectorList = append(w.aiMoveVectorList, &model.Vector{ - X: float64(lastPathVector.X) + float64(currPathVector.X-lastPathVector.X)/float64(w.aiMoveMeshSpeedParam)*float64(i), - Y: float64(lastPathVector.Y) + float64(currPathVector.Y-lastPathVector.Y)/float64(w.aiMoveMeshSpeedParam)*float64(i), - Z: float64(lastPathVector.Z) + float64(currPathVector.Z-lastPathVector.Z)/float64(w.aiMoveMeshSpeedParam)*float64(i), - }) - } - } - } -} - -func (w *WorldStatic) InitTerrain() bool { - data := gdc.CONF.ReadWorldTerrain() - decoder := gob.NewDecoder(bytes.NewReader(data)) - err := decoder.Decode(&w.terrain) - if err != nil { - logger.LOG.Error("unmarshal world terrain data error: %v", err) - return false - } - return true -} - -func (w *WorldStatic) SaveTerrain() bool { - var buffer bytes.Buffer - encoder := gob.NewEncoder(&buffer) - err := encoder.Encode(w.terrain) - if err != nil { - logger.LOG.Error("marshal world terrain data error: %v", err) - return false - } - gdc.CONF.WriteWorldTerrain(buffer.Bytes()) - return true -} - -func (w *WorldStatic) GetTerrain(x int16, y int16, z int16) (exist bool) { - pos := MeshMapPos{ - X: x, - Y: y, - Z: z, - } - exist = w.terrain[pos] - return exist -} - -func (w *WorldStatic) SetTerrain(x int16, y int16, z int16) { - pos := MeshMapPos{ - X: x, - Y: y, - Z: z, - } - w.terrain[pos] = true -} - -func (w *WorldStatic) InitGather() { -} - -func (w *WorldStatic) GetGather(x int16, y int16, z int16) (gatherId uint32, exist bool) { - pos := MeshMapPos{ - X: x, - Y: y, - Z: z, - } - gatherId, exist = w.gather[pos] - return gatherId, exist -} - -func (w *WorldStatic) SetGather(x int16, y int16, z int16, gatherId uint32) { - pos := MeshMapPos{ - X: x, - Y: y, - Z: z, - } - w.gather[pos] = gatherId -} - type WorldManager struct { worldMap map[uint32]*World snowflake *alg.SnowflakeWorker @@ -180,6 +27,9 @@ func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) { r.worldMap = make(map[uint32]*World) r.snowflake = snowflake r.worldStatic = NewWorldStatic() + r.worldStatic.InitTerrain() + //r.worldStatic.Pathfinding() + //r.worldStatic.ConvPathVectorListToAiMoveVectorList() return r } @@ -520,6 +370,8 @@ func (s *Scene) GetEntity(entityId uint32) *Entity { return s.entityMap[entityId] } +// 伤害处理和转发 + func (s *Scene) AddAttack(attack *Attack) { s.attackQueue.EnQueue(attack) } @@ -544,7 +396,7 @@ func (s *Scene) AttackHandler(gameManager *GameManager) { } attackResult := hitInfo.AttackResult - //logger.LOG.Debug("run attack handler, attackResult: %v", attackResult) + logger.LOG.Debug("run attack handler, attackResult: %v", attackResult) target := s.entityMap[attackResult.DefenseId] if target == nil { logger.LOG.Error("could not found target, defense id: %v", attackResult.DefenseId) diff --git a/gs/game/world_static.go b/gs/game/world_static.go new file mode 100644 index 00000000..c1e7a23b --- /dev/null +++ b/gs/game/world_static.go @@ -0,0 +1,162 @@ +package game + +import ( + "bytes" + "encoding/gob" + "hk4e/common/utils/alg" + gdc "hk4e/gs/config" + "hk4e/gs/model" + "hk4e/logger" + "unsafe" +) + +// 世界的静态资源坐标点数据 + +type MeshMapPos struct { + X int16 + Y int16 + Z int16 +} + +type WorldStatic struct { + // x y z -> if terrain exist + terrain map[MeshMapPos]bool + // x y z -> gather id + gather map[MeshMapPos]uint32 + pathfindingStartPos MeshMapPos + pathfindingEndPos MeshMapPos + pathVectorList []MeshMapPos + aiMoveMeshSpeedParam int + aiMoveVectorList []*model.Vector + aiMoveCurrIndex int +} + +func NewWorldStatic() (r *WorldStatic) { + r = new(WorldStatic) + r.terrain = make(map[MeshMapPos]bool) + r.gather = make(map[MeshMapPos]uint32) + r.InitGather() + r.pathfindingStartPos = MeshMapPos{ + X: 2747, + Y: 194, + Z: -1719, + } + r.pathfindingEndPos = MeshMapPos{ + X: 2588, + Y: 211, + Z: -1349, + } + r.pathVectorList = make([]MeshMapPos, 0) + r.aiMoveMeshSpeedParam = 3 + r.aiMoveVectorList = make([]*model.Vector, 0) + r.aiMoveCurrIndex = 0 + return r +} + +func (w *WorldStatic) InitTerrain() bool { + data := gdc.CONF.ReadWorldTerrain() + decoder := gob.NewDecoder(bytes.NewReader(data)) + err := decoder.Decode(&w.terrain) + if err != nil { + logger.LOG.Error("unmarshal world terrain data error: %v", err) + return false + } + return true +} + +func (w *WorldStatic) SaveTerrain() bool { + var buffer bytes.Buffer + encoder := gob.NewEncoder(&buffer) + err := encoder.Encode(w.terrain) + if err != nil { + logger.LOG.Error("marshal world terrain data error: %v", err) + return false + } + gdc.CONF.WriteWorldTerrain(buffer.Bytes()) + return true +} + +func (w *WorldStatic) GetTerrain(x int16, y int16, z int16) (exist bool) { + pos := MeshMapPos{ + X: x, + Y: y, + Z: z, + } + exist = w.terrain[pos] + return exist +} + +func (w *WorldStatic) SetTerrain(x int16, y int16, z int16) { + pos := MeshMapPos{ + X: x, + Y: y, + Z: z, + } + w.terrain[pos] = true +} + +func (w *WorldStatic) InitGather() { +} + +func (w *WorldStatic) GetGather(x int16, y int16, z int16) (gatherId uint32, exist bool) { + pos := MeshMapPos{ + X: x, + Y: y, + Z: z, + } + gatherId, exist = w.gather[pos] + return gatherId, exist +} + +func (w *WorldStatic) SetGather(x int16, y int16, z int16, gatherId uint32) { + pos := MeshMapPos{ + X: x, + Y: y, + Z: z, + } + w.gather[pos] = gatherId +} + +func (w *WorldStatic) ConvWSTMapToPFMap() map[alg.MeshMapPos]bool { + return *(*map[alg.MeshMapPos]bool)(unsafe.Pointer(&w.terrain)) +} + +func (w *WorldStatic) ConvWSPosToPFPos(v MeshMapPos) alg.MeshMapPos { + return alg.MeshMapPos(v) +} + +func (w *WorldStatic) ConvPFPVLToWSPVL(v []alg.MeshMapPos) []MeshMapPos { + return *(*[]MeshMapPos)(unsafe.Pointer(&v)) +} + +func (w *WorldStatic) Pathfinding() { + bfs := alg.NewBFS() + bfs.InitMap( + w.ConvWSTMapToPFMap(), + w.ConvWSPosToPFPos(w.pathfindingStartPos), + w.ConvWSPosToPFPos(w.pathfindingEndPos), + 100, + ) + pathVectorList := bfs.Pathfinding() + if pathVectorList == nil { + logger.LOG.Error("could not find path") + return + } + logger.LOG.Debug("find path success, path: %v", pathVectorList) + w.pathVectorList = w.ConvPFPVLToWSPVL(pathVectorList) +} + +func (w *WorldStatic) ConvPathVectorListToAiMoveVectorList() { + for index, currPathVector := range w.pathVectorList { + if index > 0 { + lastPathVector := w.pathVectorList[index-1] + for i := 0; i < w.aiMoveMeshSpeedParam; i++ { + w.aiMoveVectorList = append(w.aiMoveVectorList, &model.Vector{ + X: float64(lastPathVector.X) + float64(currPathVector.X-lastPathVector.X)/float64(w.aiMoveMeshSpeedParam)*float64(i), + Y: float64(lastPathVector.Y) + float64(currPathVector.Y-lastPathVector.Y)/float64(w.aiMoveMeshSpeedParam)*float64(i), + Z: float64(lastPathVector.Z) + float64(currPathVector.Z-lastPathVector.Z)/float64(w.aiMoveMeshSpeedParam)*float64(i), + }) + } + } + } +}