From cfd9f3cb99286ad772a5b0aea40dbfb63bc5e87a Mon Sep 17 00:00:00 2001 From: Naruse <71993948+DevilProMT@users.noreply.github.com> Date: Wed, 16 Apr 2025 21:31:18 +0800 Subject: [PATCH] add summon unit & maze buff & refactor battle --- database/avatar/avatar_data.py | 2 +- database/player/player_data.py | 2 +- game_server/game/avatar/avatar_manager.py | 13 ---- game_server/game/battle/battle_manager.py | 22 +++++- game_server/game/scene/scene_manager.py | 77 +++++++++++++++---- game_server/handlers/EnterSceneCsReq.py | 8 +- game_server/handlers/ReplaceLineupCsReq.py | 32 +++++++- game_server/handlers/SceneCastSkillCsReq.py | 12 ++- .../resource/configdb/avatar_config.py | 9 ++- .../resource/configdb/maze_buff_config.py | 13 ++++ .../resource/configdb/summon_unit_data.py | 16 ++++ 11 files changed, 164 insertions(+), 42 deletions(-) delete mode 100644 game_server/game/avatar/avatar_manager.py create mode 100644 game_server/resource/configdb/maze_buff_config.py create mode 100644 game_server/resource/configdb/summon_unit_data.py diff --git a/database/avatar/avatar_data.py b/database/avatar/avatar_data.py index f64c5e6..7b696e7 100644 --- a/database/avatar/avatar_data.py +++ b/database/avatar/avatar_data.py @@ -104,7 +104,7 @@ class AvatarData(BaseDatabaseData): rank=get_equipment.rank if get_equipment else 0 ) ], - relic_list = [ + relic_list=[ player.inventory_manager.get(relic_id).RelicBattleProto() for type, relic_id in self.relic_ids.items() if relic_id > 0 diff --git a/database/player/player_data.py b/database/player/player_data.py index c2c807c..9315b8e 100644 --- a/database/player/player_data.py +++ b/database/player/player_data.py @@ -34,7 +34,7 @@ class PlayerData(BaseDatabaseData): current_gender: Gender = Gender.GenderMan level: int = 70 exp: int = 0 - world_level: int = 0 + world_level: int = 6 scoin: int = 0 # Credits hcoin: int = 0 # Jade mcoin: int = 0 # Crystals diff --git a/game_server/game/avatar/avatar_manager.py b/game_server/game/avatar/avatar_manager.py deleted file mode 100644 index 36a1e5b..0000000 --- a/game_server/game/avatar/avatar_manager.py +++ /dev/null @@ -1,13 +0,0 @@ -import dataclasses -from rail_proto.lib import AvatarSkillTree,EquipRelic - -@dataclasses.dataclass -class AvatarManager: - avatar_id: int - level: int - exp: int - promotion: int - rank: int - skills: list[AvatarSkillTree] - equip_id: int = 0 - relic_list: dict[int,EquipRelic] = dataclasses.field(default_factory=dict) \ No newline at end of file diff --git a/game_server/game/battle/battle_manager.py b/game_server/game/battle/battle_manager.py index c100045..fbf4359 100644 --- a/game_server/game/battle/battle_manager.py +++ b/game_server/game/battle/battle_manager.py @@ -1,4 +1,6 @@ import numpy as np + +from game_server.resource.configdb.avatar_config import AvatarConfig from game_server.resource.configdb.stage_config import StageConfig from game_server.resource import ResourceManager from rail_proto.lib import ( @@ -9,7 +11,8 @@ from rail_proto.lib import ( SceneBattleInfo, SceneMonsterWave, SceneMonster, - SceneEntityInfo + SceneEntityInfo, + BattleBuff, Avatar, ) class BattleManager: @@ -51,6 +54,20 @@ class BattleManager: for index, monster_list in enumerate(self.stages) ] + def GetMazeBuffs(self, msg: SceneCastSkillCsReq)-> list[BattleBuff]: + buffs = [] + for index, avatar_id in enumerate(self.player.lineup_manager.get(self.player.data.cur_lineup, None).avatar_list): + if avatar_id == 1407 and msg.attacked_by_entity_id >> 20 != 1407 or avatar_id == 1407 and msg.attacked_by_entity_id >> 20 == 1407 and msg.skill_index == 0: + continue + for buff,lv in ResourceManager.instance().find_by_index(AvatarConfig,avatar_id).MazeBuffs.items(): + buffs.append(BattleBuff( + id=buff, + level=lv, + owner_index=index, + wave_flag=0xffffffff + )) + return buffs + def EnterBattle(self, msg: SceneCastSkillCsReq, targets: list[int]) -> SceneCastSkillScRsp: self.stages: list[StageConfig] = [] for entity_id in targets: @@ -74,7 +91,8 @@ class BattleManager: stage_id=self.stage_id, battle_id=self.battle_id, battle_avatar_list=self.GetBattleLineup(), - monster_wave_list=self.GetBattleMonster() + monster_wave_list=self.GetBattleMonster(), + buff_list=self.GetMazeBuffs(msg) ) ) return SceneCastSkillScRsp() \ No newline at end of file diff --git a/game_server/game/scene/scene_manager.py b/game_server/game/scene/scene_manager.py index b3a3808..f05c526 100644 --- a/game_server/game/scene/scene_manager.py +++ b/game_server/game/scene/scene_manager.py @@ -3,6 +3,8 @@ from game_server.game.enums.scene.game_mode_type import GameModeTypeEnum from game_server.resource import ResourceManager from game_server.resource.configdb.maze_plane import MazePlaneData from game_server.resource.configdb.map_entrance import MapEntranceData +from game_server.resource.configdb.summon_unit_data import SummonUnitData + from game_server.game.motion.motion_info import Motion from rail_proto.lib import ( SceneInfo, @@ -12,8 +14,15 @@ from rail_proto.lib import ( SceneNpcInfo, SceneNpcMonsterInfo, SceneActorInfo, - AvatarType + AvatarType, + SceneCastSkillCsReq, + SceneGroupRefreshScNotify, + GroupRefreshInfo, + SceneGroupRefreshType, + SceneEntityRefreshInfo, SceneSummonUnitInfo ) +from utils.time import cur_timestamp_ms + class SceneManager(BaseModel): entry_id: int @@ -25,6 +34,17 @@ class SceneManager(BaseModel): entity_group_list: list[SceneEntityGroupInfo] = [] entities: dict[int,SceneEntityInfo] = {} + @staticmethod + def Actor(avatar_id,player_pos): + return SceneEntityInfo( + entity_id=avatar_id << 20, + motion=player_pos, + actor=SceneActorInfo( + base_avatar_id=avatar_id, + avatar_type=AvatarType.AVATAR_FORMAL_TYPE + ) + ) + def ToProto(self,session) -> SceneInfo: prop_entity_id = 10 npc_entity_id = 10_000 @@ -139,25 +159,50 @@ class SceneManager(BaseModel): ).ToProto() player_group = SceneEntityGroupInfo(state=0,group_id=0) for avatar_id in session.player.lineup_manager.get(session.player.data.cur_lineup).avatar_list: - player_entity = SceneEntityInfo( - inst_id=0, - entity_id=avatar_id << 20, - motion=player_pos, - actor=SceneActorInfo( - avatar_type=AvatarType.AVATAR_FORMAL_TYPE.value, - base_avatar_id=avatar_id, - uid=session.player.data.uid, - ) - ) - player_group.entity_list.append(player_entity) + player_group.entity_list.append(self.Actor(avatar_id,player_pos)) proto.entity_group_list.append(player_group) session.player.data.entry_id = self.entry_id session.player.data.plane_id = entrance.PlaneID session.player.data.floor_id = entrance.FloorID + self.plane_id = entrance.PlaneID + self.floor_id = entrance.FloorID return proto - - - - + + def SummonUnit(self,msg: SceneCastSkillCsReq,summon_id) -> SceneEntityInfo: + return SceneEntityInfo( + entity_id=msg.cast_entity_id, + motion=Motion( + x=msg.target_motion.pos.x, + y=msg.target_motion.pos.y, + z=msg.target_motion.pos.z, + rotY=msg.target_motion.rot.y + ).ToProto(), + summon_unit=SceneSummonUnitInfo( + attach_entity_id=msg.attacked_by_entity_id, + caster_entity_id=msg.attacked_by_entity_id, + summon_unit_id=summon_id, + life_time_ms=20000, + create_time_ms=cur_timestamp_ms() + ) + ) + async def GetSummonUnit(self,session, msg: SceneCastSkillCsReq): + summon_id = str(msg.attacked_by_entity_id >> 20) + "1" + summon = ResourceManager.instance().find_all_by_index(SummonUnitData, summon_id) + if summon: + summon_unit = SceneGroupRefreshScNotify( + floor_id=self.floor_id, + group_refresh_list=[ + GroupRefreshInfo( + refresh_type=SceneGroupRefreshType.SCENE_GROUP_REFRESH_TYPE_LOADED.value, + refresh_entity=[ + SceneEntityRefreshInfo( + add_entity=self.SummonUnit(msg,data.ID) + ) + for data in summon + ] + ) + ] + ) + await session.notify(summon_unit) \ No newline at end of file diff --git a/game_server/handlers/EnterSceneCsReq.py b/game_server/handlers/EnterSceneCsReq.py index fadc24f..b492aa8 100644 --- a/game_server/handlers/EnterSceneCsReq.py +++ b/game_server/handlers/EnterSceneCsReq.py @@ -1,5 +1,6 @@ import betterproto from game_server.net.session import PlayerSession +from game_server.game.scene.scene_manager import SceneManager from game_server.game.motion.motion_info import Motion from rail_proto.lib import ( EnterSceneCsReq, @@ -9,10 +10,10 @@ from rail_proto.lib import ( ) async def handle(session: PlayerSession, msg: EnterSceneCsReq) -> betterproto.Message: + session.player.scene_manager = SceneManager(entry_id=msg.entry_id) scene = session.player.scene_manager - scene.entry_id = msg.entry_id if msg.teleport_id > 0: - session.player.scene_manager.teleport_id = msg.teleport_id + scene.teleport_id = msg.teleport_id scene_proto = scene.ToProto(session) lineup = session.player.lineup_manager.get(session.player.data.cur_lineup).ToProto() session.pending_notify( @@ -23,7 +24,7 @@ async def handle(session: PlayerSession, msg: EnterSceneCsReq) -> betterproto.Me ) session.pending_notify( SceneEntityMoveScNotify( - entry_id=session.player.scene_manager.entry_id, + entry_id=scene.entry_id, motion=Motion( x=session.player.data.pos.x, y=session.player.data.pos.y, @@ -33,7 +34,6 @@ async def handle(session: PlayerSession, msg: EnterSceneCsReq) -> betterproto.Me ) ) scene.teleport_id = 0 - #session.player.data.save_player_data() return EnterSceneScRsp( retcode=0 ) \ No newline at end of file diff --git a/game_server/handlers/ReplaceLineupCsReq.py b/game_server/handlers/ReplaceLineupCsReq.py index 669de8a..e6e2e85 100644 --- a/game_server/handlers/ReplaceLineupCsReq.py +++ b/game_server/handlers/ReplaceLineupCsReq.py @@ -1,18 +1,46 @@ import betterproto from game_server.net.session import PlayerSession +from game_server.game.motion.motion_info import Motion from rail_proto.lib import ( ReplaceLineupCsReq, ReplaceLineupScRsp, - SyncLineupNotify + SyncLineupNotify, + SceneGroupRefreshScNotify, + GroupRefreshInfo, + SceneEntityRefreshInfo, + SceneGroupRefreshType ) async def handle(session: PlayerSession, msg: ReplaceLineupCsReq) -> betterproto.Message: lineup = session.player.lineup_manager.get(msg.index) lineup.avatar_list = [avatar.id for avatar in msg.lineup_slot_list] + lineup.leader_slot = msg.leader_slot await session.notify( SyncLineupNotify( lineup=lineup.ToProto() ) ) - #lineup.save_lineup() + player_pos = Motion( + x=session.player.data.pos.x, + y=session.player.data.pos.y, + z=session.player.data.pos.z, + rotY=session.player.data.rot.y + ).ToProto() + for avatar_id in lineup.avatar_list: + session.pending_notify( + SceneGroupRefreshScNotify( + floor_id=session.player.data.floor_id, + group_refresh_list=[ + GroupRefreshInfo( + refresh_type=SceneGroupRefreshType.SCENE_GROUP_REFRESH_TYPE_LOADED.value, + refresh_entity=[ + SceneEntityRefreshInfo( + add_entity=session.player.scene_manager.Actor(avatar_id, player_pos) + ) + ] + ) + ] + ) + ) + return ReplaceLineupScRsp(retcode=0) \ No newline at end of file diff --git a/game_server/handlers/SceneCastSkillCsReq.py b/game_server/handlers/SceneCastSkillCsReq.py index 91fdd1b..485db6f 100644 --- a/game_server/handlers/SceneCastSkillCsReq.py +++ b/game_server/handlers/SceneCastSkillCsReq.py @@ -15,6 +15,14 @@ async def handle(session: PlayerSession, msg: SceneCastSkillCsReq) -> betterprot if id not in targets and (id > 20000 or id < 10) ) session.player.battle_manager = BattleManager(session.player) - if msg.skill_index == 0 and targets: + + avatars_lineup = session.player.lineup_manager.get(session.player.data.cur_lineup).avatar_list + caster = msg.attacked_by_entity_id + if caster >> 20 in avatars_lineup: + if msg.skill_index > 0: + scene = session.player.scene_manager + await scene.GetSummonUnit(session,msg) + + if targets: return session.player.battle_manager.EnterBattle(msg,targets) - return SceneCastSkillScRsp(retcode=0) \ No newline at end of file + return SceneCastSkillScRsp() \ No newline at end of file diff --git a/game_server/resource/configdb/avatar_config.py b/game_server/resource/configdb/avatar_config.py index 720415b..29671ac 100644 --- a/game_server/resource/configdb/avatar_config.py +++ b/game_server/resource/configdb/avatar_config.py @@ -1,23 +1,30 @@ -from dataclasses import dataclass, field +from dataclasses import dataclass from game_server.resource.base_resource import BaseResource, T from game_server.resource.decorators import GameResource from game_server.resource.configdb.avatar_skill_tree_config import AvatarSkillTreeConfig +from game_server.resource.configdb.maze_buff_config import MazeBuffConfig @dataclass @GameResource("resources/ExcelOutput/AvatarConfig.json") class AvatarConfig(BaseResource): AvatarID: int AvatarSkills: dict[int, int] + MazeBuffs: dict[int,int] # ID and LvMax def on_load(self: T) -> bool: from game_server.resource import ResourceManager self.AvatarSkills = {} + self.MazeBuffs = {} skill_tree_config = ResourceManager.instance().find_all_by_index( AvatarSkillTreeConfig, self.AvatarID ) + for data in ResourceManager.instance().values(MazeBuffConfig): + if str(data.ID).startswith(str(self.AvatarID)): + self.MazeBuffs[data.ID] = data.LvMax + for skill in skill_tree_config: skill_id = skill.PointID skill_level = skill.MaxLevel diff --git a/game_server/resource/configdb/maze_buff_config.py b/game_server/resource/configdb/maze_buff_config.py new file mode 100644 index 0000000..74d80bb --- /dev/null +++ b/game_server/resource/configdb/maze_buff_config.py @@ -0,0 +1,13 @@ +from dataclasses import dataclass +from game_server.resource.base_resource import BaseResource +from game_server.resource.decorators import GameResource, LoadPriority +from game_server.game.enums.scene.game_mode_type import GameModeTypeEnum + +@dataclass +@GameResource("resources/ExcelOutput/MazeBuff.json",load_priority=LoadPriority.HIGH) +class MazeBuffConfig(BaseResource): + ID: int + LvMax: int + + def get_index(self) -> str: + return str(self.ID) diff --git a/game_server/resource/configdb/summon_unit_data.py b/game_server/resource/configdb/summon_unit_data.py new file mode 100644 index 0000000..85f1177 --- /dev/null +++ b/game_server/resource/configdb/summon_unit_data.py @@ -0,0 +1,16 @@ + +from dataclasses import dataclass +from game_server.resource.base_resource import BaseResource +from game_server.resource.decorators import GameResource + +@dataclass +@GameResource("resources/ExcelOutput/SummonUnitData.json") +class SummonUnitData(BaseResource): + ID: int + JsonPath: str + DestroyOnEnterBattle: bool + RemoveMazeBuffOnDestroy: bool + IsClient: bool + + def get_index(self) -> str: + return str(self.ID)