Files
Sprout-Farm/Server/ConsoleCommandsAPI.py
2025-08-19 09:13:54 +08:00

1064 lines
43 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
萌芽农场服务器控制台命令API模块
作者: AI Assistant
功能: 提供服务器控制台命令处理功能
"""
import os
import json
import sys
from typing import Dict, Any, List, Optional
from datetime import datetime
from SMYMongoDBAPI import SMYMongoDBAPI
class ConsoleCommandsAPI:
"""控制台命令处理类"""
def __init__(self, server):
"""
初始化控制台命令API
Args:
server: 游戏服务器实例
"""
self.server = server
self.commands = {
#添加命令
"addmoney": self.cmd_add_money, # 给玩家添加金币
"addxp": self.cmd_add_experience, # 给玩家添加经验值
"addlevel": self.cmd_add_level, # 给玩家添加等级
"addseed": self.cmd_add_seed, # 给玩家添加种子
#杂项命令
"lsplayer": self.cmd_list_players, # 列出所有玩家
"playerinfo": self.cmd_player_info, # 查看玩家信息
"ban": self.cmd_ban_player, # 踢出玩家
"weather": self.cmd_weather, # 设置天气
"help": self.cmd_help, # 显示帮助信息
#重置命令
"resetland": self.cmd_reset_land, # 重置玩家土地
"repasswd": self.cmd_reset_password, # 重置玩家密码
"rename": self.cmd_rename_player, # 重命名玩家昵称
"refarmname": self.cmd_rename_farm, # 重命名农场名称
#服务器管理命令
"stop": self.cmd_stop, # 停止服务器
#重启服务器
#查看服务器状态
#玩家配置数据库命令(未测试)
"save": self.cmd_save_all, # 保存所有玩家数据
"reload": self.cmd_reload_config, # 重新加载配置文件
# MongoDB管理命令未测试
"dbtest": self.cmd_db_test, # 测试MongoDB连接
"dbconfig": self.cmd_db_config, # 配置MongoDB连接
"dbchat": self.cmd_db_chat, # 管理聊天数据
"dbclean": self.cmd_db_clean, # 清理数据库
"dbbackup": self.cmd_db_backup # 备份数据库
}
# 初始化MongoDB API
self.mongo_api = None
self._init_mongodb_api()
def process_command(self, command_line: str) -> bool:
"""
处理控制台命令
Args:
command_line: 命令行字符串
Returns:
bool: 命令是否执行成功
"""
if not command_line.strip():
return False
parts = command_line.strip().split()
if not parts:
return False
# 移除命令前的斜杠(如果有)
command = parts[0].lstrip('/')
args = parts[1:] if len(parts) > 1 else []
if command in self.commands:
try:
self.commands[command](args)
return True
except Exception as e:
print(f"❌ 执行命令 '{command}' 时出错: {str(e)}")
return False
else:
print(f"❌ 未知命令: {command}")
print("💡 输入 'help' 查看可用命令")
return False
def get_available_commands(self) -> List[str]:
"""
获取可用命令列表
Returns:
List[str]: 可用命令列表
"""
return list(self.commands.keys())
def cmd_add_money(self, args: List[str]):
"""添加金币命令: /addmoney QQ号 数量"""
if len(args) != 2:
print("❌ 用法: /addmoney <QQ号> <数量>")
return
qq_number, amount_str = args
try:
amount = int(amount_str)
except ValueError:
print("❌ 金币数量必须是整数")
return
# 加载玩家数据
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 修改金币
old_money = player_data.get("钱币", 0)
player_data["钱币"] = old_money + amount
# 保存数据
self.server.save_player_data(qq_number, player_data)
print(f"✅ 已为玩家 {qq_number} 添加 {amount} 金币")
print(f" 原金币: {old_money} → 新金币: {player_data['钱币']}")
def cmd_add_experience(self, args: List[str]):
"""添加经验命令: /addxp QQ号 数量"""
if len(args) != 2:
print("❌ 用法: /addxp <QQ号> <数量>")
return
qq_number, amount_str = args
try:
amount = int(amount_str)
except ValueError:
print("❌ 经验数量必须是整数")
return
# 加载玩家数据
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 修改经验
old_exp = player_data.get("经验值", 0)
player_data["经验值"] = old_exp + amount
# 检查是否升级
old_level = player_data.get("等级", 1)
self.server._check_level_up(player_data)
new_level = player_data.get("等级", 1)
# 保存数据
self.server.save_player_data(qq_number, player_data)
print(f"✅ 已为玩家 {qq_number} 添加 {amount} 经验")
print(f" 原经验: {old_exp} → 新经验: {player_data['经验值']}")
if new_level > old_level:
print(f"🎉 玩家升级了! {old_level}{new_level}")
def cmd_add_level(self, args: List[str]):
"""添加等级命令: /addlevel QQ号 数量"""
if len(args) != 2:
print("❌ 用法: /addlevel <QQ号> <数量>")
return
qq_number, amount_str = args
try:
amount = int(amount_str)
except ValueError:
print("❌ 等级数量必须是整数")
return
# 加载玩家数据
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 修改等级
old_level = player_data.get("等级", 1)
new_level = max(1, old_level + amount) # 确保等级不小于1
player_data["等级"] = new_level
# 保存数据
self.server.save_player_data(qq_number, player_data)
print(f"✅ 已为玩家 {qq_number} 添加 {amount} 等级")
print(f" 原等级: {old_level} → 新等级: {new_level}")
def cmd_add_seed(self, args: List[str]):
"""添加种子命令: /addseed QQ号 作物名称 数量"""
if len(args) != 3:
print("❌ 用法: /addseed <QQ号> <作物名称> <数量>")
return
qq_number, crop_name, amount_str = args
try:
amount = int(amount_str)
except ValueError:
print("❌ 种子数量必须是整数")
return
# 加载玩家数据
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 检查作物是否存在
crop_data = self.server._load_crop_data()
if crop_name not in crop_data:
print(f"❌ 作物 '{crop_name}' 不存在")
print(f"💡 可用作物: {', '.join(list(crop_data.keys())[:10])}...")
return
# 添加种子到背包
if "seeds" not in player_data:
player_data["seeds"] = {}
old_count = player_data["seeds"].get(crop_name, 0)
player_data["seeds"][crop_name] = old_count + amount
# 保存数据
self.server.save_player_data(qq_number, player_data)
print(f"✅ 已为玩家 {qq_number} 添加 {amount}{crop_name} 种子")
print(f" 原数量: {old_count} → 新数量: {player_data['seeds'][crop_name]}")
def cmd_list_players(self, args: List[str]):
"""列出所有玩家命令: /lsplayer"""
try:
# 使用MongoDB获取玩家数据
if hasattr(self.server, 'mongo_api') and self.server.mongo_api:
players_data = self.server.mongo_api.get_all_players_basic_info()
if not players_data:
print("📭 暂无已注册玩家")
return
print(f"📋 已注册玩家列表 (共 {len(players_data)} 人):")
print("-" * 80)
print(f"{'QQ号':<12} {'昵称':<15} {'等级':<6} {'金币':<10} {'最后登录':<20}")
print("-" * 80)
for player in players_data:
qq_number = player.get("玩家账号", "未知")
nickname = player.get("玩家昵称", "未设置")
level = player.get("等级", 1)
money = player.get("钱币", 0)
last_login = player.get("最后登录时间", "从未登录")
print(f"{qq_number:<12} {nickname:<15} {level:<6} {money:<10} {last_login:<20}")
print("-" * 80)
else:
print("❌ 未配置MongoDB连接")
except Exception as e:
print(f"❌ 列出玩家时出错: {str(e)}")
def cmd_player_info(self, args: List[str]):
"""查看玩家信息命令: /playerinfo QQ号"""
if len(args) != 1:
print("❌ 用法: /playerinfo <QQ号>")
return
qq_number = args[0]
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
print(f"👤 玩家信息: {qq_number}")
print("=" * 50)
print(f"昵称: {player_data.get('玩家昵称', '未设置')}")
print(f"农场名: {player_data.get('农场名称', '未设置')}")
print(f"等级: {player_data.get('等级', 1)}")
print(f"经验: {player_data.get('经验值', 0)}")
print(f"金币: {player_data.get('钱币', 0)}")
print(f"体力: {player_data.get('体力值', 20)}")
print(f"注册时间: {player_data.get('注册时间', '未知')}")
print(f"最后登录: {player_data.get('最后登录时间', '从未登录')}")
print(f"总在线时长: {player_data.get('总游玩时间', '0时0分0秒')}")
# 显示土地信息
farm_lots = player_data.get("农场土地", [])
planted_count = sum(1 for lot in farm_lots if lot.get("is_planted", False))
digged_count = sum(1 for lot in farm_lots if lot.get("is_diged", False))
print(f"土地状态: 总共{len(farm_lots)}块,已开垦{digged_count}块,已种植{planted_count}")
# 显示种子信息
seeds = player_data.get("seeds", {})
if seeds:
print(f"种子背包: {len(seeds)}种作物,总计{sum(seeds.values())}个种子")
else:
print("种子背包: 空")
print("=" * 50)
def cmd_reset_land(self, args: List[str]):
"""重置玩家土地命令: /resetland QQ号"""
if len(args) != 1:
print("❌ 用法: /resetland <QQ号>")
return
qq_number = args[0]
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 加载初始化模板优先从MongoDB
template_data = None
if hasattr(self.server, 'use_mongodb') and self.server.use_mongodb and hasattr(self.server, 'mongo_api') and self.server.mongo_api:
try:
template_data = self.server.mongo_api.get_initial_player_data_template()
if template_data:
print("✅ 成功从MongoDB加载初始玩家数据模板")
else:
print("⚠️ MongoDB中未找到初始玩家数据模板尝试从JSON文件加载")
except Exception as e:
print(f"⚠️ 从MongoDB加载初始玩家数据模板失败: {str(e)}尝试从JSON文件加载")
# MongoDB加载失败或不可用从JSON文件加载
if not template_data:
try:
with open("config/initial_player_data_template.json", 'r', encoding='utf-8') as f:
template_data = json.load(f)
print("✅ 成功从JSON文件加载初始玩家数据模板")
except Exception as e:
print(f"❌ 无法加载初始化模板: {str(e)}")
return
# 重置土地状态
if "农场土地" in template_data:
old_lots_count = len(player_data.get("农场土地", []))
player_data["农场土地"] = template_data["农场土地"]
new_lots_count = len(player_data["农场土地"])
# 保存数据
self.server.save_player_data(qq_number, player_data)
print(f"✅ 已重置玩家 {qq_number} 的土地状态")
print(f" 土地数量: {old_lots_count}{new_lots_count}")
print(f" 所有作物和状态已清除,恢复为初始状态")
else:
print("❌ 初始化模板中没有找到土地数据")
def cmd_weather(self, args: List[str]):
"""天气控制命令: /weather <天气类型>"""
if len(args) != 1:
print("❌ 用法: /weather <天气类型>")
print(" 可用天气: clear, rain, snow, cherry, gardenia, willow")
return
weather_type = args[0].lower()
# 定义可用的天气类型映射
weather_map = {
"clear": "晴天",
"rain": "下雨",
"snow": "下雪",
"cherry": "樱花雨",
"gardenia": "栀子花雨",
"willow": "柳叶雨",
"stop": "停止天气"
}
if weather_type not in weather_map:
print("❌ 无效的天气类型")
print(" 可用天气: clear, rain, snow, cherry, gardenia, willow, stop")
return
# 广播天气变更消息给所有在线客户端
weather_message = {
"type": "weather_change",
"weather_type": weather_type,
"weather_name": weather_map[weather_type]
}
# 发送给所有连接的客户端
if hasattr(self.server, 'clients'):
for client_id in list(self.server.clients.keys()):
try:
self.server.send_data(client_id, weather_message)
except Exception as e:
print(f"⚠️ 向客户端 {client_id} 发送天气消息失败: {str(e)}")
print(f"🌤️ 已将天气切换为: {weather_map[weather_type]}")
if hasattr(self.server, 'clients') and len(self.server.clients) > 0:
print(f" 已通知 {len(self.server.clients)} 个在线客户端")
else:
print(" 当前无在线客户端")
def cmd_reset_password(self, args: List[str]):
"""重置玩家密码命令: /repasswd QQ号"""
if len(args) != 1:
print("❌ 用法: /repasswd <QQ号>")
return
qq_number = args[0]
# 加载玩家数据
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 重置密码为123456
old_password = player_data.get("玩家密码", "未设置")
player_data["玩家密码"] = "123456"
# 保存数据
success = self.server.save_player_data(qq_number, player_data)
if success:
print(f"✅ 已重置玩家 {qq_number} 的密码")
print(f" 新密码: 123456")
else:
print(f"❌ 重置玩家 {qq_number} 密码失败")
def cmd_rename_player(self, args: List[str]):
"""重命名玩家昵称命令: /rename QQ号 新昵称"""
if len(args) != 2:
print("❌ 用法: /rename <QQ号> <新昵称>")
return
qq_number, new_nickname = args
# 加载玩家数据
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 修改玩家昵称
old_nickname = player_data.get("玩家昵称", "未设置")
player_data["玩家昵称"] = new_nickname
# 保存数据
success = self.server.save_player_data(qq_number, player_data)
if success:
print(f"✅ 已重命名玩家 {qq_number} 的昵称")
print(f" 原昵称: {old_nickname} → 新昵称: {new_nickname}")
else:
print(f"❌ 重命名玩家 {qq_number} 昵称失败")
def cmd_rename_farm(self, args: List[str]):
"""重命名农场名称命令: /refarmname QQ号 新农场名称"""
if len(args) != 2:
print("❌ 用法: /refarmname <QQ号> <新农场名称>")
return
qq_number, new_farm_name = args
# 加载玩家数据
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 修改农场名称
old_farm_name = player_data.get("农场名称", "未设置")
player_data["农场名称"] = new_farm_name
# 保存数据
success = self.server.save_player_data(qq_number, player_data)
if success:
print(f"✅ 已重命名玩家 {qq_number} 的农场名称")
print(f" 原农场名: {old_farm_name} → 新农场名: {new_farm_name}")
else:
print(f"❌ 重命名玩家 {qq_number} 农场名称失败")
def cmd_ban_player(self, args: List[str]):
"""踢出玩家命令: /ban QQ号 [时长] [原因]"""
if len(args) < 1 or len(args) > 3:
print("❌ 用法: /ban <QQ号> [时长(秒)] [原因]")
print(" 时长默认为0秒(立即可重新登录),原因默认为'您已被管理员踢出服务器'")
return
qq_number = args[0]
ban_duration = 0 # 默认0秒
ban_reason = "您已被管理员踢出服务器" # 默认原因
# 解析时长参数
if len(args) >= 2:
try:
ban_duration = int(args[1])
if ban_duration < 0:
print("❌ 踢出时长不能为负数")
return
except ValueError:
print("❌ 踢出时长必须是整数(秒)")
return
# 解析原因参数
if len(args) >= 3:
ban_reason = args[2]
# 加载玩家数据
player_data = self.server.load_player_data(qq_number)
if not player_data:
print(f"❌ 玩家 {qq_number} 不存在")
return
# 计算禁止登录时间
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
ban_end_time = ""
if ban_duration > 0:
from datetime import timedelta
end_datetime = datetime.now() + timedelta(seconds=ban_duration)
ban_end_time = end_datetime.strftime("%Y-%m-%d %H:%M:%S")
# 设置禁用系统
if "禁用系统" not in player_data:
player_data["禁用系统"] = {}
player_data["禁用系统"] = {
"是否被禁止登录": ban_duration > 0,
"禁止登录原因": ban_reason,
"禁止登录开始": current_time,
"禁止登录截止": ban_end_time
}
# 保存数据
success = self.server.save_player_data(qq_number, player_data)
if not success:
print(f"❌ 保存玩家 {qq_number} 数据失败")
return
# 如果玩家在线,强制下线
kicked_online = False
if hasattr(self.server, 'user_data'):
for client_id, user_info in self.server.user_data.items():
if user_info.get("username") == qq_number and user_info.get("logged_in", False):
# 发送踢出消息
kick_message = {
"type": "kick_notification",
"reason": ban_reason,
"duration": ban_duration
}
self.server.send_data(client_id, kick_message)
# 断开连接
if hasattr(self.server, 'disconnect_client'):
self.server.disconnect_client(client_id)
kicked_online = True
break
# 输出结果
if ban_duration > 0:
print(f"✅ 已踢出玩家 {qq_number},禁止登录 {ban_duration}")
print(f" 踢出原因: {ban_reason}")
print(f" 禁止登录至: {ban_end_time}")
else:
print(f"✅ 已踢出玩家 {qq_number},可立即重新登录")
print(f" 踢出原因: {ban_reason}")
if kicked_online:
print(f" 玩家已在线,已强制下线")
else:
print(f" 玩家当前不在线")
def cmd_help(self, args: List[str]):
"""显示帮助信息"""
print("🌱 萌芽农场服务器控制台命令帮助")
print("=" * 60)
print("玩家管理命令:")
print(" /addmoney <QQ号> <数量> - 为玩家添加金币")
print(" /addxp <QQ号> <数量> - 为玩家添加经验")
print(" /addlevel <QQ号> <数量> - 为玩家添加等级")
print(" /addseed <QQ号> <作物> <数量> - 为玩家添加种子")
print(" /lsplayer - 列出所有已注册玩家")
print(" /playerinfo <QQ号> - 查看玩家详细信息")
print(" /resetland <QQ号> - 重置玩家土地状态")
print(" /repasswd <QQ号> - 重置玩家密码为123456")
print(" /rename <QQ号> <新昵称> - 重命名玩家昵称")
print(" /refarmname <QQ号> <新农场名> - 重命名农场名称")
print(" /ban <QQ号> [时长] [原因] - 踢出玩家(时长秒,原因可选)")
print("")
print("游戏控制命令:")
print(" /weather <类型> - 控制全服天气")
print(" 可用类型: clear, rain, snow, cherry, gardenia, willow, stop")
print("")
print("服务器管理命令:")
print(" /save - 立即保存所有玩家数据")
print(" /reload - 重新加载配置文件")
print(" /stop - 停止服务器")
print(" /help - 显示此帮助信息")
print("=" * 60)
print("💡 提示: 命令前的斜杠(/)是可选的")
print("")
print("数据库管理命令:")
print(" /dbtest - 测试数据库连接")
print(" /dbconfig <操作> [参数] - 数据库配置管理")
print(" /dbchat <操作> [参数] - 聊天消息管理")
print(" /dbclean <类型> - 数据库清理")
print(" /dbbackup [类型] - 数据库备份")
def cmd_save_all(self, args: List[str]):
"""保存所有数据命令"""
try:
# 保存所有在线玩家数据
saved_count = 0
if hasattr(self.server, 'user_data'):
for client_id, user_info in self.server.user_data.items():
if user_info.get("logged_in", False):
username = user_info.get("username")
if username:
player_data = self.server.load_player_data(username)
if player_data:
self.server.save_player_data(username, player_data)
saved_count += 1
print(f"✅ 已保存 {saved_count} 个在线玩家的数据")
except Exception as e:
print(f"❌ 保存数据时出错: {str(e)}")
def cmd_reload_config(self, args: List[str]):
"""重新加载配置命令"""
try:
# 重新加载作物数据
if hasattr(self.server, '_load_crop_data'):
self.server._load_crop_data()
print("✅ 已重新加载配置文件")
except Exception as e:
print(f"❌ 重新加载配置时出错: {str(e)}")
def cmd_stop(self, args: List[str]):
"""停止服务器命令"""
print("⚠️ 正在停止服务器...")
try:
# 保存所有在线玩家数据
if hasattr(self.server, 'user_data'):
for client_id, user_info in self.server.user_data.items():
if user_info.get("logged_in", False):
username = user_info.get("username")
if username:
player_data = self.server.load_player_data(username)
if player_data:
self.server.save_player_data(username, player_data)
print("💾 数据保存完成")
except:
pass
if hasattr(self.server, 'stop'):
self.server.stop()
print("✅ 服务器已停止")
sys.exit(0)
def _init_mongodb_api(self):
"""初始化MongoDB API"""
try:
# 检查服务器是否使用MongoDB
if hasattr(self.server, 'use_mongodb') and self.server.use_mongodb:
environment = "production" if hasattr(self.server, 'environment') and self.server.environment == "production" else "test"
self.mongo_api = SMYMongoDBAPI(environment)
if self.mongo_api.is_connected():
print(f"✅ MongoDB API 初始化成功 [{environment}]")
else:
print(f"⚠️ MongoDB API 连接失败 [{environment}]")
self.mongo_api = None
else:
print("💡 服务器未启用MongoDB数据库命令将不可用")
except Exception as e:
print(f"❌ MongoDB API 初始化失败: {str(e)}")
self.mongo_api = None
# ========================= MongoDB管理命令 =========================
def cmd_db_test(self, args):
"""测试数据库连接命令: /dbtest"""
if not self.mongo_api:
print("❌ MongoDB API 未初始化或连接失败")
return
try:
if self.mongo_api.is_connected():
# 测试基本操作
config = self.mongo_api.get_daily_checkin_config()
if config:
print("✅ 数据库连接正常,可以正常读取配置")
print(f" 环境: {self.mongo_api.environment}")
print(f" 数据库: {self.mongo_api.config[self.mongo_api.environment]['database']}")
print(f" 主机: {self.mongo_api.config[self.mongo_api.environment]['host']}:{self.mongo_api.config[self.mongo_api.environment]['port']}")
else:
print("⚠️ 数据库连接正常,但无法读取配置数据")
else:
print("❌ 数据库连接失败")
except Exception as e:
print(f"❌ 数据库测试失败: {str(e)}")
def cmd_db_config(self, args):
"""数据库配置管理命令: /dbconfig <操作> [参数]"""
if not self.mongo_api:
print("❌ MongoDB API 未初始化")
return
if len(args) == 0:
print("❌ 用法: /dbconfig <操作> [参数]")
print(" 可用操作:")
print(" list - 列出所有配置类型")
print(" get <配置类型> - 获取指定配置")
print(" reload <配置类型> - 重新加载指定配置到服务器")
print(" 配置类型: daily_checkin, lucky_draw, new_player, wisdom_tree, online_gift, scare_crow, item, pet, stamina, crop_data, initial_player_data")
return
operation = args[0].lower()
if operation == "list":
print("📋 可用的配置类型:")
print("-" * 50)
config_types = [
("daily_checkin", "每日签到配置"),
("lucky_draw", "幸运抽奖配置"),
("new_player", "新手大礼包配置"),
("wisdom_tree", "智慧树配置"),
("online_gift", "在线礼包配置"),
("scare_crow", "稻草人配置"),
("item", "道具配置"),
("pet", "宠物配置"),
("stamina", "体力系统配置"),
("crop_data", "作物数据配置"),
("initial_player_data", "初始玩家数据模板")
]
for config_type, description in config_types:
print(f" {config_type:<20} - {description}")
print("-" * 50)
elif operation == "get":
if len(args) < 2:
print("❌ 用法: /dbconfig get <配置类型>")
return
config_type = args[1]
try:
config_methods = {
"daily_checkin": self.mongo_api.get_daily_checkin_config,
"lucky_draw": self.mongo_api.get_lucky_draw_config,
"new_player": self.mongo_api.get_new_player_config,
"wisdom_tree": self.mongo_api.get_wisdom_tree_config,
"online_gift": self.mongo_api.get_online_gift_config,
"scare_crow": self.mongo_api.get_scare_crow_config,
"item": self.mongo_api.get_item_config,
"pet": self.mongo_api.get_pet_config,
"stamina": self.mongo_api.get_stamina_config,
"crop_data": self.mongo_api.get_crop_data_config,
"initial_player_data": self.mongo_api.get_initial_player_data_template
}
if config_type not in config_methods:
print(f"❌ 未知的配置类型: {config_type}")
return
config = config_methods[config_type]()
if config:
print(f"{config_type} 配置:")
print(json.dumps(config, ensure_ascii=False, indent=2))
else:
print(f"❌ 无法获取 {config_type} 配置")
except Exception as e:
print(f"❌ 获取配置失败: {str(e)}")
elif operation == "reload":
if len(args) < 2:
print("❌ 用法: /dbconfig reload <配置类型>")
return
config_type = args[1]
print(f"🔄 正在重新加载 {config_type} 配置到服务器...")
try:
# 这里可以添加重新加载配置到服务器的逻辑
# 例如重新加载作物数据等
if config_type == "crop_data":
if hasattr(self.server, '_load_crop_data'):
self.server._load_crop_data()
print(f"✅ 已重新加载 {config_type} 配置到服务器")
else:
print(f"⚠️ 服务器不支持重新加载 {config_type} 配置")
else:
print(f"💡 {config_type} 配置重新加载功能暂未实现")
except Exception as e:
print(f"❌ 重新加载配置失败: {str(e)}")
else:
print(f"❌ 未知操作: {operation}")
def cmd_db_chat(self, args):
"""聊天消息管理命令: /dbchat <操作> [参数]"""
if not self.mongo_api:
print("❌ MongoDB API 未初始化")
return
if len(args) == 0:
print("❌ 用法: /dbchat <操作> [参数]")
print(" 可用操作:")
print(" latest - 获取最新聊天消息")
print(" history [天数] [数量] - 获取聊天历史 (默认3天最多500条)")
print(" clean [保留天数] - 清理旧聊天消息 (默认保留30天)")
return
operation = args[0].lower()
if operation == "latest":
try:
message = self.mongo_api.get_latest_chat_message()
if message:
print("💬 最新聊天消息:")
print(f" 玩家: {message.get('player_name', 'N/A')} (QQ: {message.get('username', 'N/A')})")
print(f" 内容: {message.get('content', '')}")
print(f" 时间: {message.get('time_str', 'N/A')}")
else:
print("📭 暂无聊天消息")
except Exception as e:
print(f"❌ 获取最新聊天消息失败: {str(e)}")
elif operation == "history":
days = 3
limit = 500
if len(args) > 1:
try:
days = int(args[1])
except ValueError:
print("❌ 天数必须是整数")
return
if len(args) > 2:
try:
limit = int(args[2])
except ValueError:
print("❌ 数量必须是整数")
return
try:
messages = self.mongo_api.get_chat_history(days, limit)
if messages:
print(f"💬 聊天历史 (最近{days}天,共{len(messages)}条):")
print("-" * 80)
for msg in messages[-10:]: # 只显示最后10条
print(f"[{msg.get('time_str', 'N/A')}] {msg.get('player_name', 'N/A')}: {msg.get('content', '')}")
if len(messages) > 10:
print(f"... 还有 {len(messages) - 10} 条历史消息")
print("-" * 80)
else:
print("📭 暂无聊天历史")
except Exception as e:
print(f"❌ 获取聊天历史失败: {str(e)}")
elif operation == "clean":
keep_days = 30
if len(args) > 1:
try:
keep_days = int(args[1])
except ValueError:
print("❌ 保留天数必须是整数")
return
try:
deleted_count = self.mongo_api.clean_old_chat_messages(keep_days)
print(f"🧹 清理完成: 删除了 {deleted_count} 个文档 ({keep_days}天前的消息)")
except Exception as e:
print(f"❌ 清理聊天消息失败: {str(e)}")
else:
print(f"❌ 未知操作: {operation}")
def cmd_db_clean(self, args):
"""数据库清理命令: /dbclean <类型>"""
if not self.mongo_api:
print("❌ MongoDB API 未初始化")
return
if len(args) == 0:
print("❌ 用法: /dbclean <类型>")
print(" 可用类型:")
print(" codes - 清理过期验证码")
print(" chat [保留天数] - 清理旧聊天消息 (默认保留30天)")
print(" all - 清理所有过期数据")
return
clean_type = args[0].lower()
if clean_type == "codes":
try:
removed_count = self.mongo_api.clean_expired_verification_codes()
print(f"🧹 验证码清理完成: 清理了 {removed_count} 个过期验证码")
except Exception as e:
print(f"❌ 清理验证码失败: {str(e)}")
elif clean_type == "chat":
keep_days = 30
if len(args) > 1:
try:
keep_days = int(args[1])
except ValueError:
print("❌ 保留天数必须是整数")
return
try:
deleted_count = self.mongo_api.clean_old_chat_messages(keep_days)
print(f"🧹 聊天消息清理完成: 删除了 {deleted_count} 个文档 ({keep_days}天前的消息)")
except Exception as e:
print(f"❌ 清理聊天消息失败: {str(e)}")
elif clean_type == "all":
print("🧹 开始清理所有过期数据...")
total_cleaned = 0
# 清理验证码
try:
codes_count = self.mongo_api.clean_expired_verification_codes()
print(f" 验证码: 清理了 {codes_count}")
total_cleaned += codes_count
except Exception as e:
print(f" 验证码清理失败: {str(e)}")
# 清理聊天消息
try:
chat_count = self.mongo_api.clean_old_chat_messages(30)
print(f" 聊天消息: 删除了 {chat_count} 个文档")
total_cleaned += chat_count
except Exception as e:
print(f" 聊天消息清理失败: {str(e)}")
print(f"✅ 清理完成,总计处理 {total_cleaned}")
else:
print(f"❌ 未知清理类型: {clean_type}")
def cmd_db_backup(self, args):
"""数据库备份命令: /dbbackup [类型]"""
if not self.mongo_api:
print("❌ MongoDB API 未初始化")
return
backup_type = "config" if len(args) == 0 else args[0].lower()
if backup_type == "config":
try:
# 备份所有游戏配置
configs = self.mongo_api.find_documents("gameconfig")
if configs:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_file = f"backup/gameconfig_backup_{timestamp}.json"
# 确保备份目录存在
os.makedirs("backup", exist_ok=True)
with open(backup_file, 'w', encoding='utf-8') as f:
json.dump(configs, f, ensure_ascii=False, indent=2)
print(f"✅ 游戏配置备份完成: {backup_file}")
print(f" 备份了 {len(configs)} 个配置文档")
else:
print("❌ 没有找到配置数据")
except Exception as e:
print(f"❌ 配置备份失败: {str(e)}")
elif backup_type == "chat":
try:
# 备份聊天消息
chat_docs = self.mongo_api.find_documents("chat")
if chat_docs:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_file = f"backup/chat_backup_{timestamp}.json"
# 确保备份目录存在
os.makedirs("backup", exist_ok=True)
with open(backup_file, 'w', encoding='utf-8') as f:
json.dump(chat_docs, f, ensure_ascii=False, indent=2)
print(f"✅ 聊天消息备份完成: {backup_file}")
print(f" 备份了 {len(chat_docs)} 个聊天文档")
else:
print("❌ 没有找到聊天数据")
except Exception as e:
print(f"❌ 聊天备份失败: {str(e)}")
else:
print("❌ 用法: /dbbackup [类型]")
print(" 可用类型:")
print(" config - 备份游戏配置 (默认)")
print(" chat - 备份聊天消息")
# ===================== 扩展功能方法 =====================
def add_custom_command(self, command_name: str, command_func):
"""
添加自定义命令
Args:
command_name: 命令名称
command_func: 命令处理函数
"""
self.commands[command_name] = command_func
print(f"✅ 已添加自定义命令: {command_name}")
def remove_command(self, command_name: str) -> bool:
"""
移除命令
Args:
command_name: 命令名称
Returns:
bool: 是否成功移除
"""
if command_name in self.commands:
del self.commands[command_name]
print(f"✅ 已移除命令: {command_name}")
return True
else:
print(f"❌ 命令不存在: {command_name}")
return False
def get_command_info(self, command_name: str) -> Optional[str]:
"""
获取命令信息
Args:
command_name: 命令名称
Returns:
Optional[str]: 命令文档字符串
"""
if command_name in self.commands:
func = self.commands[command_name]
return func.__doc__ if func.__doc__ else "无描述"
return None
def execute_batch_commands(self, commands: List[str]) -> Dict[str, bool]:
"""
批量执行命令
Args:
commands: 命令列表
Returns:
Dict[str, bool]: 每个命令的执行结果
"""
results = {}
for cmd in commands:
print(f"\n执行命令: {cmd}")
results[cmd] = self.process_command(cmd)
return results