mirror of
https://github.com/MikuLeaks/KianaBH3.git
synced 2025-12-14 05:44:34 +01:00
feat: Implement commands (help,rank,maxskill)
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
from game_server.net.gateway import Gateway
|
from game_server.net.gateway import Gateway
|
||||||
|
from game_server.game.chat.command_handler import handler
|
||||||
|
|
||||||
class GameServer:
|
class GameServer:
|
||||||
def main(self, ServerIp, GameServerPort):
|
def main(self, ServerIp, GameServerPort):
|
||||||
|
handler.load_commands()
|
||||||
Gateway(ServerIp, GameServerPort)
|
Gateway(ServerIp, GameServerPort)
|
||||||
|
|||||||
0
game_server/game/chat/__init__.py
Normal file
0
game_server/game/chat/__init__.py
Normal file
16
game_server/game/chat/command/__init__.py
Normal file
16
game_server/game/chat/command/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import importlib
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
folder = "game_server/game/chat/command"
|
||||||
|
sys.path.append(os.path.dirname(folder))
|
||||||
|
|
||||||
|
for filename in os.listdir(folder):
|
||||||
|
if filename.endswith(".py") and filename != "__init__.py":
|
||||||
|
module_name = filename[:-3]
|
||||||
|
module_path = f"game_server.game.chat.command.{module_name}"
|
||||||
|
try:
|
||||||
|
importlib.import_module(module_path)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error importing module '{module_path}': {e}")
|
||||||
48
game_server/game/chat/command/max_skill.py
Normal file
48
game_server/game/chat/command/max_skill.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
from database import mongo
|
||||||
|
from lib.proto import GetAvatarDataReq, AvatarSubSkill
|
||||||
|
from game_server.net.session import Session
|
||||||
|
from game_server.resource import ResourceManager
|
||||||
|
from game_server.game.enum.data_type import DataType
|
||||||
|
from game_server.game.chat.decorators import Command
|
||||||
|
from game_server.resource.configdb.avatar_sub_skill_data import AvatarSubSkillData
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
prefix="maxskill",
|
||||||
|
usage="/maxskill {avatar_id | all} - Maximize the skills of a specific avatar. Use 'all' to maximize the skills of all avatars.",
|
||||||
|
)
|
||||||
|
async def execute(session: Session, avatar_id):
|
||||||
|
desc = getattr(execute, "usage", "No description available.")
|
||||||
|
|
||||||
|
if avatar_id == "all":
|
||||||
|
for avatar in session.player.avatars.values():
|
||||||
|
await max_out_skills_for_avatar(avatar, session)
|
||||||
|
return "All avatars' skills have been maxed out!"
|
||||||
|
|
||||||
|
if not avatar_id.isdigit():
|
||||||
|
return f"Usage: {desc}"
|
||||||
|
|
||||||
|
avatar_id = int(avatar_id)
|
||||||
|
|
||||||
|
avatar = session.player.avatars.get(avatar_id)
|
||||||
|
if not avatar:
|
||||||
|
return f"Avatar with ID {avatar_id} does not exist."
|
||||||
|
|
||||||
|
await max_out_skills_for_avatar(avatar, session)
|
||||||
|
|
||||||
|
return f"All skills for avatar {avatar_id} have been maxed out!"
|
||||||
|
|
||||||
|
async def max_out_skills_for_avatar(avatar, session:Session):
|
||||||
|
resource_manager = ResourceManager.instance()
|
||||||
|
for skill_id, skill in avatar.skill_lists.items():
|
||||||
|
sub_skills = [
|
||||||
|
data for data in resource_manager.values(AvatarSubSkillData)
|
||||||
|
if data.skillId == skill_id
|
||||||
|
]
|
||||||
|
for sub_skill_data in sub_skills:
|
||||||
|
skill.sub_skill_lists[sub_skill_data.avatarSubSkillId] = AvatarSubSkill(
|
||||||
|
sub_skill_id=sub_skill_data.avatarSubSkillId,
|
||||||
|
level=sub_skill_data.maxLv
|
||||||
|
)
|
||||||
|
|
||||||
|
mongo.save(session, DataType.AVATAR, [avatar.avatar_id])
|
||||||
|
await session.process_packet(session.create_packet(GetAvatarDataReq(avatar_id_list=[avatar.avatar_id])))
|
||||||
46
game_server/game/chat/command/rank.py
Normal file
46
game_server/game/chat/command/rank.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
from game_server.game.enum.data_type import DataType
|
||||||
|
from game_server.game.chat.decorators import Command
|
||||||
|
from game_server.net.session import Session
|
||||||
|
from database import mongo
|
||||||
|
from lib.proto import GetAvatarDataReq
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
prefix="rank",
|
||||||
|
usage="/rank {avatar_id | all} {rank} - Edit the rank of a specific avatar or use 'all' to update the rank of all avatars.",
|
||||||
|
)
|
||||||
|
async def execute(session: Session, avatar_id, rank="1"):
|
||||||
|
desc = getattr(execute, "usage", "No description available.")
|
||||||
|
|
||||||
|
if not rank.isdigit():
|
||||||
|
return f"Usage: {desc}"
|
||||||
|
|
||||||
|
if avatar_id == "all":
|
||||||
|
for avatar in session.player.avatars.values():
|
||||||
|
await update_avatar_rank(avatar, rank, session)
|
||||||
|
return f"Updated rank for all avatars to {rank}."
|
||||||
|
|
||||||
|
if not avatar_id.isdigit():
|
||||||
|
return f"Usage: {desc}"
|
||||||
|
|
||||||
|
avatar_id = int(avatar_id)
|
||||||
|
|
||||||
|
avatar = session.player.avatars.get(avatar_id)
|
||||||
|
if not avatar:
|
||||||
|
return f"Avatar with ID {avatar_id} does not exist."
|
||||||
|
|
||||||
|
await update_avatar_rank(avatar, rank, session)
|
||||||
|
|
||||||
|
return f"Updated avatar {avatar_id}'s rank to {rank}."
|
||||||
|
|
||||||
|
async def update_avatar_rank(avatar, rank, session:Session):
|
||||||
|
rank = int(rank)
|
||||||
|
if rank < 1:
|
||||||
|
rank = 1
|
||||||
|
if rank > 5:
|
||||||
|
rank = 5
|
||||||
|
|
||||||
|
avatar.star = rank
|
||||||
|
|
||||||
|
mongo.save(session, DataType.AVATAR, [avatar.avatar_id])
|
||||||
|
|
||||||
|
await session.process_packet(session.create_packet(GetAvatarDataReq(avatar_id_list=[avatar.avatar_id])))
|
||||||
53
game_server/game/chat/command_handler.py
Normal file
53
game_server/game/chat/command_handler.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
from utils.logger import Info
|
||||||
|
from game_server.game.chat.decorators import command_registry
|
||||||
|
from game_server.net.session import Session
|
||||||
|
import game_server.game.chat.command # noqa: F401
|
||||||
|
|
||||||
|
|
||||||
|
class CommandHandler:
|
||||||
|
def load_commands(self):
|
||||||
|
registered_commands = ", ".join(
|
||||||
|
item.prefix for item in command_registry.values() if not item.is_alias
|
||||||
|
)
|
||||||
|
|
||||||
|
Info(
|
||||||
|
f"[BOOT] [CommandHandler] Registered {len(command_registry)} game commands => {registered_commands}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def parse_command(self, content: str):
|
||||||
|
content = content.lstrip("/")
|
||||||
|
parts = content.split(maxsplit=1)
|
||||||
|
if len(parts) < 2:
|
||||||
|
return parts[0], ""
|
||||||
|
|
||||||
|
return parts[0], parts[1]
|
||||||
|
|
||||||
|
def print_help(self):
|
||||||
|
result = "Available commands:\n"
|
||||||
|
for index, (_, func) in enumerate(command_registry.items()):
|
||||||
|
result += f"{index+1}) {func.usage}\n\n"
|
||||||
|
return result
|
||||||
|
|
||||||
|
async def handle_command(self, session: Session, content: str):
|
||||||
|
if content == "/help":
|
||||||
|
return self.print_help()
|
||||||
|
|
||||||
|
command_label, args = self.parse_command(content)
|
||||||
|
command_func = command_registry.get(command_label)
|
||||||
|
|
||||||
|
if command_func is not None:
|
||||||
|
func_args_cnt = command_func.__code__.co_argcount - 1
|
||||||
|
args_list = args.split()[:func_args_cnt]
|
||||||
|
|
||||||
|
if args_list and args_list[0] == "help":
|
||||||
|
return f"Usage: {command_func.usage}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
return await command_func(session, *args_list)
|
||||||
|
except TypeError:
|
||||||
|
return f"Usage: {command_func.usage}"
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
handler = CommandHandler()
|
||||||
21
game_server/game/chat/decorators.py
Normal file
21
game_server/game/chat/decorators.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
from typing import Dict, Type
|
||||||
|
|
||||||
|
|
||||||
|
command_registry: Dict[str, Type] = {}
|
||||||
|
|
||||||
|
|
||||||
|
def Command(prefix: str, usage: str, aliases: list = list()):
|
||||||
|
def decorator(func):
|
||||||
|
func.usage = usage
|
||||||
|
func.prefix = prefix
|
||||||
|
func.is_alias = False
|
||||||
|
command_registry[prefix] = func
|
||||||
|
|
||||||
|
# Register alias if exist
|
||||||
|
for alias in aliases:
|
||||||
|
func.is_alias = True
|
||||||
|
command_registry[alias] = func
|
||||||
|
|
||||||
|
return func
|
||||||
|
|
||||||
|
return decorator
|
||||||
68
game_server/packet/handlers/SendChatMsgNotify.py
Normal file
68
game_server/packet/handlers/SendChatMsgNotify.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import betterproto
|
||||||
|
from utils.time import get_unix_in_seconds
|
||||||
|
from game_server.net.session import Session
|
||||||
|
from game_server.game.chat.command_handler import handler
|
||||||
|
from lib.proto import (
|
||||||
|
SendChatMsgNotify,
|
||||||
|
RecvChatMsgNotify,
|
||||||
|
ChatMsg,
|
||||||
|
ChatMsgSensitiveCheckResult,
|
||||||
|
ChatMsgMsgChannel,
|
||||||
|
ChatMsgContent,
|
||||||
|
ChatMsgItem
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def handle(session: Session, msg: SendChatMsgNotify) -> betterproto.Message:
|
||||||
|
string_msg=[msg.msg_str for msg in msg.chat_msg.content.items if msg.msg_str != None][0]
|
||||||
|
msgs=[
|
||||||
|
ChatMsg(
|
||||||
|
uid=session.player.uid,
|
||||||
|
nickname=session.player.name,
|
||||||
|
time=get_unix_in_seconds(),
|
||||||
|
msg=string_msg,
|
||||||
|
channel=ChatMsgMsgChannel.WORLD.value,
|
||||||
|
avatar_id=session.player.assistant_avatar_id,
|
||||||
|
dress_id=session.player.avatars.get(session.player.assistant_avatar_id).dress_id,
|
||||||
|
frame_id=session.player.head_frame,
|
||||||
|
custom_head_id=session.player.head_photo,
|
||||||
|
check_result=ChatMsgSensitiveCheckResult(
|
||||||
|
rewrite_text=string_msg
|
||||||
|
),
|
||||||
|
content=ChatMsgContent(
|
||||||
|
items=[
|
||||||
|
ChatMsgItem(
|
||||||
|
msg_str=string_msg
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
text = await handler.handle_command(session, string_msg)
|
||||||
|
if text:
|
||||||
|
msgs.append(
|
||||||
|
ChatMsg(
|
||||||
|
uid=0,
|
||||||
|
nickname="Ai-Chan",
|
||||||
|
time=get_unix_in_seconds(),
|
||||||
|
msg=text,
|
||||||
|
channel=ChatMsgMsgChannel.WORLD.value,
|
||||||
|
avatar_id=3201,
|
||||||
|
dress_id=593201,
|
||||||
|
frame_id=200001,
|
||||||
|
custom_head_id=161080,
|
||||||
|
check_result=ChatMsgSensitiveCheckResult(
|
||||||
|
rewrite_text=text
|
||||||
|
),
|
||||||
|
content=ChatMsgContent(
|
||||||
|
items=[
|
||||||
|
ChatMsgItem(
|
||||||
|
msg_str=text
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return RecvChatMsgNotify(
|
||||||
|
chat_msg_list=msgs
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user