场景LUA触发器

This commit is contained in:
flswld
2023-03-02 19:32:29 +08:00
parent a7b3f41839
commit 58b98f189d
45 changed files with 1044 additions and 878 deletions

View File

@@ -1,10 +1,10 @@
package game
import (
"hk4e/common/constant"
"hk4e/gdconf"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/protocol/proto"
)
// GMTeleportPlayer 传送玩家
@@ -14,7 +14,7 @@ func (c *CommandManager) GMTeleportPlayer(userId, sceneId uint32, posX, posY, po
logger.Error("player is nil, uid: %v", userId)
return
}
GAME_MANAGER.TeleportPlayer(player, constant.EnterReasonGm, sceneId, &model.Vector{
GAME_MANAGER.TeleportPlayer(player, uint16(proto.EnterReason_ENTER_REASON_GM), sceneId, &model.Vector{
X: posX,
Y: posY,
Z: posZ,

View File

@@ -167,5 +167,7 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
}()
case ReloadGameDataConfigFinish:
gdconf.ReplaceGameDataConfig()
// TODO 参考更表一样改成异步加载
WORLD_MANAGER.LoadSceneBlockAoiMap()
}
}

View File

@@ -440,14 +440,14 @@ func (g *GameManager) PacketAvatarInfo(avatar *model.Avatar) *proto.AvatarInfo {
for _, v := range avatar.FetterList {
pbAvatar.FetterInfo.FetterList = append(pbAvatar.FetterInfo.FetterList, &proto.FetterData{
FetterId: v,
FetterState: uint32(constant.FETTER_STATE_FINISH),
FetterState: constant.FETTER_STATE_FINISH,
})
}
// 解锁全部资料
for _, v := range gdconf.GetFetterIdListByAvatarId(int32(avatar.AvatarId)) {
pbAvatar.FetterInfo.FetterList = append(pbAvatar.FetterInfo.FetterList, &proto.FetterData{
FetterId: uint32(v),
FetterState: uint32(constant.FETTER_STATE_FINISH),
FetterState: constant.FETTER_STATE_FINISH,
})
}
// 突破等级奖励

View File

@@ -314,7 +314,7 @@ func (g *GameManager) PacketAvatarEquipChangeNotifyByWeapon(avatar *model.Avatar
AvatarGuid: avatar.Guid,
ItemId: weapon.ItemId,
EquipGuid: weapon.Guid,
EquipType: uint32(constant.EQUIP_TYPE_WEAPON),
EquipType: constant.EQUIP_TYPE_WEAPON,
Weapon: &proto.SceneWeaponInfo{
EntityId: entityId,
GadgetId: uint32(weaponConfig.GadgetId),

View File

@@ -1,10 +1,14 @@
package game
import (
"math"
"hk4e/common/config"
"hk4e/common/constant"
"hk4e/common/utils"
"hk4e/gdconf"
"hk4e/gs/model"
"hk4e/pkg/alg"
"hk4e/pkg/logger"
"hk4e/pkg/reflection"
"hk4e/protocol/cmd"
@@ -147,19 +151,19 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
currHp := float32(0)
fightProp := target.GetFightProp()
if fightProp != nil {
currHp = fightProp[uint32(constant.FIGHT_PROP_CUR_HP)]
currHp = fightProp[constant.FIGHT_PROP_CUR_HP]
currHp -= damage
if currHp < 0 {
currHp = 0
}
fightProp[uint32(constant.FIGHT_PROP_CUR_HP)] = currHp
fightProp[constant.FIGHT_PROP_CUR_HP] = currHp
}
entityFightPropUpdateNotify := &proto.EntityFightPropUpdateNotify{
FightPropMap: fightProp,
EntityId: target.GetId(),
}
g.SendToWorldA(world, cmd.EntityFightPropUpdateNotify, player.ClientSeq, entityFightPropUpdateNotify)
if currHp == 0 && target.GetAvatarEntity() == nil {
if currHp == 0 && target.GetEntityType() != constant.ENTITY_TYPE_AVATAR {
scene.SetEntityLifeState(target, constant.LIFE_STATE_DEAD, proto.PlayerDieType_PLAYER_DIE_GM)
}
combatData, err := pb.Marshal(hitInfo)
@@ -195,13 +199,13 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
if sceneEntity == nil {
continue
}
if sceneEntity.GetAvatarEntity() != nil {
if sceneEntity.GetEntityType() == constant.ENTITY_TYPE_AVATAR {
// 玩家实体在移动
g.AoiPlayerMove(player, player.Pos, &model.Vector{
X: float64(motionInfo.Pos.X),
Y: float64(motionInfo.Pos.Y),
Z: float64(motionInfo.Pos.Z),
})
}, sceneEntity.GetId())
// 更新玩家的位置信息
player.Pos.X = float64(motionInfo.Pos.X)
player.Pos.Y = float64(motionInfo.Pos.Y)
@@ -223,13 +227,15 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
rot.X = float64(motionInfo.Rot.X)
rot.Y = float64(motionInfo.Rot.Y)
rot.Z = float64(motionInfo.Rot.Z)
// 载具耐力消耗
gadgetEntity := sceneEntity.GetGadgetEntity()
if gadgetEntity != nil && gadgetEntity.GetGadgetVehicleEntity() != nil {
// 处理耐力消耗
g.ImmediateStamina(player, motionInfo.State)
// 处理载具销毁请求
g.VehicleDestroyMotion(player, sceneEntity, motionInfo.State)
if sceneEntity.GetEntityType() == constant.ENTITY_TYPE_GADGET {
// 载具耐力消耗
gadgetEntity := sceneEntity.GetGadgetEntity()
if gadgetEntity.GetGadgetVehicleEntity() != nil {
// 处理耐力消耗
g.ImmediateStamina(player, motionInfo.State)
// 处理载具销毁请求
g.VehicleDestroyMotion(player, sceneEntity, motionInfo.State)
}
}
}
sceneEntity.SetMoveState(uint16(motionInfo.State))
@@ -278,67 +284,181 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
}
}
func (g *GameManager) AoiPlayerMove(player *model.Player, oldPos *model.Vector, newPos *model.Vector) {
sceneBlockAoiMap := WORLD_MANAGER.GetSceneBlockAoiMap()
aoiManager, exist := sceneBlockAoiMap[player.SceneId]
func (g *GameManager) AoiPlayerMove(player *model.Player, oldPos *model.Vector, newPos *model.Vector, entityId uint32) {
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId)
if scene == nil {
logger.Error("scene is nil, sceneId: %v", player.SceneId)
if world == nil {
logger.Error("get player world is nil, uid: %v", player.PlayerID)
return
}
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
}
scene := world.GetSceneById(player.SceneId)
sceneBlockAoiMap := WORLD_MANAGER.GetSceneBlockAoiMap()
aoiManager, exist := sceneBlockAoiMap[player.SceneId]
if !exist {
logger.Error("get scene block aoi is nil, sceneId: %v, uid: %v", player.SceneId, player.PlayerID)
return
}
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 {
// 跨越了block格子
logger.Debug("player cross grid, oldGid: %v, newGid: %v, uid: %v", oldGid, newGid, player.PlayerID)
}
// 旧位置视野范围内的group
oldVisionGroupMap := make(map[uint32]*gdconf.Group)
oldGroupList := aoiManager.GetObjectListByPos(float32(oldPos.X), 0.0, float32(oldPos.Z))
for groupId, groupAny := range oldGroupList {
group := groupAny.(*gdconf.Group)
distance2D := math.Sqrt(math.Pow(oldPos.X-float64(group.Pos.X), 2.0) + math.Pow(oldPos.Z-float64(group.Pos.Z), 2.0))
if distance2D > ENTITY_LOD {
continue
}
oldVisionGroupMap[uint32(groupId)] = group
}
// 新位置视野范围内的group
newVisionGroupMap := make(map[uint32]*gdconf.Group)
newGroupList := aoiManager.GetObjectListByPos(float32(newPos.X), 0.0, float32(newPos.Z))
for groupId, groupAny := range newGroupList {
group := groupAny.(*gdconf.Group)
distance2D := math.Sqrt(math.Pow(newPos.X-float64(group.Pos.X), 2.0) + math.Pow(newPos.Z-float64(group.Pos.Z), 2.0))
if distance2D > ENTITY_LOD {
continue
}
newVisionGroupMap[uint32(groupId)] = group
}
// 消失的场景实体
delEntityIdList := make([]uint32, 0)
for groupId, group := range oldVisionGroupMap {
_, exist := newVisionGroupMap[groupId]
if exist {
continue
}
// 旧有新没有的group即为消失的
for _, monster := range group.MonsterList {
entity := scene.GetEntityByObjectId(monster.ObjectId)
if entity == nil {
continue
}
newGridList := aoiManager.GetSurrGridListByGid(newGid)
newObjectMap := make(map[int64]any)
for _, grid := range newGridList {
tmp := grid.GetObjectList()
for k, v := range tmp {
newObjectMap[k] = v
}
scene.DestroyEntity(entity.GetId())
delEntityIdList = append(delEntityIdList, entity.GetId())
}
for _, npc := range group.NpcList {
entity := scene.GetEntityByObjectId(npc.ObjectId)
if entity == nil {
continue
}
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.GetId())
delEntityIdList = append(delEntityIdList, entity.GetId())
scene.DestroyEntity(entity.GetId())
delEntityIdList = append(delEntityIdList, entity.GetId())
}
for _, gadget := range group.GadgetList {
entity := scene.GetEntityByObjectId(gadget.ObjectId)
if entity == nil {
continue
}
addEntityIdList := make([]uint32, 0)
for newObjectId, newObject := range newObjectMap {
_, exist := oldObjectMap[newObjectId]
if exist {
continue
}
entityId := g.CreateConfigEntity(scene, newObjectId, newObject)
if entityId == 0 {
continue
}
addEntityIdList = append(addEntityIdList, entityId)
}
// 发送已消失格子里的实体消失通知
g.RemoveSceneEntityNotifyToPlayer(player, proto.VisionType_VISION_MISS, delEntityIdList)
// 发送新出现格子里的实体出现通知
g.AddSceneEntityNotify(player, proto.VisionType_VISION_MEET, addEntityIdList, false, false)
scene.DestroyEntity(entity.GetId())
delEntityIdList = append(delEntityIdList, entity.GetId())
}
}
// 出现的场景实体
addEntityIdList := make([]uint32, 0)
for groupId, group := range newVisionGroupMap {
_, exist := oldVisionGroupMap[groupId]
if exist {
continue
}
// 新有旧没有的group即为出现的
for _, monster := range group.MonsterList {
entityId := g.CreateConfigEntity(scene, monster.ObjectId, monster)
addEntityIdList = append(addEntityIdList, entityId)
}
for _, npc := range group.NpcList {
entityId := g.CreateConfigEntity(scene, npc.ObjectId, npc)
addEntityIdList = append(addEntityIdList, entityId)
}
for _, gadget := range group.GadgetList {
entityId := g.CreateConfigEntity(scene, gadget.ObjectId, gadget)
addEntityIdList = append(addEntityIdList, entityId)
}
}
// 同步客户端消失和出现的场景实体
g.RemoveSceneEntityNotifyToPlayer(player, proto.VisionType_VISION_MISS, delEntityIdList)
g.AddSceneEntityNotify(player, proto.VisionType_VISION_MEET, addEntityIdList, false, false)
// 场景区域触发器
dbQuest := player.GetDbQuest()
for _, group := range newVisionGroupMap {
for _, region := range group.RegionList {
shape := alg.NewShape()
switch uint8(region.Shape) {
case constant.REGION_SHAPE_SPHERE:
shape.NewSphere(&alg.Vector3{X: region.Pos.X, Y: region.Pos.Y, Z: region.Pos.Z}, region.Radius)
case constant.REGION_SHAPE_CUBIC:
shape.NewCubic(&alg.Vector3{X: region.Pos.X, Y: region.Pos.Y, Z: region.Pos.Z},
&alg.Vector3{X: region.Size.X, Y: region.Size.Y, Z: region.Size.Z})
case constant.REGION_SHAPE_CYLINDER:
shape.NewCylinder(&alg.Vector3{X: region.Pos.X, Y: region.Pos.Y, Z: region.Pos.Z},
region.Radius, region.Height)
case constant.REGION_SHAPE_POLYGON:
vector2PointArray := make([]*alg.Vector2, 0)
for _, vector := range region.PointArray {
// z就是y
vector2PointArray = append(vector2PointArray, &alg.Vector2{X: vector.X, Z: vector.Y})
}
shape.NewPolygon(&alg.Vector3{X: region.Pos.X, Y: region.Pos.Y, Z: region.Pos.Z},
vector2PointArray, region.Height)
}
oldPosInRegion := shape.Contain(&alg.Vector3{
X: float32(oldPos.X),
Y: float32(oldPos.Y),
Z: float32(oldPos.Z),
})
newPosInRegion := shape.Contain(&alg.Vector3{
X: float32(newPos.X),
Y: float32(newPos.Y),
Z: float32(newPos.Z),
})
if !oldPosInRegion && newPosInRegion {
// EVENT_ENTER_REGION
logger.Debug("player enter region: %v, uid: %v", region, player.PlayerID)
for _, trigger := range group.TriggerList {
if trigger.Event != constant.LUA_EVENT_ENTER_REGION {
continue
}
cond := CallLuaFunc(group.LuaState, trigger.Condition, &LuaCtx{
uid: player.PlayerID,
}, &LuaEvt{
param1: region.ConfigId,
targetEntityId: entityId,
})
if !cond {
continue
}
// TODO 这一块写得太炸裂了需要优化
for _, triggerDataConfig := range gdconf.GetTriggerDataMap() {
if triggerDataConfig.TriggerName == trigger.Name {
for _, quest := range dbQuest.GetQuestMap() {
questDataConfig := gdconf.GetQuestDataById(int32(quest.QuestId))
if questDataConfig == nil {
continue
}
for _, questCond := range questDataConfig.FinishCondList {
if questCond.Type != constant.QUEST_FINISH_COND_TYPE_TRIGGER_FIRE {
continue
}
if questCond.Param[0] != triggerDataConfig.TriggerId {
continue
}
dbQuest.ForceFinishQuest(quest.QuestId)
}
}
}
}
}
} else if oldPosInRegion && !newPosInRegion {
// EVENT_LEAVE_REGION
logger.Debug("player leave region: %v, uid: %v", region, player.PlayerID)
}
}
}
g.AcceptQuest(player, true)
}
func (g *GameManager) AbilityInvocationsNotify(player *model.Player, payloadMsg pb.Message) {

View File

@@ -63,7 +63,7 @@ func (g *GameManager) GCGStartChallenge(player *model.Player) {
g.PacketGCGGameBriefDataNotify(player, proto.GCGGameBusinessType_GCG_GAME_GUIDE_GROUP, game))
// 玩家进入GCG界面
g.TeleportPlayer(player, constant.EnterReasonDungeonEnter, 79999, new(model.Vector), new(model.Vector), 2162)
g.TeleportPlayer(player, uint16(proto.EnterReason_ENTER_REASON_DUNGEON_ENTER), 79999, new(model.Vector), new(model.Vector), 2162)
}
// GCGAskDuelReq GCG决斗请求

View File

@@ -16,11 +16,11 @@ type ChangeItem struct {
func (g *GameManager) GetAllItemDataConfig() map[int32]*gdconf.ItemData {
allItemDataConfig := make(map[int32]*gdconf.ItemData)
for itemId, itemData := range gdconf.GetItemDataMap() {
if uint16(itemData.Type) == constant.ITEM_TYPE_WEAPON {
if itemData.Type == constant.ITEM_TYPE_WEAPON {
// 排除武器
continue
}
if uint16(itemData.Type) == constant.ITEM_TYPE_RELIQUARY {
if itemData.Type == constant.ITEM_TYPE_RELIQUARY {
// 排除圣遗物
continue
}
@@ -111,7 +111,7 @@ func (g *GameManager) AddUserItem(userId uint32, itemList []*ChangeItem, isHint
if isHint {
if hintReason == 0 {
hintReason = constant.ActionReasonSubfieldDrop
hintReason = uint16(proto.ActionReasonType_ACTION_REASON_SUBFIELD_DROP)
}
itemAddHintNotify := &proto.ItemAddHintNotify{
Reason: uint32(hintReason),

View File

@@ -215,7 +215,7 @@ func (g *GameManager) PacketPlayerStoreNotify(player *model.Player) *proto.Playe
logger.Error("get item data config is nil, itemId: %v", weapon.ItemId)
continue
}
if uint16(itemDataConfig.Type) != constant.ITEM_TYPE_WEAPON {
if itemDataConfig.Type != constant.ITEM_TYPE_WEAPON {
continue
}
affixMap := make(map[uint32]uint32)
@@ -247,7 +247,7 @@ func (g *GameManager) PacketPlayerStoreNotify(player *model.Player) *proto.Playe
logger.Error("get item data config is nil, itemId: %v", reliquary.ItemId)
continue
}
if uint16(itemDataConfig.Type) != constant.ITEM_TYPE_RELIQUARY {
if itemDataConfig.Type != constant.ITEM_TYPE_RELIQUARY {
continue
}
pbItem := &proto.Item{
@@ -281,7 +281,7 @@ func (g *GameManager) PacketPlayerStoreNotify(player *model.Player) *proto.Playe
Guid: item.Guid,
Detail: nil,
}
if itemDataConfig != nil && uint16(itemDataConfig.Type) == constant.ITEM_TYPE_FURNITURE {
if itemDataConfig != nil && itemDataConfig.Type == constant.ITEM_TYPE_FURNITURE {
pbItem.Detail = &proto.Item_Furniture{
Furniture: &proto.Furniture{
Count: item.Count,

View File

@@ -3,7 +3,6 @@ package game
import (
"strconv"
"hk4e/common/constant"
"hk4e/gdconf"
"hk4e/gs/model"
"hk4e/pkg/logger"
@@ -25,7 +24,7 @@ func (g *GameManager) SceneTransToPointReq(player *model.Player, payloadMsg pb.M
// 传送玩家
sceneId := req.SceneId
g.TeleportPlayer(player, constant.EnterReasonTransPoint, sceneId, &model.Vector{
g.TeleportPlayer(player, uint16(proto.EnterReason_ENTER_REASON_TRANS_POINT), sceneId, &model.Vector{
X: pointDataConfig.TranPos.X,
Y: pointDataConfig.TranPos.Y,
Z: pointDataConfig.TranPos.Z,
@@ -55,7 +54,7 @@ func (g *GameManager) MarkMapReq(player *model.Player, payloadMsg pb.Message) {
posYInt = 300
}
// 传送玩家
g.TeleportPlayer(player, constant.EnterReasonGm, req.Mark.SceneId, &model.Vector{
g.TeleportPlayer(player, uint16(proto.EnterReason_ENTER_REASON_GM), req.Mark.SceneId, &model.Vector{
X: float64(req.Mark.Pos.X),
Y: float64(posYInt),
Z: float64(req.Mark.Pos.Z),
@@ -110,8 +109,8 @@ func (g *GameManager) TeleportPlayer(player *model.Player, enterReason uint16, s
var enterType proto.EnterType
switch enterReason {
case constant.EnterReasonDungeonEnter:
logger.Debug("player dungeon scene, scene: %v, pos: %v", player.SceneId, player.Pos)
case uint16(proto.EnterReason_ENTER_REASON_DUNGEON_ENTER):
logger.Debug("player tp to dungeon scene, sceneId: %v, pos: %v", player.SceneId, player.Pos)
enterType = proto.EnterType_ENTER_DUNGEON
default:
if jumpScene {

View File

@@ -340,7 +340,7 @@ func (g *GameManager) HostEnterMpWorld(hostPlayer *model.Player, otherUid uint32
hostPlayer,
hostPlayer,
proto.EnterType_ENTER_GOTO,
uint32(constant.EnterReasonHostFromSingleToMp),
uint32(proto.EnterReason_ENTER_REASON_HOST_FROM_SINGLE_TO_MP),
hostPlayer.SceneId,
hostPlayer.Pos,
0,

View File

@@ -72,7 +72,7 @@ func (g *GameManager) AcceptQuest(player *model.Player, isNtfClient bool) {
canAccept := true
for _, acceptCond := range questData.AcceptCondList {
switch acceptCond.Type {
case constant.QUEST_ACCEPT_COND_TYPE_QUEST_STATE_EQ:
case constant.QUEST_ACCEPT_COND_TYPE_STATE_EQUAL:
// 某个任务状态等于 参数1:任务id 参数2:任务状态
if len(acceptCond.Param) != 2 {
logger.Error("quest accept cond config format error, questId: %v", questData.QuestId)
@@ -84,7 +84,7 @@ func (g *GameManager) AcceptQuest(player *model.Player, isNtfClient bool) {
canAccept = false
break
}
if quest.State != uint32(acceptCond.Param[1]) {
if quest.State != uint8(acceptCond.Param[1]) {
canAccept = false
break
}
@@ -130,7 +130,7 @@ func (g *GameManager) PacketQuest(player *model.Player, questId uint32) *proto.Q
}
pbQuest := &proto.Quest{
QuestId: quest.QuestId,
State: quest.State,
State: uint32(quest.State),
StartTime: quest.StartTime,
ParentQuestId: uint32(questDataConfig.ParentQuestId),
StartGameTime: 0,

View File

@@ -12,7 +12,7 @@ import (
func (g *GameManager) GetAllReliquaryDataConfig() map[int32]*gdconf.ItemData {
allReliquaryDataConfig := make(map[int32]*gdconf.ItemData)
for itemId, itemData := range gdconf.GetItemDataMap() {
if uint16(itemData.Type) != constant.ITEM_TYPE_RELIQUARY {
if itemData.Type != constant.ITEM_TYPE_RELIQUARY {
continue
}
if (itemId >= 20002 && itemId <= 20004) ||

View File

@@ -19,6 +19,7 @@ import (
const (
ENTITY_MAX_BATCH_SEND_NUM = 1000 // 单次同步的最大实体数量
ENTITY_LOD = 300 // 实体加载视野距离
)
func (g *GameManager) EnterSceneReadyReq(player *model.Player, payloadMsg pb.Message) {
@@ -172,7 +173,7 @@ func (g *GameManager) SceneInitFinishReq(player *model.Player, payloadMsg pb.Mes
sceneAreaWeatherNotify := &proto.SceneAreaWeatherNotify{
WeatherAreaId: 0,
ClimateType: uint32(constant.CLIMATE_TYPE_SUNNY),
ClimateType: constant.CLIMATE_TYPE_SUNNY,
}
g.SendMsg(cmd.SceneAreaWeatherNotify, player.PlayerID, player.ClientSeq, sceneAreaWeatherNotify)
}
@@ -272,8 +273,21 @@ func (g *GameManager) EnterSceneDoneReq(player *model.Player, payloadMsg pb.Mess
aoiManager, exist := WORLD_MANAGER.GetSceneBlockAoiMap()[scene.GetId()]
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)
for _, groupAny := range objectList {
group := groupAny.(*gdconf.Group)
distance2D := math.Sqrt(math.Pow(player.Pos.X-float64(group.Pos.X), 2.0) + math.Pow(player.Pos.Z-float64(group.Pos.Z), 2.0))
if distance2D > ENTITY_LOD {
continue
}
for _, monster := range group.MonsterList {
g.CreateConfigEntity(scene, monster.ObjectId, monster)
}
for _, npc := range group.NpcList {
g.CreateConfigEntity(scene, npc.ObjectId, npc)
}
for _, gadget := range group.GadgetList {
g.CreateConfigEntity(scene, gadget.ObjectId, gadget)
}
}
}
if player.SceneJump {
@@ -293,7 +307,7 @@ func (g *GameManager) EnterSceneDoneReq(player *model.Player, payloadMsg pb.Mess
sceneAreaWeatherNotify := &proto.SceneAreaWeatherNotify{
WeatherAreaId: 0,
ClimateType: uint32(constant.CLIMATE_TYPE_SUNNY),
ClimateType: constant.CLIMATE_TYPE_SUNNY,
}
g.SendMsg(cmd.SceneAreaWeatherNotify, player.PlayerID, player.ClientSeq, sceneAreaWeatherNotify)
@@ -365,7 +379,7 @@ func (g *GameManager) SceneEntityDrownReq(player *model.Player, payloadMsg pb.Me
}
// CreateConfigEntity 创建配置表里的实体
func (g *GameManager) CreateConfigEntity(scene *Scene, objectId int64, entityConfig any) uint32 {
func (g *GameManager) CreateConfigEntity(scene *Scene, objectId uint64, entityConfig any) uint32 {
switch entityConfig.(type) {
case *gdconf.Monster:
monster := entityConfig.(*gdconf.Monster)
@@ -438,7 +452,7 @@ func (g *GameManager) PacketPlayerEnterSceneNotifyLogin(player *model.Player, en
TargetUid: player.PlayerID,
EnterSceneToken: player.EnterSceneToken,
WorldLevel: player.PropertiesMap[constant.PLAYER_PROP_PLAYER_WORLD_LEVEL],
EnterReason: uint32(constant.EnterReasonLogin),
EnterReason: uint32(proto.EnterReason_ENTER_REASON_LOGIN),
IsFirstLoginEnterScene: true,
WorldType: 1,
SceneTagIdList: make([]uint32, 0),
@@ -580,7 +594,7 @@ func (g *GameManager) AddSceneEntityNotify(player *model.Player, visionType prot
continue
}
switch entity.GetEntityType() {
case uint32(proto.ProtEntityType_PROT_ENTITY_AVATAR):
case constant.ENTITY_TYPE_AVATAR:
if visionType == proto.VisionType_VISION_MEET && entity.GetAvatarEntity().GetUid() == player.PlayerID {
continue
}
@@ -594,14 +608,14 @@ func (g *GameManager) AddSceneEntityNotify(player *model.Player, visionType prot
}
sceneEntityInfoAvatar := g.PacketSceneEntityInfoAvatar(scene, scenePlayer, world.GetPlayerActiveAvatarId(scenePlayer))
entityList = append(entityList, sceneEntityInfoAvatar)
case uint32(proto.ProtEntityType_PROT_ENTITY_WEAPON):
case uint32(proto.ProtEntityType_PROT_ENTITY_MONSTER):
case constant.ENTITY_TYPE_WEAPON:
case constant.ENTITY_TYPE_MONSTER:
sceneEntityInfoMonster := g.PacketSceneEntityInfoMonster(scene, entity.GetId())
entityList = append(entityList, sceneEntityInfoMonster)
case uint32(proto.ProtEntityType_PROT_ENTITY_NPC):
case constant.ENTITY_TYPE_NPC:
sceneEntityInfoNpc := g.PacketSceneEntityInfoNpc(scene, entity.GetId())
entityList = append(entityList, sceneEntityInfoNpc)
case uint32(proto.ProtEntityType_PROT_ENTITY_GADGET):
case constant.ENTITY_TYPE_GADGET:
sceneEntityInfoGadget := g.PacketSceneEntityInfoGadget(scene, entity.GetId())
entityList = append(entityList, sceneEntityInfoGadget)
}
@@ -628,16 +642,16 @@ func (g *GameManager) EntityFightPropUpdateNotifyBroadcast(scene *Scene, entity
func (g *GameManager) PacketFightPropMapToPbFightPropList(fightPropMap map[uint32]float32) []*proto.FightPropPair {
fightPropList := []*proto.FightPropPair{
{PropType: uint32(constant.FIGHT_PROP_BASE_HP), PropValue: fightPropMap[uint32(constant.FIGHT_PROP_BASE_HP)]},
{PropType: uint32(constant.FIGHT_PROP_BASE_ATTACK), PropValue: fightPropMap[uint32(constant.FIGHT_PROP_BASE_ATTACK)]},
{PropType: uint32(constant.FIGHT_PROP_BASE_DEFENSE), PropValue: fightPropMap[uint32(constant.FIGHT_PROP_BASE_DEFENSE)]},
{PropType: uint32(constant.FIGHT_PROP_CRITICAL), PropValue: fightPropMap[uint32(constant.FIGHT_PROP_CRITICAL)]},
{PropType: uint32(constant.FIGHT_PROP_CRITICAL_HURT), PropValue: fightPropMap[uint32(constant.FIGHT_PROP_CRITICAL_HURT)]},
{PropType: uint32(constant.FIGHT_PROP_CHARGE_EFFICIENCY), PropValue: fightPropMap[uint32(constant.FIGHT_PROP_CHARGE_EFFICIENCY)]},
{PropType: uint32(constant.FIGHT_PROP_CUR_HP), PropValue: fightPropMap[uint32(constant.FIGHT_PROP_CUR_HP)]},
{PropType: uint32(constant.FIGHT_PROP_MAX_HP), PropValue: fightPropMap[uint32(constant.FIGHT_PROP_MAX_HP)]},
{PropType: uint32(constant.FIGHT_PROP_CUR_ATTACK), PropValue: fightPropMap[uint32(constant.FIGHT_PROP_CUR_ATTACK)]},
{PropType: uint32(constant.FIGHT_PROP_CUR_DEFENSE), PropValue: fightPropMap[uint32(constant.FIGHT_PROP_CUR_DEFENSE)]},
{PropType: constant.FIGHT_PROP_BASE_HP, PropValue: fightPropMap[constant.FIGHT_PROP_BASE_HP]},
{PropType: constant.FIGHT_PROP_BASE_ATTACK, PropValue: fightPropMap[constant.FIGHT_PROP_BASE_ATTACK]},
{PropType: constant.FIGHT_PROP_BASE_DEFENSE, PropValue: fightPropMap[constant.FIGHT_PROP_BASE_DEFENSE]},
{PropType: constant.FIGHT_PROP_CRITICAL, PropValue: fightPropMap[constant.FIGHT_PROP_CRITICAL]},
{PropType: constant.FIGHT_PROP_CRITICAL_HURT, PropValue: fightPropMap[constant.FIGHT_PROP_CRITICAL_HURT]},
{PropType: constant.FIGHT_PROP_CHARGE_EFFICIENCY, PropValue: fightPropMap[constant.FIGHT_PROP_CHARGE_EFFICIENCY]},
{PropType: constant.FIGHT_PROP_CUR_HP, PropValue: fightPropMap[constant.FIGHT_PROP_CUR_HP]},
{PropType: constant.FIGHT_PROP_MAX_HP, PropValue: fightPropMap[constant.FIGHT_PROP_MAX_HP]},
{PropType: constant.FIGHT_PROP_CUR_ATTACK, PropValue: fightPropMap[constant.FIGHT_PROP_CUR_ATTACK]},
{PropType: constant.FIGHT_PROP_CUR_DEFENSE, PropValue: fightPropMap[constant.FIGHT_PROP_CUR_DEFENSE]},
}
return fightPropList
}
@@ -1053,21 +1067,21 @@ func (g *GameManager) PacketDelTeamEntityNotify(scene *Scene, player *model.Play
func (g *GameManager) GetTempFightPropMap() map[uint32]float32 {
fpm := map[uint32]float32{
uint32(constant.FIGHT_PROP_CUR_HP): float32(72.91699),
uint32(constant.FIGHT_PROP_PHYSICAL_SUB_HURT): float32(0.1),
uint32(constant.FIGHT_PROP_CUR_DEFENSE): float32(505.0),
uint32(constant.FIGHT_PROP_CUR_ATTACK): float32(45.679916),
uint32(constant.FIGHT_PROP_ICE_SUB_HURT): float32(0.1),
uint32(constant.FIGHT_PROP_BASE_ATTACK): float32(45.679916),
uint32(constant.FIGHT_PROP_MAX_HP): float32(72.91699),
uint32(constant.FIGHT_PROP_FIRE_SUB_HURT): float32(0.1),
uint32(constant.FIGHT_PROP_ELEC_SUB_HURT): float32(0.1),
uint32(constant.FIGHT_PROP_WIND_SUB_HURT): float32(0.1),
uint32(constant.FIGHT_PROP_ROCK_SUB_HURT): float32(0.1),
uint32(constant.FIGHT_PROP_GRASS_SUB_HURT): float32(0.1),
uint32(constant.FIGHT_PROP_WATER_SUB_HURT): float32(0.1),
uint32(constant.FIGHT_PROP_BASE_HP): float32(72.91699),
uint32(constant.FIGHT_PROP_BASE_DEFENSE): float32(505.0),
constant.FIGHT_PROP_CUR_HP: float32(72.91699),
constant.FIGHT_PROP_PHYSICAL_SUB_HURT: float32(0.1),
constant.FIGHT_PROP_CUR_DEFENSE: float32(505.0),
constant.FIGHT_PROP_CUR_ATTACK: float32(45.679916),
constant.FIGHT_PROP_ICE_SUB_HURT: float32(0.1),
constant.FIGHT_PROP_BASE_ATTACK: float32(45.679916),
constant.FIGHT_PROP_MAX_HP: float32(72.91699),
constant.FIGHT_PROP_FIRE_SUB_HURT: float32(0.1),
constant.FIGHT_PROP_ELEC_SUB_HURT: float32(0.1),
constant.FIGHT_PROP_WIND_SUB_HURT: float32(0.1),
constant.FIGHT_PROP_ROCK_SUB_HURT: float32(0.1),
constant.FIGHT_PROP_GRASS_SUB_HURT: float32(0.1),
constant.FIGHT_PROP_WATER_SUB_HURT: float32(0.1),
constant.FIGHT_PROP_BASE_HP: float32(72.91699),
constant.FIGHT_PROP_BASE_DEFENSE: float32(505.0),
}
return fpm
}

View File

@@ -3,7 +3,6 @@ package game
import (
"time"
"hk4e/common/constant"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/protocol/cmd"
@@ -92,7 +91,7 @@ func (g *GameManager) BuyGoodsReq(player *model.Player, payloadMsg pb.Message) {
g.AddUserItem(player.PlayerID, []*ChangeItem{{
ItemId: buyItemId,
ChangeCount: buyItemCount,
}}, true, constant.ActionReasonShop)
}}, true, uint16(proto.ActionReasonType_ACTION_REASON_SHOP))
req.Goods.BoughtNum = dbItem.GetItemCount(player, buyItemId)
buyGoodsRsp := &proto.BuyGoodsRsp{

View File

@@ -520,7 +520,7 @@ func (g *GameManager) DrownBackHandler(player *model.Player) {
// }
// }
// 传送玩家至安全位置
g.TeleportPlayer(player, constant.EnterReasonRevival, player.SceneId, pos, new(model.Vector), 0)
g.TeleportPlayer(player, uint16(proto.EnterReason_ENTER_REASON_REVIVAL), player.SceneId, pos, new(model.Vector), 0)
}
// 防止重置后又被修改
if player.StaminaInfo.DrownBackDelay != 0 {

View File

@@ -17,7 +17,7 @@ import (
func (g *GameManager) GetAllWeaponDataConfig() map[int32]*gdconf.ItemData {
allWeaponDataConfig := make(map[int32]*gdconf.ItemData)
for itemId, itemData := range gdconf.GetItemDataMap() {
if uint16(itemData.Type) != constant.ITEM_TYPE_WEAPON {
if itemData.Type != constant.ITEM_TYPE_WEAPON {
continue
}
if (itemId >= 10000 && itemId <= 10008) ||
@@ -188,7 +188,7 @@ func (g *GameManager) WeaponAwakenReq(player *model.Player, payloadMsg pb.Messag
}
// 根据精炼材料的类型做不同操作
switch itemDataConfig.Type {
case int32(constant.ITEM_TYPE_WEAPON):
case constant.ITEM_TYPE_WEAPON:
// 精炼材料为武器
// 是否拥有将被用于精炼的武器
foodWeapon, ok := player.GameObjectGuidMap[req.ItemGuid].(*model.Weapon)
@@ -211,7 +211,7 @@ func (g *GameManager) WeaponAwakenReq(player *model.Player, payloadMsg pb.Messag
}
// 消耗作为精炼材料的武器
g.CostUserWeapon(player.PlayerID, []uint64{foodWeapon.WeaponId})
case int32(constant.ITEM_TYPE_MATERIAL):
case constant.ITEM_TYPE_MATERIAL:
// 精炼材料为道具
// 是否拥有将被用于精炼的道具
item, ok := player.GameObjectGuidMap[req.ItemGuid].(*model.Item)

View File

@@ -292,7 +292,7 @@ func (t *TickManager) onTick5Second(now int64) {
for _, entityId := range scenePlayer.VehicleInfo.LastCreateEntityIdMap {
entity := scene.GetEntity(entityId)
// 确保实体类型是否为载具
if entity != nil && entity.gadgetEntity != nil && entity.gadgetEntity.gadgetVehicleEntity != nil {
if entity != nil && entity.GetEntityType() == constant.ENTITY_TYPE_GADGET && entity.gadgetEntity.gadgetVehicleEntity != nil {
vehicleLocationInfo := &proto.VehicleLocationInfo{
Rot: &proto.Vector{
X: float32(entity.rot.X),
@@ -300,7 +300,7 @@ func (t *TickManager) onTick5Second(now int64) {
Z: float32(entity.rot.Z),
},
EntityId: entity.id,
CurHp: entity.fightProp[uint32(constant.FIGHT_PROP_CUR_HP)],
CurHp: entity.fightProp[constant.FIGHT_PROP_CUR_HP],
OwnerUid: entity.gadgetEntity.gadgetVehicleEntity.owner.PlayerID,
Pos: &proto.Vector{
X: float32(entity.pos.X),
@@ -309,7 +309,7 @@ func (t *TickManager) onTick5Second(now int64) {
},
UidList: make([]uint32, 0, len(entity.gadgetEntity.gadgetVehicleEntity.memberMap)),
GadgetId: entity.gadgetEntity.gadgetVehicleEntity.vehicleId,
MaxHp: entity.fightProp[uint32(constant.FIGHT_PROP_MAX_HP)],
MaxHp: entity.fightProp[constant.FIGHT_PROP_MAX_HP],
}
for _, p := range entity.gadgetEntity.gadgetVehicleEntity.memberMap {
vehicleLocationInfo.UidList = append(vehicleLocationInfo.UidList, p.PlayerID)

View File

@@ -1,7 +1,6 @@
package game
import (
"hk4e/pkg/logger"
"image"
"image/color"
"image/jpeg"
@@ -10,6 +9,8 @@ import (
"sort"
"strconv"
"hk4e/pkg/logger"
"hk4e/gs/model"
"hk4e/protocol/proto"
@@ -215,7 +216,7 @@ func LoadVideoPlayerFile() error {
return nil
}
var OBJECT_ID_COUNTER int64 = math.MaxUint32
var OBJECT_ID_COUNTER uint64 = math.MaxUint64
func (g *GameManager) VideoPlayerUpdate(rgb bool) {
err := LoadVideoPlayerFile()

View File

@@ -31,8 +31,85 @@ 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)
r.LoadSceneBlockAoiMap()
r.multiplayerWorldNum = 0
return r
}
func (w *WorldManager) GetWorldByID(worldId uint32) *World {
return w.worldMap[worldId]
}
func (w *WorldManager) GetAllWorld() map[uint32]*World {
return w.worldMap
}
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),
playerFirstEnterMap: make(map[uint32]int64),
waitEnterPlayerMap: make(map[uint32]int64),
multiplayerTeam: CreateMultiplayerTeam(),
peerList: make([]*model.Player, 0),
}
world.mpLevelEntityId = world.GetNextWorldEntityId(constant.ENTITY_TYPE_MP_LEVEL)
w.worldMap[worldId] = world
return world
}
func (w *WorldManager) DestroyWorld(worldId uint32) {
world := w.GetWorldByID(worldId)
for _, player := range world.playerMap {
world.RemovePlayer(player)
player.WorldId = 0
}
delete(w.worldMap, worldId)
if world.multiplayer {
w.multiplayerWorldNum--
}
}
// GetAiWorld 获取本服务器的Ai世界
func (w *WorldManager) GetAiWorld() *World {
return w.aiWorld
}
// InitAiWorld 初始化Ai世界
func (w *WorldManager) InitAiWorld(owner *model.Player) {
w.aiWorld = w.GetWorldByID(owner.WorldId)
w.aiWorld.ChangeToMultiplayer()
go RunPlayAudio()
}
func (w *WorldManager) IsAiWorld(world *World) bool {
return world.id == w.aiWorld.id
}
func (w *WorldManager) IsRobotWorld(world *World) bool {
return world.owner.PlayerID < PlayerBaseUid
}
func (w *WorldManager) IsBigWorld(world *World) bool {
return (world.id == w.aiWorld.id) && (w.aiWorld.owner.PlayerID == BigWorldAiUid)
}
func (w *WorldManager) GetSceneBlockAoiMap() map[uint32]*alg.AoiManager {
return w.sceneBlockAoiMap
}
func (w *WorldManager) LoadSceneBlockAoiMap() {
w.sceneBlockAoiMap = make(map[uint32]*alg.AoiManager)
for _, sceneLuaConfig := range gdconf.GetSceneLuaConfigMap() {
// 检查各block大小是否相同 并提取出block大小
minX := int16(0)
maxX := int16(0)
minZ := int16(0)
@@ -83,13 +160,11 @@ func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) {
}
}
if !ok {
logger.Error("config scene block size not same, scene id: %v", sceneLuaConfig.Id)
continue
}
numX := int16(0)
if blockXLen != 0 {
if blockXLen > 32 {
blockXLen = 32
}
numX = (maxX - minX) / blockXLen
} else {
numX = 1
@@ -99,9 +174,6 @@ func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) {
}
numZ := int16(0)
if blockZLen != 0 {
if blockZLen > 32 {
blockZLen = 32
}
numZ = (maxZ - minZ) / blockZLen
} else {
numZ = 1
@@ -109,105 +181,20 @@ func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) {
if numZ == 0 {
numZ = 1
}
// 将每个block作为aoi格子 并在格子中放入block拥有的所有group
aoiManager := alg.NewAoiManager()
aoiManager.SetAoiRange(minX, maxX, -1.0, 1.0, minZ, maxZ)
aoiManager.Init3DRectAoiManager(numX, 1, numZ)
for _, blockConfig := range sceneLuaConfig.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))
}
for _, block := range sceneLuaConfig.BlockMap {
for _, group := range block.GroupMap {
aoiManager.AddObjectToGridByPos(int64(group.Id), group,
group.Pos.X,
0.0,
group.Pos.Z)
}
}
r.sceneBlockAoiMap[uint32(sceneLuaConfig.Id)] = aoiManager
w.sceneBlockAoiMap[uint32(sceneLuaConfig.Id)] = aoiManager
}
r.multiplayerWorldNum = 0
return r
}
func (w *WorldManager) GetWorldByID(worldId uint32) *World {
return w.worldMap[worldId]
}
func (w *WorldManager) GetAllWorld() map[uint32]*World {
return w.worldMap
}
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),
playerFirstEnterMap: make(map[uint32]int64),
waitEnterPlayerMap: make(map[uint32]int64),
multiplayerTeam: CreateMultiplayerTeam(),
peerList: make([]*model.Player, 0),
}
world.mpLevelEntityId = world.GetNextWorldEntityId(constant.ENTITY_ID_TYPE_MPLEVEL)
w.worldMap[worldId] = world
return world
}
func (w *WorldManager) DestroyWorld(worldId uint32) {
world := w.GetWorldByID(worldId)
for _, player := range world.playerMap {
world.RemovePlayer(player)
player.WorldId = 0
}
delete(w.worldMap, worldId)
if world.multiplayer {
w.multiplayerWorldNum--
}
}
// GetAiWorld 获取本服务器的Ai世界
func (w *WorldManager) GetAiWorld() *World {
return w.aiWorld
}
// InitAiWorld 初始化Ai世界
func (w *WorldManager) InitAiWorld(owner *model.Player) {
w.aiWorld = w.GetWorldByID(owner.WorldId)
w.aiWorld.ChangeToMultiplayer()
go RunPlayAudio()
}
func (w *WorldManager) IsAiWorld(world *World) bool {
return world.id == w.aiWorld.id
}
func (w *WorldManager) IsRobotWorld(world *World) bool {
return world.owner.PlayerID < PlayerBaseUid
}
func (w *WorldManager) IsBigWorld(world *World) bool {
return (world.id == w.aiWorld.id) && (w.aiWorld.owner.PlayerID == BigWorldAiUid)
}
func (w *WorldManager) GetSceneBlockAoiMap() map[uint32]*alg.AoiManager {
return w.sceneBlockAoiMap
}
func (w *WorldManager) GetMultiplayerWorldNum() uint32 {
@@ -259,7 +246,7 @@ func (w *World) GetMpLevelEntityId() uint32 {
return w.mpLevelEntityId
}
func (w *World) GetNextWorldEntityId(entityType uint16) uint32 {
func (w *World) GetNextWorldEntityId(entityType uint8) uint32 {
for {
w.entityIdCounter++
ret := (uint32(entityType) << 24) + w.entityIdCounter
@@ -484,7 +471,7 @@ func (w *World) GetPlayerTeamEntityId(player *model.Player) uint32 {
// InitPlayerTeamEntityId 初始化某玩家的本地队伍实体id
func (w *World) InitPlayerTeamEntityId(player *model.Player) {
w.multiplayerTeam.localTeamEntityMap[player.PlayerID] = w.GetNextWorldEntityId(constant.ENTITY_ID_TYPE_TEAM)
w.multiplayerTeam.localTeamEntityMap[player.PlayerID] = w.GetNextWorldEntityId(constant.ENTITY_TYPE_TEAM)
}
// GetPlayerWorldAvatarEntityId 获取某玩家在世界队伍中的某角色的实体id
@@ -735,7 +722,7 @@ func (w *World) CreateScene(sceneId uint32) *Scene {
world: w,
playerMap: make(map[uint32]*model.Player),
entityMap: make(map[uint32]*Entity),
objectIdEntityMap: make(map[int64]*Entity),
objectIdEntityMap: make(map[uint64]*Entity),
gameTime: 18 * 60,
createTime: time.Now().UnixMilli(),
meeoIndex: 0,
@@ -745,6 +732,7 @@ func (w *World) CreateScene(sceneId uint32) *Scene {
}
func (w *World) GetSceneById(sceneId uint32) *Scene {
// 场景是取时创建 可以简化代码不判空
scene, exist := w.sceneMap[sceneId]
if !exist {
scene = w.CreateScene(sceneId)

View File

@@ -18,10 +18,10 @@ type Scene struct {
world *World
playerMap map[uint32]*model.Player
entityMap map[uint32]*Entity
objectIdEntityMap map[int64]*Entity // 用于标识配置档里的唯一实体是否已被创建
gameTime uint32 // 游戏内提瓦特大陆的时间
createTime int64 // 场景创建时间
meeoIndex uint32 // 客户端风元素染色同步协议的计数器
objectIdEntityMap map[uint64]*Entity // 用于标识配置档里的唯一实体是否已被创建
gameTime uint32 // 游戏内提瓦特大陆的时间
createTime int64 // 场景创建时间
meeoIndex uint32 // 客户端风元素染色同步协议的计数器
}
func (s *Scene) GetId() uint32 {
@@ -80,7 +80,7 @@ func (s *Scene) RemovePlayer(player *model.Player) {
}
func (s *Scene) SetEntityLifeState(entity *Entity, lifeState uint16, dieType proto.PlayerDieType) {
if entity.avatarEntity != nil {
if entity.GetEntityType() == constant.ENTITY_TYPE_AVATAR {
// 获取玩家对象
player := USER_MANAGER.GetOnlineUser(entity.avatarEntity.uid)
if player == nil {
@@ -98,8 +98,8 @@ func (s *Scene) SetEntityLifeState(entity *Entity, lifeState uint16, dieType pro
if lifeState == constant.LIFE_STATE_REVIVE {
avatar.LifeState = constant.LIFE_STATE_ALIVE
// 设置血量
entity.fightProp[uint32(constant.FIGHT_PROP_CUR_HP)] = 110
GAME_MANAGER.EntityFightPropUpdateNotifyBroadcast(s, entity, uint32(constant.FIGHT_PROP_CUR_HP))
entity.fightProp[constant.FIGHT_PROP_CUR_HP] = 110
GAME_MANAGER.EntityFightPropUpdateNotifyBroadcast(s, entity, constant.FIGHT_PROP_CUR_HP)
}
avatarLifeStateChangeNotify := &proto.AvatarLifeStateChangeNotify{
@@ -118,8 +118,8 @@ func (s *Scene) SetEntityLifeState(entity *Entity, lifeState uint16, dieType pro
if lifeState == constant.LIFE_STATE_DEAD {
// 设置血量
entity.fightProp[uint32(constant.FIGHT_PROP_CUR_HP)] = 0
GAME_MANAGER.EntityFightPropUpdateNotifyBroadcast(s, entity, uint32(constant.FIGHT_PROP_CUR_HP))
entity.fightProp[constant.FIGHT_PROP_CUR_HP] = 0
GAME_MANAGER.EntityFightPropUpdateNotifyBroadcast(s, entity, constant.FIGHT_PROP_CUR_HP)
}
lifeStateChangeNotify := &proto.LifeStateChangeNotify{
@@ -139,7 +139,7 @@ func (s *Scene) SetEntityLifeState(entity *Entity, lifeState uint16, dieType pro
}
func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32 {
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_ID_TYPE_AVATAR)
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_TYPE_AVATAR)
dbAvatar := player.GetDbAvatar()
avatar, ok := dbAvatar.AvatarMap[avatarId]
if !ok {
@@ -156,7 +156,7 @@ func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
fightProp: dbAvatar.AvatarMap[avatarId].FightPropMap, // 使用角色结构的数据
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_AVATAR),
entityType: constant.ENTITY_TYPE_AVATAR,
avatarEntity: &AvatarEntity{
uid: player.PlayerID,
avatarId: avatarId,
@@ -178,7 +178,7 @@ func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32
}
func (s *Scene) CreateEntityWeapon() uint32 {
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_ID_TYPE_WEAPON)
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_TYPE_WEAPON)
entity := &Entity{
id: entityId,
scene: s,
@@ -189,18 +189,18 @@ func (s *Scene) CreateEntityWeapon() uint32 {
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
fightProp: nil,
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_WEAPON),
entityType: constant.ENTITY_TYPE_WEAPON,
}
s.CreateEntity(entity, 0)
return entity.id
}
func (s *Scene) CreateEntityMonster(pos, rot *model.Vector, monsterId uint32, level uint8, fightProp map[uint32]float32, configId uint32, objectId int64) uint32 {
func (s *Scene) CreateEntityMonster(pos, rot *model.Vector, monsterId uint32, level uint8, fightProp map[uint32]float32, configId uint32, objectId uint64) uint32 {
_, exist := s.objectIdEntityMap[objectId]
if exist {
return 0
}
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_ID_TYPE_MONSTER)
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_TYPE_MONSTER)
entity := &Entity{
id: entityId,
scene: s,
@@ -211,7 +211,7 @@ func (s *Scene) CreateEntityMonster(pos, rot *model.Vector, monsterId uint32, le
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
fightProp: fightProp,
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_MONSTER),
entityType: constant.ENTITY_TYPE_MONSTER,
level: level,
monsterEntity: &MonsterEntity{
monsterId: monsterId,
@@ -232,12 +232,12 @@ func (s *Scene) CreateEntityMonster(pos, rot *model.Vector, monsterId uint32, le
return entity.id
}
func (s *Scene) CreateEntityNpc(pos, rot *model.Vector, npcId, roomId, parentQuestId, blockId, configId uint32, objectId int64) uint32 {
func (s *Scene) CreateEntityNpc(pos, rot *model.Vector, npcId, roomId, parentQuestId, blockId, configId uint32, objectId uint64) uint32 {
_, exist := s.objectIdEntityMap[objectId]
if exist {
return 0
}
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_ID_TYPE_NPC)
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_TYPE_NPC)
entity := &Entity{
id: entityId,
scene: s,
@@ -248,11 +248,11 @@ func (s *Scene) CreateEntityNpc(pos, rot *model.Vector, npcId, roomId, parentQue
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
fightProp: map[uint32]float32{
uint32(constant.FIGHT_PROP_CUR_HP): math.MaxFloat32,
uint32(constant.FIGHT_PROP_MAX_HP): math.MaxFloat32,
uint32(constant.FIGHT_PROP_BASE_HP): float32(1),
constant.FIGHT_PROP_CUR_HP: math.MaxFloat32,
constant.FIGHT_PROP_MAX_HP: math.MaxFloat32,
constant.FIGHT_PROP_BASE_HP: float32(1),
},
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_NPC),
entityType: constant.ENTITY_TYPE_NPC,
npcEntity: &NpcEntity{
NpcId: npcId,
RoomId: roomId,
@@ -266,12 +266,12 @@ func (s *Scene) CreateEntityNpc(pos, rot *model.Vector, npcId, roomId, parentQue
return entity.id
}
func (s *Scene) CreateEntityGadgetNormal(pos, rot *model.Vector, gadgetId uint32, configId uint32, objectId int64) uint32 {
func (s *Scene) CreateEntityGadgetNormal(pos, rot *model.Vector, gadgetId uint32, configId uint32, objectId uint64) uint32 {
_, exist := s.objectIdEntityMap[objectId]
if exist {
return 0
}
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_ID_TYPE_GADGET)
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_TYPE_GADGET)
entity := &Entity{
id: entityId,
scene: s,
@@ -282,11 +282,11 @@ func (s *Scene) CreateEntityGadgetNormal(pos, rot *model.Vector, gadgetId uint32
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
fightProp: map[uint32]float32{
uint32(constant.FIGHT_PROP_CUR_HP): math.MaxFloat32,
uint32(constant.FIGHT_PROP_MAX_HP): math.MaxFloat32,
uint32(constant.FIGHT_PROP_BASE_HP): float32(1),
constant.FIGHT_PROP_CUR_HP: math.MaxFloat32,
constant.FIGHT_PROP_MAX_HP: math.MaxFloat32,
constant.FIGHT_PROP_BASE_HP: float32(1),
},
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_GADGET),
entityType: constant.ENTITY_TYPE_GADGET,
gadgetEntity: &GadgetEntity{
gadgetId: gadgetId,
gadgetType: GADGET_TYPE_NORMAL,
@@ -298,12 +298,12 @@ func (s *Scene) CreateEntityGadgetNormal(pos, rot *model.Vector, gadgetId uint32
return entity.id
}
func (s *Scene) CreateEntityGadgetGather(pos, rot *model.Vector, gadgetId uint32, gatherId uint32, configId uint32, objectId int64) uint32 {
func (s *Scene) CreateEntityGadgetGather(pos, rot *model.Vector, gadgetId uint32, gatherId uint32, configId uint32, objectId uint64) uint32 {
_, exist := s.objectIdEntityMap[objectId]
if exist {
return 0
}
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_ID_TYPE_GADGET)
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_TYPE_GADGET)
entity := &Entity{
id: entityId,
scene: s,
@@ -314,11 +314,11 @@ func (s *Scene) CreateEntityGadgetGather(pos, rot *model.Vector, gadgetId uint32
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
fightProp: map[uint32]float32{
uint32(constant.FIGHT_PROP_CUR_HP): math.MaxFloat32,
uint32(constant.FIGHT_PROP_MAX_HP): math.MaxFloat32,
uint32(constant.FIGHT_PROP_BASE_HP): float32(1),
constant.FIGHT_PROP_CUR_HP: math.MaxFloat32,
constant.FIGHT_PROP_MAX_HP: math.MaxFloat32,
constant.FIGHT_PROP_BASE_HP: float32(1),
},
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_GADGET),
entityType: constant.ENTITY_TYPE_GADGET,
gadgetEntity: &GadgetEntity{
gadgetId: gadgetId,
gadgetType: GADGET_TYPE_GATHER,
@@ -344,11 +344,11 @@ func (s *Scene) CreateEntityGadgetClient(pos, rot *model.Vector, entityId uint32
lastMoveSceneTimeMs: 0,
lastMoveReliableSeq: 0,
fightProp: map[uint32]float32{
uint32(constant.FIGHT_PROP_CUR_HP): math.MaxFloat32,
uint32(constant.FIGHT_PROP_MAX_HP): math.MaxFloat32,
uint32(constant.FIGHT_PROP_BASE_HP): float32(1),
constant.FIGHT_PROP_CUR_HP: math.MaxFloat32,
constant.FIGHT_PROP_MAX_HP: math.MaxFloat32,
constant.FIGHT_PROP_BASE_HP: float32(1),
},
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_GADGET),
entityType: constant.ENTITY_TYPE_GADGET,
gadgetEntity: &GadgetEntity{
gadgetType: GADGET_TYPE_CLIENT,
gadgetClientEntity: &GadgetClientEntity{
@@ -370,7 +370,7 @@ func (s *Scene) CreateEntityGadgetVehicle(uid uint32, pos, rot *model.Vector, ve
logger.Error("player is nil, uid: %v", uid)
return 0
}
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_ID_TYPE_GADGET)
entityId := s.world.GetNextWorldEntityId(constant.ENTITY_TYPE_GADGET)
entity := &Entity{
id: entityId,
scene: s,
@@ -382,11 +382,11 @@ func (s *Scene) CreateEntityGadgetVehicle(uid uint32, pos, rot *model.Vector, ve
lastMoveReliableSeq: 0,
fightProp: map[uint32]float32{
// TODO 以后使用配置表
uint32(constant.FIGHT_PROP_CUR_HP): 114514,
uint32(constant.FIGHT_PROP_MAX_HP): 114514,
uint32(constant.FIGHT_PROP_BASE_HP): float32(1),
constant.FIGHT_PROP_CUR_HP: 114514,
constant.FIGHT_PROP_MAX_HP: 114514,
constant.FIGHT_PROP_BASE_HP: float32(1),
},
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_GADGET),
entityType: constant.ENTITY_TYPE_GADGET,
gadgetEntity: &GadgetEntity{
gadgetType: GADGET_TYPE_VEHICLE,
gadgetVehicleEntity: &GadgetVehicleEntity{
@@ -402,7 +402,7 @@ func (s *Scene) CreateEntityGadgetVehicle(uid uint32, pos, rot *model.Vector, ve
return entity.id
}
func (s *Scene) CreateEntity(entity *Entity, objectId int64) {
func (s *Scene) CreateEntity(entity *Entity, objectId uint64) {
if len(s.entityMap) >= ENTITY_MAX_SEND_NUM && !ENTITY_NUM_UNLIMIT {
logger.Error("above max scene entity num limit: %v, id: %v, pos: %v", ENTITY_MAX_SEND_NUM, entity.id, entity.pos)
return
@@ -434,29 +434,29 @@ func (s *Scene) GetEntity(entityId uint32) *Entity {
return s.entityMap[entityId]
}
func (s *Scene) GetEntityByObjectId(objectId int64) *Entity {
func (s *Scene) GetEntityByObjectId(objectId uint64) *Entity {
return s.objectIdEntityMap[objectId]
}
// Entity 场景实体数据结构
type Entity struct {
id uint32
scene *Scene
lifeState uint16
pos *model.Vector
rot *model.Vector
moveState uint16
id uint32 // 实体id
scene *Scene // 实体归属上级场景的访问指针
lifeState uint16 // 存活状态
pos *model.Vector // 位置
rot *model.Vector // 朝向
moveState uint16 // 运动状态
lastMoveSceneTimeMs uint32
lastMoveReliableSeq uint32
fightProp map[uint32]float32
entityType uint32
level uint8
fightProp map[uint32]float32 // 战斗属性
level uint8 // 等级
entityType uint8 // 实体类型
avatarEntity *AvatarEntity
monsterEntity *MonsterEntity
npcEntity *NpcEntity
gadgetEntity *GadgetEntity
configId uint32
objectId int64
configId uint32 // 配置表相关
objectId uint64
}
func (e *Entity) GetId() uint32 {
@@ -503,14 +503,14 @@ func (e *Entity) GetFightProp() map[uint32]float32 {
return e.fightProp
}
func (e *Entity) GetEntityType() uint32 {
return e.entityType
}
func (e *Entity) GetLevel() uint8 {
return e.level
}
func (e *Entity) GetEntityType() uint8 {
return e.entityType
}
func (e *Entity) GetAvatarEntity() *AvatarEntity {
return e.avatarEntity
}

View File

@@ -30,8 +30,8 @@ type Avatar struct {
Promote uint8 // 突破等阶
Satiation uint32 // 饱食度
SatiationPenalty uint32 // 饱食度溢出
CurrHP float64 // 当前生命值
CurrEnergy float64 // 当前元素能量值
CurrHP float32 // 当前生命值
CurrEnergy float32 // 当前元素能量值
FetterList []uint32 // 资料解锁条目
SkillLevelMap map[uint32]uint32 // 技能等级数据
SkillDepotId uint32 // 技能库id
@@ -75,22 +75,22 @@ func (a *DbAvatar) InitAvatarFightProp(avatar *Avatar) {
return
}
avatar.FightPropMap = make(map[uint32]float32)
avatar.FightPropMap[uint32(constant.FIGHT_PROP_NONE)] = 0.0
avatar.FightPropMap[constant.FIGHT_PROP_NONE] = 0.0
// 白字攻防血
avatar.FightPropMap[uint32(constant.FIGHT_PROP_BASE_ATTACK)] = float32(avatarDataConfig.GetBaseAttackByLevel(avatar.Level))
avatar.FightPropMap[uint32(constant.FIGHT_PROP_BASE_DEFENSE)] = float32(avatarDataConfig.GetBaseDefenseByLevel(avatar.Level))
avatar.FightPropMap[uint32(constant.FIGHT_PROP_BASE_HP)] = float32(avatarDataConfig.GetBaseHpByLevel(avatar.Level))
avatar.FightPropMap[constant.FIGHT_PROP_BASE_ATTACK] = avatarDataConfig.GetBaseAttackByLevel(avatar.Level)
avatar.FightPropMap[constant.FIGHT_PROP_BASE_DEFENSE] = avatarDataConfig.GetBaseDefenseByLevel(avatar.Level)
avatar.FightPropMap[constant.FIGHT_PROP_BASE_HP] = avatarDataConfig.GetBaseHpByLevel(avatar.Level)
// 白字+绿字攻防血
avatar.FightPropMap[uint32(constant.FIGHT_PROP_CUR_ATTACK)] = float32(avatarDataConfig.GetBaseAttackByLevel(avatar.Level))
avatar.FightPropMap[uint32(constant.FIGHT_PROP_CUR_DEFENSE)] = float32(avatarDataConfig.GetBaseDefenseByLevel(avatar.Level))
avatar.FightPropMap[uint32(constant.FIGHT_PROP_MAX_HP)] = float32(avatarDataConfig.GetBaseHpByLevel(avatar.Level))
avatar.FightPropMap[constant.FIGHT_PROP_CUR_ATTACK] = avatarDataConfig.GetBaseAttackByLevel(avatar.Level)
avatar.FightPropMap[constant.FIGHT_PROP_CUR_DEFENSE] = avatarDataConfig.GetBaseDefenseByLevel(avatar.Level)
avatar.FightPropMap[constant.FIGHT_PROP_MAX_HP] = avatarDataConfig.GetBaseHpByLevel(avatar.Level)
// 当前血量
avatar.FightPropMap[uint32(constant.FIGHT_PROP_CUR_HP)] = float32(avatar.CurrHP)
avatar.FightPropMap[constant.FIGHT_PROP_CUR_HP] = avatar.CurrHP
// 双暴
avatar.FightPropMap[uint32(constant.FIGHT_PROP_CRITICAL)] = float32(avatarDataConfig.Critical)
avatar.FightPropMap[uint32(constant.FIGHT_PROP_CRITICAL_HURT)] = float32(avatarDataConfig.CriticalHurt)
avatar.FightPropMap[constant.FIGHT_PROP_CRITICAL] = avatarDataConfig.Critical
avatar.FightPropMap[constant.FIGHT_PROP_CRITICAL_HURT] = avatarDataConfig.CriticalHurt
// 元素充能
avatar.FightPropMap[uint32(constant.FIGHT_PROP_CHARGE_EFFICIENCY)] = 1.0
avatar.FightPropMap[constant.FIGHT_PROP_CHARGE_EFFICIENCY] = 1.0
a.SetCurrEnergy(avatar, avatar.CurrEnergy, true)
}
@@ -158,7 +158,7 @@ func (a *DbAvatar) AddAvatar(player *Player, avatarId uint32) {
a.AvatarMap[avatarId] = avatar
}
func (a *DbAvatar) SetCurrEnergy(avatar *Avatar, value float64, max bool) {
func (a *DbAvatar) SetCurrEnergy(avatar *Avatar, value float32, max bool) {
var avatarSkillDataConfig *gdconf.AvatarSkillData = nil
if avatar.AvatarId == 10000005 || avatar.AvatarId == 10000007 {
avatarSkillDepotDataConfig := gdconf.GetAvatarSkillDepotDataById(int32(avatar.SkillDepotId))
@@ -185,7 +185,7 @@ func (a *DbAvatar) SetCurrEnergy(avatar *Avatar, value float64, max bool) {
if max {
avatar.FightPropMap[uint32(elementType.CurrEnergyProp)] = float32(avatarSkillDataConfig.CostElemVal)
} else {
avatar.FightPropMap[uint32(elementType.CurrEnergyProp)] = float32(value)
avatar.FightPropMap[uint32(elementType.CurrEnergyProp)] = value
}
}

View File

@@ -16,7 +16,7 @@ type DbQuest struct {
// Quest 任务
type Quest struct {
QuestId uint32 // 任务id
State uint32 // 任务状态
State uint8 // 任务状态
AcceptTime uint32 // 接取时间
StartTime uint32 // 开始执行时间
FinishProgressList []uint32 // 任务进度
@@ -55,7 +55,7 @@ func (q *DbQuest) AddQuest(questId uint32) {
}
q.QuestMap[questId] = &Quest{
QuestId: uint32(questDataConfig.QuestId),
State: constant.QUEST_STATE_TYPE_ACCEPT,
State: constant.QUEST_STATE_UNSTARTED,
AcceptTime: uint32(time.Now().Unix()),
StartTime: 0,
FinishProgressList: nil,
@@ -69,7 +69,7 @@ func (q *DbQuest) ExecQuest(questId uint32) {
logger.Error("get quest is nil, questId: %v", questId)
return
}
if quest.State != constant.QUEST_STATE_TYPE_ACCEPT {
if quest.State != constant.QUEST_STATE_UNSTARTED {
logger.Error("invalid quest state, questId: %v, state: %v", questId, quest.State)
return
}
@@ -78,7 +78,7 @@ func (q *DbQuest) ExecQuest(questId uint32) {
logger.Error("get quest data config is nil, questId: %v", questId)
return
}
quest.State = constant.QUEST_STATE_TYPE_EXEC
quest.State = constant.QUEST_STATE_UNFINISHED
quest.StartTime = uint32(time.Now().Unix())
quest.FinishProgressList = make([]uint32, len(questDataConfig.FinishCondList))
}
@@ -100,7 +100,7 @@ func (q *DbQuest) AddQuestProgress(questId uint32, index int, progress uint32) {
logger.Error("get quest is nil, questId: %v", questId)
return
}
if quest.State != constant.QUEST_STATE_TYPE_EXEC {
if quest.State != constant.QUEST_STATE_UNFINISHED {
logger.Error("invalid quest state, questId: %v, state: %v", questId, quest.State)
return
}
@@ -115,7 +115,7 @@ func (q *DbQuest) AddQuestProgress(questId uint32, index int, progress uint32) {
}
quest.FinishProgressList[index] += progress
if quest.FinishProgressList[index] >= uint32(questDataConfig.FinishCondList[index].Count) {
quest.State = constant.QUEST_STATE_TYPE_FINISH
quest.State = constant.QUEST_STATE_FINISHED
}
}