diff --git a/.env b/.env index a96545d..05e5593 100644 --- a/.env +++ b/.env @@ -1,15 +1,14 @@ DEBUG=true -HOST=0.0.0.0 # 配置 NoneBot 监听的 IP / 主机名 -PORT=43001 # 配置 NoneBot 监听的端口 -COMMAND_START=["","/"] # 配置命令起始字符 -COMMAND_SEP=["."] # 配置命令分割字符 +HOST=0.0.0.0 +PORT=43001 +COMMAND_START=["","/"] +COMMAND_SEP=["."] DRIVER=~fastapi+~httpx LOG_LEVEL=DEBUG +SUPERUSERS=[] -SUPERUSERS=[] # 超级管理员 - -NICKNAME=[] # 机器人昵称 +NICKNAME=[] # QQ官方机器人配置文件 # QQ_IS_SANDBOX=true @@ -21,18 +20,30 @@ QQ_BOTS='[{ "c2c_group_at_messages": true }, "use_websocket": false - }]' + } + ]' APSCHEDULER_CONFIG={"apscheduler.timezone": "Asia/Shanghai"} - # .env.prod -savedata = data/ram_data # 保存路径,相对路径,此处为保存至运行目录下的 "Yuni/savedata/" 下,默认为 "" -ram_policy = 0 # 授权策略 0 为根据可用功能 1 为根据服务级别,默认为 0 -ram_cmd = ram # 指令名,或者叫触发词,默认为 ram -ram_add = -a # 启用功能(根据可用功能),默认为 -a -ram_rm = -r # 禁用功能(根据可用功能),默认为 -r -ram_show = -s # 展示群功能状态(根据可用功能),默认为 -s -ram_available = -v # 展示全局可用功能(根据可用功能),默认为 -v +# 保存路径,相对路径,此处为保存至运行目录下的 "Yuni/savedata/" 下,默认为 "" +savedata=data/ram_data +# 授权策略 0 为根据可用功能 1 为根据服务级别,默认为 0 +ram_policy=0 + +# 指令名,或者叫触发词,默认为 ram +ram_cmd=ram + +# 启用功能(根据可用功能),默认为 -a +ram_add=-a + +# 禁用功能(根据可用功能),默认为 -r +ram_rm=-r + +# 展示群功能状态(根据可用功能),默认为 -s +ram_show=-s + +# 展示全局可用功能(根据可用功能),默认为 -v +ram_available=-v diff --git a/bot.py b/bot.py index 9de98fd..2b62550 100644 --- a/bot.py +++ b/bot.py @@ -1,5 +1,6 @@ import nonebot from nonebot.adapters.qq import Adapter as QQ +from nonebot.adapters.onebot.v11 import Adapter as Onebot from nonebot.log import logger # 初始化 NoneBot 以及 数据库 @@ -9,7 +10,7 @@ app = nonebot.get_asgi() # 注册适配器 driver = nonebot.get_driver() driver.register_adapter(QQ) - +driver.register_adapter(Onebot) # 加载自定义插件 nonebot.load_plugins("src/plugins") # 加载bot自定义插件 diff --git a/pyproject.toml b/pyproject.toml index efd6c8a..c45d089 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,9 @@ nonebug-saa = { git = "https://github.com/MountainDash/nonebug-saa.git" } [tool.nonebot] adapters = [ - { name = "QQ", module_name = "nonebot.adapter.qq" } + { name = "QQ", module_name = "nonebot.adapter.qq" }, + { name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11" }, + { name = "OneBot V12", module_name = "nonebot.adapters.onebot.v12" }, ] plugins = [ diff --git a/src/plugins/bf_bot/__init__.py b/src/plugins/bf_bot/__init__.py index 70084dc..e25adfd 100644 --- a/src/plugins/bf_bot/__init__.py +++ b/src/plugins/bf_bot/__init__.py @@ -1,7 +1,7 @@ import time from nonebot import on_command, require -from nonebot.adapters import Message +from nonebot.adapters import Message, Event, Bot from nonebot.matcher import Matcher from nonebot.params import CommandArg from nonebot.plugin import PluginMetadata @@ -9,6 +9,8 @@ from nonebot.rule import to_me from nonebot.log import logger import json +from .user_data.data_utils import UserManager + require("nonebot_plugin_alconna") from nonebot_plugin_alconna import UniMessage from .data import * @@ -19,14 +21,26 @@ from .text_utils import * __plugin_meta__ = PluginMetadata( name="BF查询", description="战地3,4,1,5,2042,6", - usage="", + usage=""" + bf3: /bf3 EAID (查询BF3数据) + bf4: /bf4 EAID (查询BF4数据) + bf1: /bf1 EAID (查询BF5数据) + bfv: /bfv EAID (查询BF6数据) + bf2042: /bf2042 EAID (查询BF2042数据) + bf6: /bf6 EAID (查询BF6数据) + 绑定: /绑定 EAID (绑定你的QQ与EAID) + 解绑: /解绑 (解除你的QQ与当前绑定的EAID) + 修改绑定: /修改绑定 EAID (修改你的QQ与当前绑定的EAID) + """.strip(), extra={ }, ) query = on_command("bft", rule=to_me(), aliases={"bf3", "bf4", "bfv", "bf1", "bf2042", "bf6"}, block=True) -bind = on_command("bind", rule=to_me(), aliases={"绑定"}, block=True) +bind = on_command("bfbind", rule=to_me(), aliases={"绑定"}, block=True) +unbind = on_command("unbind", rule=to_me(), aliases={"解绑"}, block=True) +update_bind = on_command("update_bind", rule=to_me(), aliases={"修改绑定"}, block=True) bf_dict = { "bf3": "战地3", @@ -39,54 +53,73 @@ bf_dict = { @query.handle() -async def handle_function(matcher: Matcher, msg: Message = CommandArg()): +async def handle_function(event: Event, matcher: Matcher, msg: Message = CommandArg()): + start_time = time.time() + usermanager = UserManager() cmd = matcher.state["_prefix"]["command"][0] game = cmd - content = msg.extract_plain_text() + input_text = msg.extract_plain_text().strip() + logger.info(f"{type(input_text)}, {repr(input_text)}") + if input_text is None or input_text == "": + content = usermanager.get_user_by_qq(event.get_user_id()) + if not content: + await UniMessage.at(user_id=event.get_user_id()).text( + "未检测到id,也未检测到绑定记录,请使用 绑定 EAID 进行绑定操作").send() + return + player_id = content['ea_player_id'] + user_id = content['ea_user_id'] + player = content['ea_player_name'] + platform = "pc" + else: + content = await get_player_info_by_name(input_text, "pc") + if 'errors' in content: + await UniMessage.at(user_id=event.get_user_id()).text("未找到玩家,请检查是否拼写正确").send() + return + player_id = content['personaId'] + user_id = content['userId'] + player = content['personaName'] if 'personaName' in content else content['name'] + platform = "pc" + await UniMessage.text(f"正在查询 {player} 的 {bf_dict[cmd]} 数据,请耐心等待").send() play_stat = "" - if cmd == "bf3": - play_stat = await get_data_bf3(content, "pc") - elif cmd == "bf4": - play_stat = await get_data_bf4(content, "pc") - elif cmd == "bf1": - play_stat = await get_data_bf1(content, "pc") - elif cmd == "bfv": - play_stat = await get_data_bfv(content, "pc") - elif cmd == "bf2042": - play_stat = await get_data_bfv(content, "pc") - elif cmd == "bf6": - flag, play_stat = await get_data_bf6(content, 0) - if flag == 0: - msg = '检测到多个同名用户\n' + '\n'.join( - f'用户名:{info["name"]}-等级:{info["rank"]}-UID:{info["uid"]}' for info in play_stat) - await UniMessage.text(msg).finish() - elif flag == 2: - msg = "未找到该玩家名" - await UniMessage.text(msg).finish() - else: - await UniMessage.text("指令异常").finish() - if "errors" in play_stat: - logger.warning(play_stat['errors'][0]) - msg = play_stat['errors'][0] - else: - if cmd == "bf6": - img = build_bf6_simple_card(play_stat) + try: + if cmd == "bf3": + play_stat = await get_data_bf3(player_id, user_id, platform) + elif cmd == "bf4": + play_stat = await get_data_bf4(player_id, user_id, platform) + elif cmd == "bf1": + play_stat = await get_data_bf1(player_id, user_id, platform) + elif cmd == "bfv": + play_stat = await get_data_bfv(player_id, user_id, platform) + elif cmd == "bf2042": + await UniMessage.at(event.get_user_id()).text("正在开发中,敬请期待!").send() + # play_stat = await get_data_bfv(player_id, user_id, platform) + elif cmd == "bf6": + play_stat = await get_data_bf6(player_id, user_id, platform) else: + await UniMessage.at(event.get_user_id()).text("指令异常").send() + return + # logger.info(f"{json.dumps(play_stat, ensure_ascii=False, indent=2)}") + if "errors" in play_stat: + logger.warning(play_stat['errors'][0]) + msg = play_stat['errors'][0] + else: + # logger.info(f"结果{play_stat}") + # player = play_stat['userName'] weapon, vehicle = await get_best_weapon_and_best_vehicle(play_stat) - player = play_stat['userName'] pid = play_stat['userId'] kd = play_stat['killDeath'] kpm = play_stat['killsPerMinute'] - spm = play_stat['scorePerMinute'] acc = play_stat['accuracy'] # 战地3 特化 if cmd == 'bf3': head_shots = play_stat['headShots'] else: head_shots = play_stat['headshots'] - - rank = play_stat['rank'] time_play = convert_to_hours(play_stat['timePlayed']) + logger.info(f"游玩时长监测:{time_play}") + if time_play == 0: + await UniMessage.at(event.get_user_id()).text("查询接口异常,请等待一段时间后查询").send() + return kills = int(play_stat['kills']) kill_assists = int(play_stat['killAssists']) revives = int(play_stat['revives']) @@ -95,21 +128,141 @@ async def handle_function(matcher: Matcher, msg: Message = CommandArg()): best_weapon = weapon best_vehicle = vehicle best_class = play_stat['bestClass'] - longest_head_shot = play_stat['longestHeadShot'] - highest_ill_streak = play_stat['highestKillStreak'] - - # await stats_calculator(play_stat) - - stat_data, level_designation = await stats_calculator(play_stat, cmd) destroyed = await get_vehicle_destroyed(play_stat["vehicles"]) - img = await build_stats_card(game, player, pid, kd, kpm, spm, acc, head_shots, rank, time_play, kills, - kill_assists, revives, wins, loses, destroyed, best_weapon, best_vehicle, - best_class, - longest_head_shot, highest_ill_streak, stat_data, level_designation) - await UniMessage.image(raw=img.getvalue()).finish() - await UniMessage.text(f"\n玩家【{content}】的【{bf_dict[cmd]}】数据\n{msg}").send() + if cmd == 'bf6': + rank = await get_bf6_rank(player) + logger.info(f"等级:{rank}") + captured = play_stat['objective']['captured'] + score = sum(item.get("score", 0) for item in play_stat['classes']) + # 计算4兵种游玩时长 + seconds = sum(item.get("secondsPlayed", 0) for item in play_stat['classes']) + kpm = round(kills / (int(seconds) / 60), 1) + logger.info(f"击杀数:{kills},游玩分钟数:{seconds / 60},计算kpm值:{kpm}") + spm = int(score / (int(seconds) / 60)) + logger.info(f"计算spm值:{spm}") + repairs = play_stat['repairs'] + img = await build_bf6_stats_card(game='bf6', + qq_id=event.get_user_id(), + player=player, + pid=pid, + rank=rank, + kd=kd, + kpm=kpm, + spm=spm, + acc=acc, + head_shots=head_shots, + time_play=time_play, + kills=kills, + kill_assists=kill_assists, + revives=revives, + repairs=repairs, + captured=captured, + score=score, + wins=wins, + loses=loses, + destroyed=destroyed, + best_weapon=best_weapon, + best_vehicle=best_vehicle, + best_class=best_class) + else: + spm = play_stat['scorePerMinute'] + rank = play_stat['rank'] + longest_head_shot = play_stat['longestHeadShot'] + highest_ill_streak = play_stat['highestKillStreak'] + stat_data, level_designation = await stats_calculator(play_stat, cmd) + img = await build_stats_card(game, player, pid, kd, kpm, spm, acc, head_shots, rank, time_play, kills, + kill_assists, revives, wins, loses, destroyed, best_weapon, best_vehicle, + best_class, + longest_head_shot, highest_ill_streak, stat_data, level_designation) + end_time = time.time() + duration = round(end_time - start_time, 3) + await UniMessage.image(raw=img.getvalue()).at(user_id=event.get_user_id()).text( + f"本次查询耗时:{duration}s").send() + except Exception as e: + logger.exception(f"异常:{e}") @bind.handle() -async def bind_user(matcher: Matcher, msg: Message = CommandArg()): - matcher.state.get() +async def bind_user(event: Event, matcher: Matcher, msg: Message = CommandArg()): + user_manager = UserManager() + player_name = msg.extract_plain_text() + qq_id = event.get_user_id() + + # 执行已有数据查询操作 + user_record = user_manager.get_user_by_qq(qq_id) + if user_record: + user_info = await get_player_info_by_ea_id(user_record['ea_player_id'], user_record['ea_user_id'], 'pc') + await (UniMessage.at(user_id=event.get_user_id()) + .text(f"您已经将账号绑定到: {user_info['personaName']},如果你需要更改绑定请发送 修改绑定 EAID ").send()) + return + else: + user_info_json = await get_player_info_by_name(player_name, "pc") + if 'errors' in user_info_json: + await UniMessage.at(user_id=event.get_user_id()).text("未找到玩家,请检查是否拼写正确").send() + player_id = user_info_json['personaId'] + user_id = user_info_json['userId'] + player_name = user_info_json['personaName'] if 'personaName' in user_info_json else user_info_json['name'] + avatar_url = user_info_json['avatar'] + logger.info(f"QQ号:{qq_id},EA双ID:{player_id}-{user_id}") + + # 检测ea账号 是否被绑定至其他qq + bind_record = user_manager.get_user_by_ea_id(user_id) + if bind_record: + await (UniMessage.at(user_id=event.get_user_id()) + .text( + f"您的EA账号 {bind_record['ea_player_name']} 已经绑定到: {bind_record['qq_id']},请您确认绑定的EAID").send()) + return + else: + # 执行绑定操作 + record = user_manager.add_user(qq_id, player_name, player_id, user_id, "[]", "[]") + logger.info(f"插入数据返回结果:{record}") + if record > 0: + await UniMessage.at(user_id=event.get_user_id()).text(f"您已经成功绑定至: {player_name}").send() + + +@unbind.handle() +async def bind_user(event: Event, matcher: Matcher, msg: Message = CommandArg()): + user_manager = UserManager() + qq_id = event.get_user_id() + + # 执行已有数据查询操作 + user_record = user_manager.get_user_by_qq(qq_id) + if user_record: + user_info = await get_player_info_by_ea_id(user_record['ea_player_id'], user_record['ea_user_id'], 'pc') + rows = user_manager.delete_user_by_qq(qq_id) + if rows > 0: + await (UniMessage.at(user_id=event.get_user_id()) + .text( + f"您已经与: {user_info['personaName']} 成功解除绑定,如果你需要重新绑定请发送 修改绑定 EAID ").send()) + return + else: + await UniMessage.at(user_id=event.get_user_id()).text(f"未查询到绑定记录").send() + + +@update_bind.handle() +async def bind_user(event: Event, matcher: Matcher, msg: Message = CommandArg()): + user_manager = UserManager() + player_name = msg.extract_plain_text() + qq_id = event.get_user_id() + + # 执行已有数据查询操作 + user_record = user_manager.get_user_by_qq(qq_id) + if user_record: + user_info_json = await get_player_info_by_name(player_name, "pc") + if 'errors' in user_info_json: + await UniMessage.at(user_id=event.get_user_id()).text("未找到玩家,请检查是否拼写正确").send() + player_id = user_info_json['personaId'] + user_id = user_info_json['userId'] + player_name = user_info_json['personaName'] if 'personaName' in user_info_json else user_info_json['name'] + avatar_url = user_info_json['avatar'] + logger.info(f"QQ号:{qq_id},EA双ID:{player_id}-{user_id}") + + # 执行修改绑定操作 + record = user_manager.update_user(qq_id, player_name, player_id, user_id, "[]", "[]") + logger.info(f"修改数据返回结果:{record}") + if record > 0 and record == 1: + await UniMessage.at(user_id=event.get_user_id()).text( + f"您已经成功从:{user_record['ea_player_name']}修改绑定至: {player_name}").send() + else: + await UniMessage.at(user_id=event.get_user_id()).text( + f"未查询到绑定记录: {player_name},如果需要绑定,请@机器人并发送 绑定 {player_name} ").send() diff --git a/src/plugins/bf_bot/bf6_data.py b/src/plugins/bf_bot/bf6_data.py index 43dd63d..5cb3750 100644 --- a/src/plugins/bf_bot/bf6_data.py +++ b/src/plugins/bf_bot/bf6_data.py @@ -6,11 +6,6 @@ from nonebot import logger from curl_cffi import AsyncSession, CurlError import random -try: - import browser_cookie3 -except ImportError: - browser_cookie3 = None # 可选,如果没安装则 fallback 到 cookies.txt - # ---------- 配置 ---------- file_path = os.path.dirname(__file__).replace("\\", "/") exported_cookie_path = Path(f"{file_path}/cookies/tracker.txt") # 你导出的 cookies.txt @@ -59,15 +54,6 @@ def load_cookies_from_txt(path: Path) -> List[Dict[str, str]]: return cookies -def load_browser_cookies(domain="tracker.gg") -> List[Dict[str, str]]: - if not browser_cookie3: - return [] - try: - return [{"name": c.name, "value": c.value} for c in browser_cookie3.chrome(domain_name=domain)] - except Exception: - return [] - - def build_cookie_header(cookies: List[Dict[str, str]]) -> str: return "; ".join(f"{c['name']}={c['value']}" for c in cookies) @@ -130,11 +116,8 @@ def is_challenge_response(resp) -> bool: async def search_user_with_fallback(url: str): - # 1️⃣ 优先尝试浏览器 cookie - cookies = load_browser_cookies() - # 2️⃣ 如果浏览器 cookie 不存在,再 fallback 到 cookies.txt - if not cookies: - cookies = load_cookies_from_txt(exported_cookie_path) + # cookies.txt + cookies = load_cookies_from_txt(exported_cookie_path) headers = build_headers(RAW_BROWSER_HEADERS, cookies=cookies, ua_override=CUSTOM_UA) logger.info(f"请求 URL: {url}") @@ -142,12 +125,12 @@ async def search_user_with_fallback(url: str): resp = await fetch_with_cookies(url, headers) if is_challenge_response(resp): - logger.warning("⚠️ Cloudflare 拦截或 cookies 失效。") + logger.warning("Cloudflare 拦截或 cookies 失效。") if isinstance(resp, dict): return resp return {"status": getattr(resp, "status_code", None), "preview": getattr(resp, "text", "")[:200]} else: - logger.info("✅ 请求成功。") + logger.info("请求成功。") return getattr(resp, "json", lambda: resp)() if hasattr(resp, "json") else resp diff --git a/src/plugins/bf_bot/cookies/tracker.txt b/src/plugins/bf_bot/cookies/tracker.txt index 77c2ff2..c2670b1 100644 --- a/src/plugins/bf_bot/cookies/tracker.txt +++ b/src/plugins/bf_bot/cookies/tracker.txt @@ -2,24 +2,30 @@ # https://curl.haxx.se/rfc/cookie_spec.html # This is a generated file! Do not edit. -tracker.gg FALSE / FALSE 1763712553 _lr_env_src_ats false -tracker.gg FALSE / FALSE 1766200813 nitro-uid %7B%22TDID%22%3A%2238381d61-f87b-42c2-9a52-7764b7e111ac%22%2C%22TDID_LOOKUP%22%3A%22TRUE%22%2C%22TDID_CREATED_AT%22%3A%222025-09-21T03%3A20%3A13%22%7D -tracker.gg FALSE / FALSE 1766200813 nitro-uid_cst znv0HA%3D%3D -.tracker.gg TRUE / TRUE 1794816553 _scor_uid d3fe4e72704a49548e3d944283183d16 +.tracker.gg TRUE / TRUE 1795483904 _scor_uid d3fe4e72704a49548e3d944283183d16 .tracker.gg TRUE / FALSE 1792552814 ncmp.domain tracker.gg -.tracker.gg TRUE / TRUE 1792657486 __stripe_mid f3195526-098b-451a-a803-afe861f3546981d4b7 -.tracker.gg TRUE / FALSE 1795681481 _ga GA1.1.1090555935.1761016835 +.tracker.gg TRUE / TRUE 1797905122 __stripe_mid f3195526-098b-451a-a803-afe861f3546981d4b7 +.tracker.gg TRUE / FALSE 1800929047 _ga GA1.1.1090555935.1761016835 .tracker.gg TRUE / FALSE 1795576862 _ga_4115T4MP2X GS2.1.s1761016839$o1$g1$t1761016862$j37$l0$h0 -tracker.gg FALSE / FALSE 1766305486 pbjs-unifiedid %7B%22TDID%22%3A%2238381d61-f87b-42c2-9a52-7764b7e111ac%22%2C%22TDID_LOOKUP%22%3A%22TRUE%22%2C%22TDID_CREATED_AT%22%3A%222025-09-21T03%3A21%3A09%22%7D -tracker.gg FALSE / FALSE 1766305486 pbjs-unifiedid_cst YiwPLDosoA%3D%3D -.tracker.gg TRUE / FALSE 1784448555 _cc_id d7583525ab694e187a68c7c9adac9679 -tracker.gg FALSE / FALSE 1761621671 _lr_sampling_rate 100 -.tracker.gg TRUE / FALSE 1794757153 cto_bidid ZYK0w18xUFhlUWZoQ2ttd2Vlc0lnVjV1azlmSXI5ZlBVRUZ3QjVFazJUOHAlMkZnYWlFc0l2endrZGVDb1Z6dXdJdXA4V3Y1OVlEVGI4VUlNV1QxejgwWmxwJTJGRjByeGJFbWhFRTBQQnExU1luNTlvd1klM0Q -.tracker.gg TRUE / TRUE 1761122345 __cf_bm 0U2HKncz5gYebQMBxL_qtaeuqoAdy.5lnue9xCP_Lls-1761120544-1.0.1.1-vFt.KkK9agrVBKJiVR6KstByxEN86BEvyVVQxg5VhtRT40Oq6Bmaan1yzLbW9V0ixAlOLPpYcflX6CqpCjl0D9Lg.73D54Jnm3KLQ5tGxnEZhnr0ORp6W5HYsfpsNiRc -tracker.gg FALSE / FALSE 1761124153 _lr_retry_request true -.tracker.gg TRUE / FALSE 1761206955 panoramaId_expiry 1761206955341 -.tracker.gg TRUE / TRUE 1761123286 __stripe_sid 99b864d5-840b-4cce-9c31-b4699e594ec16de245 -.tracker.gg TRUE / FALSE 1795681481 _ga_HWSV72GK8X GS2.1.s1761120545$o13$g1$t1761121480$j60$l0$h0 -tracker.gg FALSE / FALSE 1766305486 pbjs-unifiedid_last Wed%2C%2022%20Oct%202025%2008%3A24%3A46%20GMT -.tracker.gg TRUE / FALSE 1794817546 cto_bundle dv27kl9RN0JGSHVyZE9za1E5a1ZNZEo4R21rQVkxVUFtYSUyRjQxd0JaWDJtWGhOVmZnV2hxUEVzemZ2TE9XSVB0UXNMVkZySUtXaW0lMkZ4WTRnN3FhSmNFOE4lMkI2WXg4cW42UFpKd2I3QmViY1JuTkZYMG9FVUZ1STJESHc2NDUzMHBEMyUyQm92bUtEMzJlajF0bXMyZ3M1Z0YwJTJGRkR3JTNEJTNE -.tracker.gg TRUE / TRUE 1792657481 cf_clearance betnOuJnsRXlDgs9rKx_2GJXze5bdRFK3eVFFB9k610-1761121481-1.2.1.1-RDnj4R4HqOjhE1Sn5Dp5wKysllw6cVSYRPbbL4y_STOAnBlQEVRv_7xC1h9TleDg9Ecyy2neJCW1Xk6BNd51K4htSHptKFlQF8tv_JqMlDyFg9DxShAveOMXu4o9vkivWZmFvJRKv9ERqm33dfsYAQD5lkyYFtsurraCOPzu3TILLbsnjoi2v_kCILeFLPdEbeiABRHQUrsZdi1jhwKM9cDJ_XHs0bmPZrDOfVaf444 +tracker.gg FALSE / FALSE 1771553052 pbjs-unifiedid_cst YiwPLDosoA%3D%3D +.tracker.gg TRUE / FALSE 1789697050 _cc_id d7583525ab694e187a68c7c9adac9679 +.tracker.gg TRUE / FALSE 1792826487 _sharedID bed2ec05800bb7f9e68b74ba7bdcd4d2 +.tracker.gg TRUE / FALSE 1797905048 _pubcid a08276dc-b9f1-4665-af99-d3e92418fa0d +tracker.gg FALSE / FALSE 1771553049 nitro-uid_cst V0fMHQ%3D%3D +.tracker.gg TRUE / FALSE 1797905048 _pubcid_cst znv0HA%3D%3D +tracker.gg FALSE / FALSE 1768961048 _lr_env_src_ats false +.tracker.gg TRUE / FALSE 1797905049 _nitroID eac08417a7dae49a9a17a3077a566d71 +tracker.gg FALSE / FALSE 1771553049 nitro-uid %7B%22TDID%22%3A%2238381d61-f87b-42c2-9a52-7764b7e111ac%22%2C%22TDID_LOOKUP%22%3A%22TRUE%22%2C%22TDID_CREATED_AT%22%3A%222025-11-22T02%3A04%3A10%22%7D +.tracker.gg TRUE / FALSE 1800093848 cto_bidid 1MhyDl8xUFhlUWZoQ2ttd2Vlc0lnVjV1azlmSXI5ZlBVRUZ3QjVFazJUOHAlMkZnYWlFc0l2endrZGVDb1Z6dXdJdXA4V3Y1OVlEVGI4VUlNV1QxejgwWmxwJTJGRiUyQjlkcXVKbW14OFo2dDZoUWFHMjcwMCUzRA +.tracker.gg TRUE / FALSE 1766455452 panoramaId_expiry 1766455451737 +.tracker.gg TRUE / FALSE 1766455452 panoramaId 06fa4e910365dd224dafc8b188a2a9fb927a5781cea050ef85eb9d2d9bd1d20a +.tracker.gg TRUE / FALSE 1766455452 panoramaIdType panoDevice +tracker.gg FALSE / FALSE 1771553052 pbjs-unifiedid %7B%22TDID%22%3A%2238381d61-f87b-42c2-9a52-7764b7e111ac%22%2C%22TDID_LOOKUP%22%3A%22TRUE%22%2C%22TDID_CREATED_AT%22%3A%222025-11-22T02%3A04%3A13%22%7D +tracker.gg FALSE / FALSE 1771553052 pbjs-unifiedid_last Mon%2C%2022%20Dec%202025%2002%3A04%3A12%20GMT +.tracker.gg TRUE / FALSE 1800065052 cto_bundle Lj73nF81bUZFQXRhbjgxQmE5SG1uZWMyaEcxdGZBYUsxY09Fb05TT2hpSVo2ckptaXA0clZkeDBIQnklMkJrcG56U21MWnRvYlZJaVJUdmolMkI4YnBMQkgxWjRqaDZpTmhJVnRkVWIlMkZGVzBYR0Q1dnJ0WWhEeVNwQVpCTXZHc2tHUnVKSHRTeSUyRnpnQWIlMkJOV3BwSGdYTU1mcktaY2t3JTNEJTNE +tracker.gg FALSE / FALSE 1766973852 _lr_sampling_rate 100 +.tracker.gg TRUE / FALSE 1800947800 _ga_HWSV72GK8X GS2.1.s1766387800$o31$g0$t1766387800$j60$l0$h0 +.tracker.gg TRUE / TRUE 1800065052 __gads ID=ac9c2c8840aa7cc9:T=1766369052:RT=1766388112:S=ALNI_Mb6I0wyc1mq0xflsJiO_mg_p7NYyg +.tracker.gg TRUE / TRUE 1800065052 __gpi UID=000011d0cd089cb2:T=1766369052:RT=1766388112:S=ALNI_MZYW_bpm3kBzbSJVap3HmFbUvCzkQ +.tracker.gg TRUE / TRUE 1781921052 __eoi ID=161dfd629cbfa555:T=1766369052:RT=1766388112:S=AA-Afjb7PNr8G6MBMl83ajT_75cS +.tracker.gg TRUE / TRUE 1797905047 cf_clearance yXkCKjvvWaL14EKripPAXHHkJsg_U80n6RCKMxweSPg-1766369048-1.2.1.1-KaeYOmcV609jWIn.Rrw.fhT5HXMcy4R1H.s67uhk5ewh5P8yuXU6VZGYdMtGF8zUBAu5dVsg9dyp0C1jMqMPKgZ3syEcCryrW5_sPsLS8EUlLb1fXq2ehVCRtEHZhfP_zZuQSGxil2vTq1Z9feznMkY1cMb1hIaSZ3JUajyF7w.YryqLr4n5lOS3dlQeaXYS__X_gbzxyJNOzMXDuYQtfqc50JQt5ymEACbbPIGsK20 diff --git a/src/plugins/bf_bot/data.py b/src/plugins/bf_bot/data.py index a07ba76..217b169 100644 --- a/src/plugins/bf_bot/data.py +++ b/src/plugins/bf_bot/data.py @@ -3,55 +3,123 @@ import json import requests from .get_bf6_data import * +from .tracker_data import * -async def get_data_bf3(user_name, platform): - url = f"https://api.gametools.network/bf3/all/?format_values=true&name={user_name}&platform={platform}" +async def get_data_bf3(player_id, user_id, platform): + url = f"https://api.gametools.network/bf3/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us" payload = {} headers = { 'accept': 'application/json' } + logger.info(f"请求URL:{url}") response = requests.request("GET", url, headers=headers, data=payload) data_json = json.loads(response.text) return data_json -async def get_data_bf4(user_name, platform): - url = f"https://api.gametools.network/bf4/all/?format_values=true&name={user_name}&platform={platform}" +async def get_data_bf4(player_id, user_id, platform): + url = f"https://api.gametools.network/bf4/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us" payload = {} headers = { 'accept': 'application/json' } + logger.info(f"请求URL:{url}") response = requests.request("GET", url, headers=headers, data=payload) data_json = json.loads(response.text) return data_json -async def get_data_bf1(user_name, platform): - url = f"https://api.gametools.network/bf1/all/?format_values=true&name={user_name}&platform={platform}&skip_battlelog=false&lang=en-us" +async def get_data_bf1(player_id, user_id, platform): + url = f"https://api.gametools.network/bf1/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us" + payload = {} + headers = { + 'accept': 'application/json' + } + logger.info(f"请求URL:{url}") + response = requests.request("GET", url, headers=headers, data=payload) + data_json = json.loads(response.text) + return data_json + + +async def get_data_bfv(player_id, user_id, platform): + url = f"https://api.gametools.network/bfv/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us" payload = {} headers = { 'accept': 'application/json' } + logger.info(f"请求URL:{url}") response = requests.request("GET", url, headers=headers, data=payload) data_json = json.loads(response.text) return data_json -async def get_data_bfv(user_name, platform): - url = f"https://api.gametools.network/bfv/all/?format_values=true&name={user_name}&platform={platform}&skip_battlelog=false&lang=en-us" +async def get_data_bf6(player_id, user_id, platform): + url = f"https://api.gametools.network/bf6/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us" payload = {} headers = { 'accept': 'application/json' } + logger.info(f"请求URL:{url}") response = requests.request("GET", url, headers=headers, data=payload) data_json = json.loads(response.text) return data_json -async def get_data_bf6(user_name, search_type): - flag, data_json = await get_info(user_name, search_type) - return flag, data_json +async def get_player_info_by_name(user_name, platform): + user_info_url = f"https://api.gametools.network/bfglobal/player/?name={user_name}&platform={platform}&skip_battlelog=false" + + payload = {} + headers = { + 'accept': 'application/json' + } + logger.info(f"查询用户请求url:{user_info_url}") + response = requests.request("GET", user_info_url, headers=headers, data=payload) + + user_info_json = json.loads(response.text) + return user_info_json + + +async def get_player_info_by_ea_id(player_id, user_id, platform): + url = f"https://api.gametools.network/bfglobal/player/?playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false" + + payload = {} + headers = { + 'accept': 'application/json' + } + + response = requests.request("GET", url, headers=headers, data=payload) + + user_info_json = json.loads(response.text) + return user_info_json + + +async def get_bf6_rank(player): + url = f"https://api.tracker.gg/api/v2/bf6/standard/search?platform=origin&query={player}&autocomplete=true" + result = await fetch_tracker_search(url, exported_cookie_path) + # 无结果再使用steam搜索 + if "errors" in result: + return 0 + user_info = {} + if "status" in result or "errors" in result: + return 0 + for res in result['data']: + if res['status'] is not None and res['platformSlug'] == 'origin': + name = res['platformUserHandle'] + uid = res['titleUserId'] + status = res['status'].strip().split('•', 1)[0].replace("Rank", "") + user = { + 'name': name, + 'rank': status, + 'uid': uid, + } + user_info = user + + logger.info(f"单用户{user_info}") + logger.info(f"查询结果: {json.dumps(user_info, ensure_ascii=False, indent=2)}") + if 'rank' not in user_info: + return 0 + return user_info['rank'] diff --git a/src/plugins/bf_bot/data_utils.py b/src/plugins/bf_bot/data_utils.py index cc4ec83..aea68e9 100644 --- a/src/plugins/bf_bot/data_utils.py +++ b/src/plugins/bf_bot/data_utils.py @@ -3,6 +3,8 @@ from PIL import Image, ImageDraw, ImageFont from nonebot import logger from functools import reduce +# from img_utils import png_resize +# from param import round_data, interval_table from .img_utils import png_resize from .param import round_data, interval_table diff --git a/src/plugins/bf_bot/database_op.py b/src/plugins/bf_bot/database_op.py new file mode 100644 index 0000000..a00de79 --- /dev/null +++ b/src/plugins/bf_bot/database_op.py @@ -0,0 +1,4 @@ + + +def bind_user(user_info): + user_info[''] diff --git a/src/plugins/bf_bot/gametools_bf6.py b/src/plugins/bf_bot/gametools_bf6.py new file mode 100644 index 0000000..40b6e3a --- /dev/null +++ b/src/plugins/bf_bot/gametools_bf6.py @@ -0,0 +1,60 @@ +import json + +import requests + + +async def get_data_bf6(player_id, user_id, platform): + url = "https://api.gametools.network/bf6/multiple/?raw=false&format_values=true" + payload = json.dumps([ + { + "player_id": player_id, + "user_id": user_id, + "platform": platform + } + ]) + + headers = { + 'accept': 'application/json', + 'Content-Type': 'application/json' + } + + response = requests.request("POST", url, headers=headers, data=payload) + info = json.loads(response.text) + return info + + +async def get_data_user(user_name, platform): + url = f"https://api.gametools.network/bfglobal/player/?name={user_name}&platform={platform}&skip_battlelog=false" + + payload = {} + headers = { + 'accept': 'application/json' + } + + response = requests.request("GET", url, headers=headers, data=payload) + data_json = json.loads(response.text) + + player_id = data_json["personaId"] + user_id = data_json["userId"] + platform = data_json["platform"] + user_name = data_json["personaName"] + + if "errors" in data_json: + return False, data_json + + user_info = { + "player_id": player_id, + "user_id": user_id, + "platform": platform, + "user_name": user_name + } + + return True, user_info + + +async def get_player_game_info(user_name, platform): + flag, user_info = await get_data_user(user_name, platform) + info = await get_data_bf6(user_info['player_id'], user_info['user_id'], user_info['platform']) + info['userName'] = user_name + info_format = json.dumps(info, ensure_ascii=False, indent=2) + print(info_format) diff --git a/src/plugins/bf_bot/get_bf6_data.py b/src/plugins/bf_bot/get_bf6_data.py index e553fd0..f52731f 100644 --- a/src/plugins/bf_bot/get_bf6_data.py +++ b/src/plugins/bf_bot/get_bf6_data.py @@ -5,9 +5,10 @@ from typing import List, Dict, Optional from nonebot import logger from curl_cffi import AsyncSession, CurlError from .bf6_data import * +# from bf6_data import * +import requests import json - -url_search = "https://api.tracker.gg/api/v2/bf6/standard/search?platform={platform}&query={name}" +url_search = "https://api.tracker.gg/api/v2/bf6/standard/search?platform={platform}&query={name}&autocomplete=true" url_overview = "https://api.tracker.gg/api/v2/bf6/standard/profile/ign/{param}" @@ -65,8 +66,8 @@ async def get_info(player, search_type): url = url_search.format(platform="steam", name=player) result = await search_user_with_fallback(url) title_id_list = [] - logger.info(f"查询结果: {json.dumps(result, ensure_ascii=False, indent=2)}") - if "errors" in result: + logger.info(f"查询结果: \n{json.dumps(result, ensure_ascii=False, indent=2)}") + if "status" in result or "errors" in result: return 3, '查询异常' for res in result['data']: if res['status'] is not None: @@ -245,3 +246,26 @@ async def get_vehicles(platform_info, overview, weapons, vehicles, gamemodes, ga '最佳载具': best_vehicle, } return player_info + + +async def get_bf6_data(player_id, user_id, platform): + + url = "https://api.gametools.network/bf6/multiple/?raw=false&format_values=true" + + payload = json.dumps([ + { + "player_id": player_id, + "user_id": user_id, + "platform": platform + } + ]) + headers = { + 'accept': 'application/json', + 'Content-Type': 'application/json' + } + + response = requests.request("POST", url, headers=headers, data=payload) + + player_stat_json = json.loads(response.text) + + return player_stat_json diff --git a/src/plugins/bf_bot/image_builder.py b/src/plugins/bf_bot/image_builder.py index 33d5851..7e1693b 100644 --- a/src/plugins/bf_bot/image_builder.py +++ b/src/plugins/bf_bot/image_builder.py @@ -12,18 +12,39 @@ from .img_utils import * from .data_utils import * from .param import * +# from img_utils import * +# from data_utils import * +# from param import * + filepath = os.path.dirname(__file__).replace("\\", "/") # 字体 -font_XXL = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 72) -font_XL = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 64) -font_L = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 48) -font_M = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 36) -font_MS = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 32) -font_S = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 28) -font_XS = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 24) -font_XXS = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 18) -font_XXXS = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 16) +font_XXL = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 72) +font_XL = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 64) +font_L = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 48) +font_ML = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 42) +font_M = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 36) +font_MS = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 32) +font_S = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 28) +font_XS = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 24) +font_XXS = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 18) +font_XXXS = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 16) + + +font_XXL_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 72) +font_XL_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 64) +font_L_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 48) +font_ML_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 42) +font_M_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 36) +font_MS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 32) +font_S_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 28) +font_XS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 24) +font_XXS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 18) +font_XXXS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 16) +font_S_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 28) +font_XS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 20) +font_XXS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 18) +font_XXXS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 16) async def build_stats_card(game="bfv", player="Player001", pid=1145141919, kd=1.25, kpm=2.3, spm=500, acc=25.6, @@ -75,12 +96,12 @@ async def build_stats_card(game="bfv", player="Player001", pid=1145141919, kd=1. draw = ImageDraw.Draw(pil_img) # 玩家信息 - draw.text((665, 65), f"{player}", fill="white", font=font_L) - draw.text((745, 133), f"{pid}", fill="white", font=font_M) + draw.text((665, 65), f"{player}", fill="white", font=font_L_CH) + draw.text((745, 133), f"{pid}", fill="white", font=font_M_CH) # 等级游玩时长 - draw.text((740, 212), f"{rank}", fill="white", font=font_M) - draw.text((985, 212), f"{time_play}H", fill="white", font=font_M) + draw.text((740, 212), f"{rank}", fill="white", font=font_M_CH) + draw.text((985, 212), f"{time_play}H", fill="white", font=font_M_CH) # draw_centered_text(draw=draw, text=rank, x_left=730, x_right=905, y=210, font=font_M, fill="white", ) # draw_centered_text(draw=draw, text=f"{time_play}H", x_left=965, x_right=1120, y=210, font=font_M, fill="white", ) # draw.text((730, 195), f"{rank}", fill="white", font=font_M) @@ -90,11 +111,172 @@ async def build_stats_card(game="bfv", player="Player001", pid=1145141919, kd=1. # 场次 draw_centered_text(draw=draw, text=(wins + loses), x_left=45, x_right=265, y=350, - font=font_L, + font=font_L_CH, fill="white") # 命中率 draw_centered_text(draw=draw, text=round(float(acc.replace("%", "")), 1), x_left=415, x_right=495, y=343, + font=font_M_CH, + fill="white") + # 爆头率 + if head_shots: + head_shots = head_shots.replace("%", "") + else: + head_shots = 0 + draw_centered_text(draw=draw, text=round(float(head_shots), 1), x_left=395, x_right=470, y=420, font=font_M_CH, + fill="white") + # kd + draw_centered_text(draw=draw, text=kd, x_left=585, x_right=785, y=340, font=font_XL_CH, fill="white") + # kpm + draw_centered_text(draw=draw, text=round(kpm, 1), x_left=825, x_right=1025, y=340, font=font_XL_CH, fill="white") + # spm + draw_centered_text(draw=draw, text=round(spm, 1), x_left=1065, x_right=1265, y=340, font=font_XL_CH, fill="white") + + # 击杀 + draw_centered_text(draw=draw, text=kills, x_left=870, x_right=1190, y=595, font=font_L_CH, fill="white") + + # 助攻 + draw_centered_text(draw=draw, text=kill_assists, x_left=820, x_right=1145, y=770, font=font_L_CH, fill="white") + + # 急救 + draw_centered_text(draw=draw, text=revives, x_left=770, x_right=1090, y=960, font=font_L_CH, fill="white") + + # 摧毁 + draw_centered_text(draw=draw, text=destroyed, x_left=720, x_right=1040, y=1140, font=font_L_CH, fill="white") + + # 底部栏 + + # 评级 + if game == 'bf6': + logger.info("bf6不计算称号") + else: + level = level_designation['level'] + des = level_designation['designation'] + color = level_designation['color'] + draw_centered_text(draw=draw, text=level, x_left=70, x_right=200, y=1120, font=font_XL_CH, fill=color) + draw_centered_text(draw=draw, text=des, x_left=200, x_right=550, y=1120, font=font_XL_CH, fill="white") + + # 最佳兵种 + + draw_centered_text(draw=draw, text=classes[best_class], x_left=140, x_right=310, y=1290, font=font_L_CH, fill="white") + + # 最远击杀 + draw_centered_text(draw=draw, text=f"{longest_head_shot}m", x_left=455, x_right=625, y=1290, font=font_L_CH, + fill="white") + + # 最高连杀 + draw_centered_text(draw=draw, text=highest_ill_streak, x_left=765, x_right=935, y=1290, font=font_L_CH, fill="white") + + # 最佳⭐ + pil_img = build_best(draw, pil_img, best_weapon, best_vehicle, game) + + # 生成时间 + draw.text((1870, 1420), f"{formatted_time}", fill=(154, 132, 149), font=font_XXXS_CH) + + # ---------------- 转回 OpenCV ---------------- + img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) + + # ---------------- 雷达图 ---------------- + if game != "bf6": + center = (311, 796) + r = 185 + scale_min = 0.25 if min(stat_data) < 0.25 else min(stat_data) + img = draw_radar(img, stat_data, center=center, r=r, + buffer=0.1, scale_min=scale_min, scale_max=1.10) + # 保存 + success, buffer = cv2.imencode(".png", img) + if success: + b_io = io.BytesIO(buffer) + return b_io # 就可以直接 return 二进制流 + else: + return None + + +async def build_bf6_stats_card(game="bfv", + qq_id=2931, + player="Player001", + pid=1145141919, + rank=114, + kd=1.25, + kpm=2.3, + spm=500, + acc=25.6, + head_shots=10, + time_play=100, + kills=100, + kill_assists=150, + revives=114, + repairs=1000, + captured=300, + score=145674, + wins=10, + loses=10, + destroyed=514, + best_weapon="M1907 SF", + best_vehicle="坦克", + best_class="Support", ): + # 获取当前事件并且格式化 + now = datetime.datetime.now() + formatted_time = now.strftime("%Y-%m-%d %H:%M:%S") + + # ---------------- OpenCV 部分 ---------------- + # 载入模板 + img = cv2.imread(f"{filepath}/template/{game}.png", cv2.IMREAD_COLOR) + + # 载入头像并缩放 + avatar = cv2.imread(f"{filepath}/avatar_cache/0.png", cv2.IMREAD_UNCHANGED) + avatar = cv2.resize(avatar, (134, 134), interpolation=cv2.INTER_AREA) + + # 粘贴头像(保持原有坐标) + y, x = 65, 105 + h, w = avatar.shape[:2] + img[y:y + h, x:x + w] = avatar + + # 公告栏 + img = notice_paste_bf6(img) + img = designation_paste(player, img, + user_id=qq_id, + start_x=104, + start_y=215, + target_height=30, + spacing=10) + + # ---------------- PIL 部分 ---------------- + pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) + draw = ImageDraw.Draw(pil_img) + + # 玩家信息 105+160 + draw.text((265, 80), f"{player}", fill="white", font=font_XL) + draw.text((265, 140), f"{pid}", fill="#CCCCCC", font=font_L) + + # 等级 + pil_img = paste_rank_icon(int(rank), pil_img) + draw_centered_text(draw=draw, text=f"{rank}", x_left=950, x_right=1075, y=205, + font=font_M, + fill="white") + # draw.text((740, 212), f"{rank}", fill="white", font=font_M) + + # 游玩时长 + draw.text((2300, 350), f"{time_play}H", fill="white", font=font_L) + # 场次 + draw.text((2300, 450), f"{wins + loses}", fill="white", font=font_L) + # draw_centered_text(draw=draw, text=(wins + loses), x_left=45, x_right=265, y=350, + # font=font_L, + # fill="white") + + # 生涯总览 + # 胜率 + + win_rate = round((wins / (wins + loses)) * 100, 1) + logger.info(f"胜场{wins},负场{loses},胜率{win_rate}") + + draw_centered_text(draw=draw, text=f"{win_rate}%", x_left=2090, x_right=2200, y=375, + font=font_XL, + fill="white") + + # 命中率 + acc_format = round(float(acc.replace("%", "")), 1) + draw_centered_text(draw=draw, text=f"{acc_format}%", x_left=1210, x_right=1303, y=363, font=font_M, fill="white") # 爆头率 @@ -102,62 +284,83 @@ async def build_stats_card(game="bfv", player="Player001", pid=1145141919, kd=1. head_shots = head_shots.replace("%", "") else: head_shots = 0 - draw_centered_text(draw=draw, text=round(float(head_shots), 1), x_left=395, x_right=470, y=420, font=font_M, + draw_centered_text(draw=draw, text=f"{round(float(head_shots), 1)}%", x_left=1210, x_right=1303, y=458, font=font_M, fill="white") # kd - draw_centered_text(draw=draw, text=kd, x_left=585, x_right=785, y=340, font=font_XL, fill="white") + # draw.text(text=kd, xy=(1350, 355), font=font_XL, fill="white") + draw_centered_text(draw=draw, text=kd, x_left=1350, x_right=1500, y=355, font=font_XL, fill="white") # kpm - draw_centered_text(draw=draw, text=round(kpm, 1), x_left=825, x_right=1025, y=340, font=font_XL, fill="white") + draw_centered_text(draw=draw, text=round(kpm, 1), x_left=1610, x_right=1760, y=355, font=font_XL, fill="white") # spm - draw_centered_text(draw=draw, text=round(spm, 1), x_left=1065, x_right=1265, y=340, font=font_XL, fill="white") + draw_centered_text(draw=draw, text=round(spm, 1), x_left=1870, x_right=2010, y=355, font=font_XL, fill="white") # 击杀 - draw_centered_text(draw=draw, text=kills, x_left=870, x_right=1190, y=595, font=font_L, fill="white") - - # 助攻 - draw_centered_text(draw=draw, text=kill_assists, x_left=820, x_right=1145, y=770, font=font_L, fill="white") + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1165, x_right=1455, y=805, + font=font_L, + fill="#333333") + draw_right_aligned_text(draw=draw, text=add_commas(str(kills)), x_left=1165, x_right=1455, y=805, + font=font_L, fill="white") # 急救 - draw_centered_text(draw=draw, text=revives, x_left=770, x_right=1090, y=960, font=font_L, fill="white") + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1165, x_right=1455, y=1080, + font=font_L, + fill="#333333") + draw_right_aligned_text(draw=draw, text=add_commas(str(revives)), x_left=1165, x_right=1455, y=1080, + font=font_L, fill="white") # 摧毁 - draw_centered_text(draw=draw, text=destroyed, x_left=720, x_right=1040, y=1140, font=font_L, fill="white") + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1165, x_right=1455, y=1350, + font=font_L, + fill="#333333") + draw_right_aligned_text(draw=draw, text=add_commas(str(destroyed)), x_left=1165, x_right=1455, y=1350, + font=font_L, fill="white") + + # 右侧 + # 占领 + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1485, x_right=1780, y=745, + font=font_L, + fill="#333333") + draw_right_aligned_text(draw=draw, text=add_commas(str(captured)), x_left=1485, x_right=1780, y=745, + font=font_L, fill="white") + + # 得分 + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1485, x_right=1780, y=955, + font=font_L, + fill="#333333") + draw_right_aligned_text(draw=draw, text=add_commas(str(score)), x_left=1485, x_right=1780, y=955, + font=font_L, fill="white") + + # 助攻 + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1485, x_right=1780, y=1160, + font=font_L, + fill="#333333") + draw_right_aligned_text(draw=draw, text=add_commas(str(kill_assists)), x_left=1485, x_right=1780, y=1160, + font=font_L, fill="white") + + # 修理 + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1485, x_right=1780, y=1370, + font=font_L, + fill="#333333") + draw_right_aligned_text(draw=draw, text=add_commas(str(repairs)), x_left=1485, x_right=1780, y=1370, + font=font_L, fill="white") # 底部栏 - # 评级 - level = level_designation['level'] - des = level_designation['designation'] - color = level_designation['color'] - draw_centered_text(draw=draw, text=level, x_left=70, x_right=200, y=1120, font=font_XL, fill=color) - draw_centered_text(draw=draw, text=des, x_left=200, x_right=550, y=1120, font=font_XL, fill="white") - - # 最佳兵种 - - draw_centered_text(draw=draw, text=classes[best_class], x_left=140, x_right=310, y=1290, font=font_L, fill="white") - - # 最远击杀 - draw_centered_text(draw=draw, text=f"{longest_head_shot}m", x_left=455, x_right=625, y=1290, font=font_L, - fill="white") - - # 最高连杀 - draw_centered_text(draw=draw, text=highest_ill_streak, x_left=765, x_right=935, y=1290, font=font_L, fill="white") + # # 最佳兵种 + # logger.info(f"最佳兵种:{best_class}") + # draw_centered_text(draw=draw, text=classes[best_class], x_left=140, x_right=310, y=1290, font=font_L, fill="white") # 最佳⭐ - pil_img = build_best(draw, pil_img, best_weapon, best_vehicle, game) + pil_img = build_best_bf6(draw, pil_img, best_weapon, best_vehicle, best_class, game) # 生成时间 - draw.text((1870, 1420), f"{formatted_time}", fill=(154, 132, 149), font=font_XXXS) + draw.text((1750, 10), f"{formatted_time}/战地中文社区/维护 SANSENHOSHI", fill=(154, 132, 149), font=font_XS_CH) # ---------------- 转回 OpenCV ---------------- img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) # ---------------- 雷达图 ---------------- - center = (311, 796) - r = 185 - scale_min = 0.25 if min(stat_data) < 0.25 else min(stat_data) - img = draw_radar(img, stat_data, center=center, r=r, - buffer=0.1, scale_min=scale_min, scale_max=1.10) + # 保存 success, buffer = cv2.imencode(".png", img) if success: @@ -184,18 +387,18 @@ def build_best(draw: ImageDraw, img: Image, weapons, vehicle, game: str): # 绘制最佳⭐ # 武器 draw_centered_text(draw=draw, text=bf_item[game][weapon_name].upper(), x_left=1240, x_right=1750, y=1355, - font=font_MS, fill="white") - draw_centered_text(draw=draw, text=w_kills, x_left=1190, x_right=1390, y=1260, font=font_L, fill="white") - draw_centered_text(draw=draw, text=w_kpm, x_left=1510, x_right=1635, y=1260, font=font_L, fill="white") - draw_centered_text(draw=draw, text=acc, x_left=1735, x_right=1803, y=1030, font=font_M, fill="white") - draw_centered_text(draw=draw, text=headshots, x_left=1695, x_right=1760, y=1200, font=font_M, fill="white") + font=font_MS_CH, fill="white") + draw_centered_text(draw=draw, text=w_kills, x_left=1190, x_right=1390, y=1260, font=font_L_CH, fill="white") + draw_centered_text(draw=draw, text=w_kpm, x_left=1510, x_right=1635, y=1260, font=font_L_CH, fill="white") + draw_centered_text(draw=draw, text=acc, x_left=1735, x_right=1803, y=1030, font=font_M_CH, fill="white") + draw_centered_text(draw=draw, text=headshots, x_left=1695, x_right=1760, y=1200, font=font_M_CH, fill="white") # 载具 draw_centered_text(draw=draw, text=bf_item[game][vehicle_name].upper(), x_left=1990, x_right=2440, y=1355, - font=font_MS, fill="white") - draw_centered_text(draw=draw, text=v_kills, x_left=1940, x_right=2150, y=1260, font=font_L, fill="white") - draw_centered_text(draw=draw, text=v_kpm, x_left=2295, x_right=2465, y=1055, font=font_XL, fill="white") - draw_centered_text(draw=draw, text=destroyed, x_left=2265, x_right=2440, y=1260, font=font_L, fill="white") + font=font_MS_CH, fill="white") + draw_centered_text(draw=draw, text=v_kills, x_left=1940, x_right=2150, y=1260, font=font_L_CH, fill="white") + draw_centered_text(draw=draw, text=v_kpm, x_left=2295, x_right=2465, y=1055, font=font_XL_CH, fill="white") + draw_centered_text(draw=draw, text=destroyed, x_left=2265, x_right=2440, y=1260, font=font_L_CH, fill="white") # 图片 weapon_url = weapons["image"] @@ -208,6 +411,64 @@ def build_best(draw: ImageDraw, img: Image, weapons, vehicle, game: str): return img +def build_best_bf6(draw: ImageDraw, img: Image, weapons, vehicle, classes, game: str): + # 最佳武器 + weapon_name = weapons["weaponName"] + w_kills = weapons["kills"] + w_kpm = weapons["killsPerMinute"] + acc = round(float(weapons["accuracy"].replace("%", "")), 1) + headshots = round(float(weapons["headshots"].replace("%", "")), 1) + + # 最佳载具 + vehicle_name = vehicle["vehicleName"] + v_kills = vehicle["kills"] + v_kpm = vehicle["killsPerMinute"] + destroyed = vehicle["destroyed"] + + # 绘制最佳⭐ + # 武器 + # draw_centered_text(draw=draw, text=bf_item[game][weapon_name].upper(), x_left=1240, x_right=1750, y=1355, + # font=font_MS, fill="white") + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 7), x_left=95, x_right=313, y=665, font=font_L, + fill="#333333") + draw_right_aligned_text(draw=draw, text=add_commas(str(w_kills)), x_left=95, x_right=313, y=665, + font=font_L, fill="white") + draw_centered_text(draw=draw, text=w_kpm, x_left=335, x_right=447, y=665, font=font_L, fill="white") + draw_centered_text(draw=draw, text=f"{acc}%", x_left=470, x_right=580, y=670, font=font_M, fill="white") + draw_centered_text(draw=draw, text=f"{headshots}%", x_left=610, x_right=717, y=670, font=font_M, fill="white") + + # 载具 + # draw_centered_text(draw=draw, text=bf_item[game][vehicle_name].upper(), x_left=1990, x_right=2440, y=1355, + # font=font_MS, fill="white") + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 7), x_left=95, x_right=313, y=1087, + font=font_L, + fill="#333333") + draw_right_aligned_text(draw=draw, text=add_commas(str(v_kills)), x_left=95, x_right=313, y=1087, + font=font_L, fill="white") + draw_centered_text(draw=draw, text=v_kpm, x_left=351, x_right=463, y=1087, font=font_L, fill="white") + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 7), x_left=477, x_right=688, y=1087, + font=font_L, + fill="#333333") + draw_right_aligned_text(draw=draw, text=destroyed, x_left=477, x_right=688, y=1087, font=font_L, fill="white") + + # 图片 + weapon_url = weapons["image"] + vehicle_url = vehicle["image"] + + wp_icon = get_save_icon(game, weapon_name, "weapon", weapon_url) + vc_icon = get_save_icon(game, vehicle_name, "vehicles", vehicle_url) + classes_icon = get_icon_from_cache(classes, 'bf6', 'classes') + wp_icon_new = png_resize(wp_icon, new_width=725 - 88) + vc_icon_new = png_resize(vc_icon, new_width=725 - 88) + classes_icon_new = png_resize(classes_icon, new_height=1072 - 325) + + img = image_paste(wp_icon_new, img, (88, 325)) + img = image_paste(vc_icon_new, img, (88, 750)) + img = image_paste(classes_icon_new, img, (753, 325)) + + return img + + def normalize_for_radar(data, buffer=0.1, scale_min=0.0, scale_max=1.0): """ 将数据动态归一化到指定区间 [scale_min, scale_max], @@ -237,6 +498,24 @@ def normalize_for_radar(data, buffer=0.1, scale_min=0.0, scale_max=1.0): return norm.tolist() +def add_commas(text): + return re.sub(r'(? 0 and new_height > 0: + scale = min(new_width / src_w, new_height / src_h) + target_w = int(src_w * scale) + target_h = int(src_h * scale) - bands = img.split() + elif new_width > 0: + scale = new_width / src_w + target_w = new_width + target_h = int(src_h * scale) + + elif new_height > 0: + scale = new_height / src_h + target_h = new_height + target_w = int(src_w * scale) + + else: + # 未指定任何尺寸,直接返回 + return img + + # ------------------------- + # 重采样方式 + # ------------------------- resample_map = { "NEAREST": Image.NEAREST, "BILINEAR": Image.BILINEAR, "BICUBIC": Image.BICUBIC, "LANCZOS": Image.LANCZOS } - resample_method = resample_map.get(resample, Image.LANCZOS) # 默认使用 LANCZOS + resample_method = resample_map.get(resample, Image.LANCZOS) - bands = [b.resize((new_width, new_height), resample=resample_method) for b in bands] - resized_file = Image.merge('RGBA', bands) + # ------------------------- + # Alpha 安全 resize(逐通道) + # ------------------------- + bands = img.split() + resized_bands = [ + band.resize((target_w, target_h), resample=resample_method) + for band in bands + ] - return resized_file + return Image.merge("RGBA", resized_bands) # 图片粘贴 @@ -200,8 +234,36 @@ def draw_centered_text(draw, text, x_left, x_right, y, font, fill): draw.text((x_center, y), text, font=font, fill=fill) +def draw_right_aligned_text(draw, text, x_left, x_right, y, font, fill): + """ + 在指定区域内从右往左绘制文本(右对齐) + :param draw: ImageDraw 对象 + :param text: 要绘制的文本 + :param x_left: 区域左边界 x + :param x_right: 区域右边界 x(文本右侧贴齐这里) + :param y: 文本基线 y 坐标 + :param font: ImageFont 对象 + :param fill: 文本颜色 + """ + text = str(text) + text_width = font.getlength(text) + + # 右对齐:文本右边贴到 x_right + x_start = x_right - text_width + + # 可选:防止越界(超出左边界时截断) + if x_start < x_left: + x_start = x_left + + draw.text((x_start, y), text, font=font, fill=fill) + + def get_save_icon(game, name, icon_type, url): - name = name.replace("/", "") + if game == 'bf6': + name = name.replace("/", "").upper() + else: + name = name.replace("/", "") + logger.info(f"查询的物品: {name},图标类型:{icon_type},游戏:{game}") icon = get_icon_from_cache(name, game, icon_type) if not icon: if game == "bf1": @@ -257,8 +319,10 @@ def get_icon_from_url(url): def get_icon_from_cache(icon_name, game, icon_type): path = f"{filepath}/img/{game}/{icon_type}" + logger.info(f"查询物品:{icon_name}物品路径:{path}") try: icon_list = os.listdir(path) + # logger.info(f"所有物品:{icon_list}") if icon_name in str(icon_list): logger.info(f"本地存在{icon_name}物品") img = Image.open(f"{path}/{icon_name}.png").convert('RGBA') @@ -365,3 +429,129 @@ def notice_paste(cv2_bg): front_img = cutout_region(front_img, mask, alpha=0) mix_bg = paste_image_cv2(front_img, cv2_bg, pos) return mix_bg + + +def notice_paste_bf6(cv2_bg): + x, y = 0, 0 + + notice_path = f"{filepath}/notice/notice_bf6.png" + front_img = cv2.imread(notice_path, cv2.IMREAD_UNCHANGED) + + if front_img is None: + raise RuntimeError(f"Failed to load image: {notice_path}") + + h, w = front_img.shape[:2] + + # ROI 边界裁剪 + bg_h, bg_w = cv2_bg.shape[:2] + w = min(w, bg_w - x) + h = min(h, bg_h - y) + + roi = cv2_bg[y:y + h, x:x + w] + + # 有 Alpha 通道 → Alpha 混合 + if front_img.shape[2] == 4: + alpha = front_img[:h, :w, 3] / 255.0 + alpha = alpha[:, :, None] + + cv2_bg[y:y + h, x:x + w] = ( + alpha * front_img[:h, :w, :3] + + (1 - alpha) * roi + ).astype(np.uint8) + + # 无 Alpha → 直接覆盖 + else: + cv2_bg[y:y + h, x:x + w] = front_img[:h, :w] + + return cv2_bg + + +def designation_paste(player, + cv2_bg, + user_id, + start_x=10, + start_y=10, + target_height=40, + spacing=6 + ): + designation_list_path = get_designation_list_by_user_id(user_id, player) + if not designation_list_path: + return cv2_bg + + icons = [] + total_width = 0 + + for path in designation_list_path: + icon = cv2.imread(path, cv2.IMREAD_UNCHANGED) + if icon is None: + continue + + h, w = icon.shape[:2] + scale = target_height / h + new_w = int(w * scale) + + icon = cv2.resize(icon, (new_w, target_height)) + icons.append(icon) + total_width += new_w + + total_width += spacing * (len(icons) - 1) + + x = start_x + y = start_y # 关键变化点:直接使用 top-left + + bg_h, bg_w = cv2_bg.shape[:2] + + for icon in icons: + ih, iw = icon.shape[:2] + + if x + iw > bg_w or y + ih > bg_h: + break + + roi = cv2_bg[y:y + ih, x:x + iw] + + if icon.shape[2] == 4: + alpha = icon[:, :, 3] / 255.0 + for c in range(3): + roi[:, :, c] = roi[:, :, c] * (1 - alpha) + icon[:, :, c] * alpha + else: + roi[:] = icon + + cv2_bg[y:y + ih, x:x + iw] = roi + x += iw + spacing + + return cv2_bg + + +def get_designation_list_by_user_id(user_id, player): + usermanager = UserManager() + designationmanager = DesignationManager() + user_info = usermanager.get_user_by_qq(user_id) + icon_no_list = [] + if user_info is not None and user_info['ea_player_name'].upper() == player.upper(): + logger.info(f"玩家标签列表:{user_info}") + icon_no_list = user_info['designation'] + icon_list = designationmanager.get_designation_by_id_list(icon_no_list) + icon_path_list = [] + for icon in icon_list: + icon_file_name = icon['icon_path'] + icon_path_list.append(f"{filepath}/img/icon/designation/{icon_file_name}") + return icon_path_list + + +def paste_rank_icon(rank, img): + rank_pic_path = get_rank_pic(rank) + rank_icon_path = f"{filepath}/img/icon/rank/{rank_pic_path}" + rank_icon = Image.open(rank_icon_path) + rank_icon = png_resize(rank_icon, new_width=132, new_height=192) + fm_img = image_paste(rank_icon, img, (946, 61)) + return fm_img + + +def get_rank_pic(rank: int) -> str: + """ + 根据 rank 返回对应的 rank_pic 路径 + """ + for (start, end), info in rank_pic.items(): + if start <= rank <= end: + return info["path"] + return "t_ui_rankswatch_1-9 1.png" diff --git a/src/plugins/bf_bot/param.py b/src/plugins/bf_bot/param.py index 1c57dda..cbc4988 100644 --- a/src/plugins/bf_bot/param.py +++ b/src/plugins/bf_bot/param.py @@ -60,6 +60,28 @@ classes = { "Tanker": "坦克" } +mods = { + +} + +rank_pic = { + (0, 9): {"path": "t_ui_rankswatch_1-9 1.png"}, + (10, 24): {"path": "t_ui_rankswatch_10-24 1.png"}, + (25, 44): {"path": "t_ui_rankswatch_25-44 1.png"}, + (45, 49): {"path": "t_ui_rankswatch_45-49 1.png"}, + (50, 99): {"path": "t_ui_rankswatch_50-99 1.png"}, + (100, 149): {"path": "t_ui_rankswatch_100-149 1.png"}, + (150, 199): {"path": "t_ui_rankswatch_150-190 1.png"}, + (200, 249): {"path": "t_ui_rankswatch_200-240 1.png"}, + (250, 299): {"path": "t_ui_rankswatch_250-290 1.png"}, + (300, 349): {"path": "t_ui_rankswatch_300-340 1.png"}, + (350, 399): {"path": "t_ui_rankswatch_350-390 1.png"}, + (400, 449): {"path": "t_ui_rankswatch_400-450 1.png"}, + (450, 499): {"path": "t_ui_rankswatch_450-490 1.png"}, + (500, 2999): {"path": "t_ui_rankswatch_500-3000 1.png"}, + (3000, 5000): {"path": "t_ui_rankswatch_3000-5000 1.png"}, +} + bf_item = { "bf1": { "Wex": "韦克斯火焰喷射器", @@ -943,7 +965,19 @@ bf_item = { "AH-6J-LITTLE-BIRD1": "AH-6J-LITTLE-BIRD1", "T-90A1": "T-90A1", "HT-95-LEVKOV": "HT-95-LEVKOV" - } + }, + "bf6": {'L110': 'L110', 'PW5A3': 'PW5A3', 'M433': 'M433', 'RPKM': 'RPKM', 'M87A1': 'M87A1', 'P18': 'P18', + 'M277': 'M277', 'B36A4': 'B36A4', 'L85A3': 'L85A3', 'M2010 ESR': 'M2010 ESR', 'M1014': 'M1014', + 'AK-205': 'AK-205', 'SVK-8.6': 'SVK-8.6', 'SGX': 'SGX', 'LMR27': 'LMR27', 'QBZ-192': 'QBZ-192', + 'M417 A2': 'M417 A2', 'DRS-IAR': 'DRS-IAR', 'KORD 6P67': 'KORD 6P67', 'USG-90': 'USG-90', 'M4A1': 'M4A1', + 'KTS100 MK8': 'KTS100 MK8', 'M45A1': 'M45A1', 'KV9': 'KV9', 'SOR-556 Mk2': 'SOR-556 MK2', 'PW7A2': 'PW7A2', + 'M123K': 'M123K', 'M44': 'M44', 'M250': 'M250', 'UMG-40': 'UMG-40', 'TR-7': 'TR-7', 'SL9': 'SL9', + 'M240L': 'M240L', 'SCW-10': 'SCW-10', 'NVO-228E': 'NVO-228E', 'M/60': 'M/60', 'PSR': 'PSR', 'SVDM': 'SVDM', + 'AK4D': 'AK4D', 'SOR-300SC': 'SOR-300SC', 'SG 553R': 'SG 553R', 'GRT-BC': 'GRT-BC', '18.5KS-K': '18.5KS-K', + 'ES 5.7': 'ES 5.7', 'M39 EMR': 'M39 EMR', 'SV-98': 'SV-98', 'Panthera KHT': 'PANTHERA KHT', + 'M77E Falchion': 'M77E FALCHION', 'Leo A4': 'LEO A4', 'Strf 09 A4': 'STRF 09 A4', + 'M1A2 SEPv3': 'M1A2 SEPV3', 'Cheetah 1A2': 'CHEETAH 1A2', 'Glider 96': 'GLIDER 96', + 'M3A3 Bradley': 'M3A3 BRADLEY', 'Su-57': 'SU-57', 'F-61V': 'F-61V', 'F-39E': 'F-39E', 'VECTOR': 'VECTOR'} } color_select = { diff --git a/src/plugins/bf_bot/test.py b/src/plugins/bf_bot/test.py index c241d2e..14deb85 100644 --- a/src/plugins/bf_bot/test.py +++ b/src/plugins/bf_bot/test.py @@ -1,7 +1,3380 @@ -from get_bf6_data import * +import asyncio +from PIL import Image, ImageDraw, ImageFont +from tracker_data import * + +weapon_data = { + "weapons": [ + { + "type": "Machine Guns", + "weaponName": "L110", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Minimi_PKG_Factory_MED-0e29fce7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Minimi_PKG_Factory_MED-0e29fce7.webp", + "id": "mg_l110", + "kills": 74, + "damage": 15353, + "assistsDamage": 35, + "bodyKills": 61, + "headshotKills": 13, + "hipfireKills": 1, + "multiKills": 12, + "accuracy": "9.52%", + "killsPerMinute": 1.07, + "damagePerMinute": 222.29, + "headshots": "17.57%", + "hitVKills": 8.59, + "shotsHit": 636, + "shotsFired": 6683, + "scopedKills": 73, + "spawns": 39, + "timeEquipped": 4144 + }, + { + "type": "SMG-PDWs", + "weaponName": "PW5A3", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MP5MLI_PKG_Factory_MED-2d1944b7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MP5MLI_PKG_Factory_MED-2d1944b7.webp", + "id": "smg_pw5a3", + "kills": 7, + "damage": 1562, + "assistsDamage": 1, + "bodyKills": 7, + "headshotKills": 0, + "hipfireKills": 1, + "multiKills": 0, + "accuracy": "18.99%", + "killsPerMinute": 0.46, + "damagePerMinute": 102.99, + "headshots": "0.0%", + "hitVKills": 18.71, + "shotsHit": 131, + "shotsFired": 690, + "scopedKills": 6, + "spawns": 0, + "timeEquipped": 910 + }, + { + "type": "Assault Rifles", + "weaponName": "M433", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_HK433_PKG_Factory_MED-b06f02f7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_HK433_PKG_Factory_MED-b06f02f7.webp", + "id": "ar_m433", + "kills": 607, + "damage": 71600, + "assistsDamage": 284, + "bodyKills": 526, + "headshotKills": 81, + "hipfireKills": 96, + "multiKills": 78, + "accuracy": "13.12%", + "killsPerMinute": 1.71, + "damagePerMinute": 201.52, + "headshots": "13.34%", + "hitVKills": 4.84, + "shotsHit": 2939, + "shotsFired": 22402, + "scopedKills": 511, + "spawns": 390, + "timeEquipped": 21318 + }, + { + "type": "Machine Guns", + "weaponName": "RPKM", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_RPKM_PKG_Factory_MED-755b785f.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_RPKM_PKG_Factory_MED-755b785f.webp", + "id": "mg_rpkm", + "kills": 88, + "damage": 16592, + "assistsDamage": 22, + "bodyKills": 80, + "headshotKills": 8, + "hipfireKills": 6, + "multiKills": 9, + "accuracy": "24.84%", + "killsPerMinute": 1.08, + "damagePerMinute": 202.79, + "headshots": "9.09%", + "hitVKills": 12.9, + "shotsHit": 1135, + "shotsFired": 4570, + "scopedKills": 82, + "spawns": 1, + "timeEquipped": 4909 + }, + { + "type": "Shotguns", + "weaponName": "M87A1", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_590A1_PKG_Factory_MED-4b387330.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_590A1_PKG_Factory_MED-4b387330.webp", + "id": "sg_m87a1", + "kills": 351, + "damage": 22678, + "assistsDamage": 72, + "bodyKills": 166, + "headshotKills": 185, + "hipfireKills": 122, + "multiKills": 31, + "accuracy": "91.29%", + "killsPerMinute": 2.72, + "damagePerMinute": 175.44, + "headshots": "52.71%", + "hitVKills": 1.88, + "shotsHit": 660, + "shotsFired": 723, + "scopedKills": 229, + "spawns": 149, + "timeEquipped": 7756 + }, + { + "type": "Pistols", + "weaponName": "P18", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M18_PKG_Factory_MED-88261bf8.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M18_PKG_Factory_MED-88261bf8.webp", + "id": "pst_p18", + "kills": 14, + "damage": 2080, + "assistsDamage": 12, + "bodyKills": 9, + "headshotKills": 5, + "hipfireKills": 6, + "multiKills": 4, + "accuracy": "23.77%", + "killsPerMinute": 0.79, + "damagePerMinute": 116.85, + "headshots": "35.71%", + "hitVKills": 6.93, + "shotsHit": 97, + "shotsFired": 408, + "scopedKills": 8, + "spawns": 1336, + "timeEquipped": 1068 + }, + { + "type": "Carbines", + "weaponName": "M277", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_XM7_PKG_Factory_MED-26271094.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_XM7_PKG_Factory_MED-26271094.webp", + "id": "crb_x277", + "kills": 420, + "damage": 52607, + "assistsDamage": 174, + "bodyKills": 309, + "headshotKills": 111, + "hipfireKills": 17, + "multiKills": 38, + "accuracy": "17.03%", + "killsPerMinute": 1.85, + "damagePerMinute": 231.61, + "headshots": "26.43%", + "hitVKills": 4.32, + "shotsHit": 1813, + "shotsFired": 10649, + "scopedKills": 403, + "spawns": 238, + "timeEquipped": 13628 + }, + { + "type": "Assault Rifles", + "weaponName": "B36A4", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_G36_PKG_Factory_MED-fb5466ec.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_G36_PKG_Factory_MED-fb5466ec.webp", + "id": "ar_b36a4", + "kills": 1045, + "damage": 48359, + "assistsDamage": 141, + "bodyKills": 547, + "headshotKills": 498, + "hipfireKills": 44, + "multiKills": 24, + "accuracy": "19.59%", + "killsPerMinute": 3.73, + "damagePerMinute": 172.69, + "headshots": "47.66%", + "hitVKills": 3.22, + "shotsHit": 3363, + "shotsFired": 17165, + "scopedKills": 1001, + "spawns": 172, + "timeEquipped": 16802 + }, + { + "type": "Assault Rifles", + "weaponName": "L85A3", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_L85A3_PKG_Factory_MED-9bd0deaa.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_L85A3_PKG_Factory_MED-9bd0deaa.webp", + "id": "ar_l85a3", + "kills": 785, + "damage": 16153, + "assistsDamage": 60, + "bodyKills": 315, + "headshotKills": 470, + "hipfireKills": 8, + "multiKills": 4, + "accuracy": "28.29%", + "killsPerMinute": 7.26, + "damagePerMinute": 149.47, + "headshots": "59.87%", + "hitVKills": 2.05, + "shotsHit": 1609, + "shotsFired": 5687, + "scopedKills": 777, + "spawns": 111, + "timeEquipped": 6484 + }, + { + "type": "Rifles", + "weaponName": "M2010 ESR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M2010ESR_PKG_Factory_MED-f94fdae6.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M2010ESR_PKG_Factory_MED-f94fdae6.webp", + "id": "snp_m2010", + "kills": 553, + "damage": 53403, + "assistsDamage": 32, + "bodyKills": 150, + "headshotKills": 403, + "hipfireKills": 200, + "multiKills": 51, + "accuracy": "47.56%", + "killsPerMinute": 2.49, + "damagePerMinute": 240.36, + "headshots": "72.88%", + "hitVKills": 1.37, + "shotsHit": 760, + "shotsFired": 1598, + "scopedKills": 353, + "spawns": 81, + "timeEquipped": 13331 + }, + { + "type": "Shotguns", + "weaponName": "M1014", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M1014_PKG_Factory_MED-e011854a.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M1014_PKG_Factory_MED-e011854a.webp", + "id": "sg_m1014", + "kills": 142, + "damage": 15520, + "assistsDamage": 19, + "bodyKills": 127, + "headshotKills": 15, + "hipfireKills": 138, + "multiKills": 11, + "accuracy": "76.98%", + "killsPerMinute": 4.06, + "damagePerMinute": 444.27, + "headshots": "10.56%", + "hitVKills": 2.8, + "shotsHit": 398, + "shotsFired": 517, + "scopedKills": 4, + "spawns": 31, + "timeEquipped": 2096 + }, + { + "type": "Carbines", + "weaponName": "AK-205", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_AK205_PKG_Factory_MED-6d376081.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_AK205_PKG_Factory_MED-6d376081.webp", + "id": "crb_ak205", + "kills": 30, + "damage": 5519, + "assistsDamage": 29, + "bodyKills": 25, + "headshotKills": 5, + "hipfireKills": 6, + "multiKills": 0, + "accuracy": "12.01%", + "killsPerMinute": 0.76, + "damagePerMinute": 139.49, + "headshots": "16.67%", + "hitVKills": 12.8, + "shotsHit": 384, + "shotsFired": 3197, + "scopedKills": 24, + "spawns": 26, + "timeEquipped": 2374 + }, + { + "type": "DMRs", + "weaponName": "SVK-8.6", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SVCh_PKG_Factory_MED-bb06d385.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SVCh_PKG_Factory_MED-bb06d385.webp", + "id": "dmr_svk86", + "kills": 262, + "damage": 42653, + "assistsDamage": 95, + "bodyKills": 144, + "headshotKills": 118, + "hipfireKills": 2, + "multiKills": 36, + "accuracy": "33.32%", + "killsPerMinute": 1.31, + "damagePerMinute": 212.95, + "headshots": "45.04%", + "hitVKills": 3.19, + "shotsHit": 837, + "shotsFired": 2512, + "scopedKills": 260, + "spawns": 76, + "timeEquipped": 12018 + }, + { + "type": "SMG-PDWs", + "weaponName": "SGX", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MPX_PKG_Factory_MED-e822f017.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MPX_PKG_Factory_MED-e822f017.webp", + "id": "smg_sgx", + "kills": 9788, + "damage": 526470, + "assistsDamage": 7, + "bodyKills": 7110, + "headshotKills": 2678, + "hipfireKills": 3088, + "multiKills": 85, + "accuracy": "54.83%", + "killsPerMinute": 56.3, + "damagePerMinute": 3028.3, + "headshots": "27.36%", + "hitVKills": 2.37, + "shotsHit": 23240, + "shotsFired": 42387, + "scopedKills": 6700, + "spawns": 65, + "timeEquipped": 10431 + }, + { + "type": "DMRs", + "weaponName": "LMR27", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_ARADMR_PKG_Factory_MED-dfe224de.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_ARADMR_PKG_Factory_MED-dfe224de.webp", + "id": "dmr_lmr27", + "kills": 5, + "damage": 765, + "assistsDamage": 2, + "bodyKills": 5, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "30.0%", + "killsPerMinute": 1.18, + "damagePerMinute": 180.0, + "headshots": "0.0%", + "hitVKills": 7.2, + "shotsHit": 36, + "shotsFired": 120, + "scopedKills": 5, + "spawns": 3, + "timeEquipped": 255 + }, + { + "type": "Carbines", + "weaponName": "QBZ-192", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_QBZ192_PKG_Factory_MED-dc0a546b.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_QBZ192_PKG_Factory_MED-dc0a546b.webp", + "id": "crb_qbz192", + "kills": 75, + "damage": 10219, + "assistsDamage": 52, + "bodyKills": 72, + "headshotKills": 3, + "hipfireKills": 4, + "multiKills": 7, + "accuracy": "12.36%", + "killsPerMinute": 1.08, + "damagePerMinute": 147.64, + "headshots": "4.0%", + "hitVKills": 3.83, + "shotsHit": 287, + "shotsFired": 2322, + "scopedKills": 71, + "spawns": 104, + "timeEquipped": 4153 + }, + { + "type": "Carbines", + "weaponName": "M417 A2", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_HK417A2_PKG_Factory_MED-494ffe6e.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_HK417A2_PKG_Factory_MED-494ffe6e.webp", + "id": "crb_m417a2", + "kills": 1942, + "damage": 52408, + "assistsDamage": 156, + "bodyKills": 638, + "headshotKills": 1304, + "hipfireKills": 103, + "multiKills": 54, + "accuracy": "24.49%", + "killsPerMinute": 6.87, + "damagePerMinute": 185.47, + "headshots": "67.15%", + "hitVKills": 1.78, + "shotsHit": 3464, + "shotsFired": 14143, + "scopedKills": 1839, + "spawns": 266, + "timeEquipped": 16954 + }, + { + "type": "Machine Guns", + "weaponName": "DRS-IAR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M27IAR_PKG_Factory_MED-ae6675cd.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M27IAR_PKG_Factory_MED-ae6675cd.webp", + "id": "mg_drsiar", + "kills": 729, + "damage": 83389, + "assistsDamage": 45, + "bodyKills": 599, + "headshotKills": 130, + "hipfireKills": 115, + "multiKills": 61, + "accuracy": "28.88%", + "killsPerMinute": 5.56, + "damagePerMinute": 636.4, + "headshots": "17.83%", + "hitVKills": 4.49, + "shotsHit": 3270, + "shotsFired": 11323, + "scopedKills": 614, + "spawns": 77, + "timeEquipped": 7862 + }, + { + "type": "Assault Rifles", + "weaponName": "KORD 6P67", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_6P67_PKG_Factory_MED-827b9414.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_6P67_PKG_Factory_MED-827b9414.webp", + "id": "ar_kord6p67", + "kills": 502, + "damage": 64820, + "assistsDamage": 98, + "bodyKills": 429, + "headshotKills": 73, + "hipfireKills": 42, + "multiKills": 107, + "accuracy": "25.85%", + "killsPerMinute": 2.55, + "damagePerMinute": 328.9, + "headshots": "14.54%", + "hitVKills": 7.41, + "shotsHit": 3722, + "shotsFired": 14397, + "scopedKills": 460, + "spawns": 178, + "timeEquipped": 11825 + }, + { + "type": "SMG-PDWs", + "weaponName": "USG-90", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_P90_PKG_Factory_MED-2ab1db64.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_P90_PKG_Factory_MED-2ab1db64.webp", + "id": "smg_usg90", + "kills": 10, + "damage": 1217, + "assistsDamage": 4, + "bodyKills": 6, + "headshotKills": 4, + "hipfireKills": 3, + "multiKills": 1, + "accuracy": "16.58%", + "killsPerMinute": 0.75, + "damagePerMinute": 91.39, + "headshots": "40.0%", + "hitVKills": 6.6, + "shotsHit": 66, + "shotsFired": 398, + "scopedKills": 7, + "spawns": 0, + "timeEquipped": 799 + }, + { + "type": "Carbines", + "weaponName": "M4A1", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M4A1_PKG_Factory_MED-34529a82.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M4A1_PKG_Factory_MED-34529a82.webp", + "id": "crb_m4a1", + "kills": 2309, + "damage": 36071, + "assistsDamage": 141, + "bodyKills": 730, + "headshotKills": 1579, + "hipfireKills": 92, + "multiKills": 42, + "accuracy": "26.14%", + "killsPerMinute": 13.41, + "damagePerMinute": 209.53, + "headshots": "68.38%", + "hitVKills": 1.6, + "shotsHit": 3691, + "shotsFired": 14118, + "scopedKills": 2217, + "spawns": 199, + "timeEquipped": 10329 + }, + { + "type": "Machine Guns", + "weaponName": "KTS100 MK8", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Ultimax_PKG_Factory_MED-a8ebb482.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Ultimax_PKG_Factory_MED-a8ebb482.webp", + "id": "mg_kts100mk8", + "kills": 4524, + "damage": 25524, + "assistsDamage": 76, + "bodyKills": 1865, + "headshotKills": 2659, + "hipfireKills": 54, + "multiKills": 23, + "accuracy": "41.99%", + "killsPerMinute": 19.76, + "damagePerMinute": 111.48, + "headshots": "58.78%", + "hitVKills": 1.38, + "shotsHit": 6236, + "shotsFired": 14851, + "scopedKills": 4470, + "spawns": 88, + "timeEquipped": 13737 + }, + { + "type": "Pistols", + "weaponName": "M45A1", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M45A1_PKG_Factory_MED-8c41691b.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M45A1_PKG_Factory_MED-8c41691b.webp", + "id": "pst_m45a1", + "kills": 228, + "damage": 252, + "assistsDamage": 0, + "bodyKills": 30, + "headshotKills": 198, + "hipfireKills": 37, + "multiKills": 2, + "accuracy": "211.11%", + "killsPerMinute": 93.7, + "damagePerMinute": 103.56, + "headshots": "86.84%", + "hitVKills": 1.0, + "shotsHit": 228, + "shotsFired": 108, + "scopedKills": 191, + "spawns": 69, + "timeEquipped": 146 + }, + { + "type": "SMG-PDWs", + "weaponName": "KV9", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Vector_PKG_Factory_MED-b5631ed7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Vector_PKG_Factory_MED-b5631ed7.webp", + "id": "smg_kv9", + "kills": 169, + "damage": 21081, + "assistsDamage": 83, + "bodyKills": 148, + "headshotKills": 21, + "hipfireKills": 58, + "multiKills": 18, + "accuracy": "16.2%", + "killsPerMinute": 1.42, + "damagePerMinute": 177.47, + "headshots": "12.43%", + "hitVKills": 5.8, + "shotsHit": 981, + "shotsFired": 6057, + "scopedKills": 111, + "spawns": 142, + "timeEquipped": 7127 + }, + { + "type": "Assault Rifles", + "weaponName": "SOR-556 Mk2", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SCARL_PKG_Factory_MED-b44467bb.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SCARL_PKG_Factory_MED-b44467bb.webp", + "id": "ar_sor556mk2", + "kills": 451, + "damage": 54559, + "assistsDamage": 175, + "bodyKills": 367, + "headshotKills": 84, + "hipfireKills": 23, + "multiKills": 47, + "accuracy": "20.04%", + "killsPerMinute": 2.27, + "damagePerMinute": 274.14, + "headshots": "18.63%", + "hitVKills": 4.89, + "shotsHit": 2205, + "shotsFired": 11002, + "scopedKills": 428, + "spawns": 139, + "timeEquipped": 11941 + }, + { + "type": "SMG-PDWs", + "weaponName": "PW7A2", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MP7A2_PKG_Factory_MED-406bc965.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MP7A2_PKG_Factory_MED-406bc965.webp", + "id": "smg_pw7a2", + "kills": 216, + "damage": 20576, + "assistsDamage": 15, + "bodyKills": 201, + "headshotKills": 15, + "hipfireKills": 75, + "multiKills": 54, + "accuracy": "26.43%", + "killsPerMinute": 5.13, + "damagePerMinute": 488.55, + "headshots": "6.94%", + "hitVKills": 6.2, + "shotsHit": 1339, + "shotsFired": 5066, + "scopedKills": 141, + "spawns": 4, + "timeEquipped": 2527 + }, + { + "type": "Machine Guns", + "weaponName": "M123K", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MG4K_PKG_Factory_MED-cc064690.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MG4K_PKG_Factory_MED-cc064690.webp", + "id": "mg_m123k", + "kills": 84, + "damage": 15303, + "assistsDamage": 40, + "bodyKills": 75, + "headshotKills": 9, + "hipfireKills": 22, + "multiKills": 8, + "accuracy": "12.66%", + "killsPerMinute": 1.03, + "damagePerMinute": 187.92, + "headshots": "10.71%", + "hitVKills": 11.15, + "shotsHit": 937, + "shotsFired": 7403, + "scopedKills": 62, + "spawns": 63, + "timeEquipped": 4886 + }, + { + "type": "Pistols", + "weaponName": "M44", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_RagingHunter_PKG_Factory_MED-f9773307.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_RagingHunter_PKG_Factory_MED-f9773307.webp", + "id": "pst_m44", + "kills": 18, + "damage": 4263, + "assistsDamage": 14, + "bodyKills": 12, + "headshotKills": 6, + "hipfireKills": 4, + "multiKills": 0, + "accuracy": "34.78%", + "killsPerMinute": 0.27, + "damagePerMinute": 63.98, + "headshots": "33.33%", + "hitVKills": 5.78, + "shotsHit": 104, + "shotsFired": 299, + "scopedKills": 14, + "spawns": 854, + "timeEquipped": 3998 + }, + { + "type": "Machine Guns", + "weaponName": "M250", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M250_PKG_Factory_MED-6e230a71.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M250_PKG_Factory_MED-6e230a71.webp", + "id": "mg_xm250", + "kills": 328, + "damage": 38530, + "assistsDamage": 90, + "bodyKills": 289, + "headshotKills": 39, + "hipfireKills": 27, + "multiKills": 58, + "accuracy": "18.11%", + "killsPerMinute": 2.33, + "damagePerMinute": 273.68, + "headshots": "11.89%", + "hitVKills": 4.3, + "shotsHit": 1412, + "shotsFired": 7796, + "scopedKills": 301, + "spawns": 166, + "timeEquipped": 8447 + }, + { + "type": "SMG-PDWs", + "weaponName": "UMG-40", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_UMP40_PKG_Factory_MED-22afa646.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_UMP40_PKG_Factory_MED-22afa646.webp", + "id": "smg_umg40", + "kills": 4, + "damage": 926, + "assistsDamage": 1, + "bodyKills": 4, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 1, + "accuracy": "24.37%", + "killsPerMinute": 0.43, + "damagePerMinute": 98.51, + "headshots": "0.0%", + "hitVKills": 21.75, + "shotsHit": 87, + "shotsFired": 357, + "scopedKills": 4, + "spawns": 3, + "timeEquipped": 564 + }, + { + "type": "Assault Rifles", + "weaponName": "TR-7", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Tavor7_PKG_Factory_MED-e682f267.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Tavor7_PKG_Factory_MED-e682f267.webp", + "id": "ar_tr7", + "kills": 616, + "damage": 68498, + "assistsDamage": 107, + "bodyKills": 474, + "headshotKills": 142, + "hipfireKills": 143, + "multiKills": 55, + "accuracy": "16.89%", + "killsPerMinute": 2.46, + "damagePerMinute": 273.5, + "headshots": "23.05%", + "hitVKills": 3.68, + "shotsHit": 2268, + "shotsFired": 13428, + "scopedKills": 473, + "spawns": 252, + "timeEquipped": 15027 + }, + { + "type": "SMG-PDWs", + "weaponName": "SL9", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_APDW_PKG_Factory_MED-c4d1b829.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_APDW_PKG_Factory_MED-c4d1b829.webp", + "id": "smg_sl9", + "kills": 376, + "damage": 37358, + "assistsDamage": 17, + "bodyKills": 316, + "headshotKills": 60, + "hipfireKills": 19, + "multiKills": 77, + "accuracy": "21.84%", + "killsPerMinute": 4.86, + "damagePerMinute": 483.08, + "headshots": "15.96%", + "hitVKills": 4.85, + "shotsHit": 1824, + "shotsFired": 8350, + "scopedKills": 357, + "spawns": 25, + "timeEquipped": 4640 + }, + { + "type": "Machine Guns", + "weaponName": "M240L", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M240L_PKG_Factory_MED-1fa18e0c.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M240L_PKG_Factory_MED-1fa18e0c.webp", + "id": "mg_m240l", + "kills": 45, + "damage": 4029, + "assistsDamage": 0, + "bodyKills": 40, + "headshotKills": 5, + "hipfireKills": 3, + "multiKills": 3, + "accuracy": "31.3%", + "killsPerMinute": 7.03, + "damagePerMinute": 629.53, + "headshots": "11.11%", + "hitVKills": 3.31, + "shotsHit": 149, + "shotsFired": 476, + "scopedKills": 42, + "spawns": 1, + "timeEquipped": 384 + }, + { + "type": "SMG-PDWs", + "weaponName": "SCW-10", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_APC10_PKG_Factory_MED-716a97fb.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_APC10_PKG_Factory_MED-716a97fb.webp", + "id": "smg_scw10", + "kills": 571, + "damage": 61171, + "assistsDamage": 139, + "bodyKills": 495, + "headshotKills": 76, + "hipfireKills": 48, + "multiKills": 105, + "accuracy": "18.37%", + "killsPerMinute": 2.47, + "damagePerMinute": 264.68, + "headshots": "13.31%", + "hitVKills": 4.04, + "shotsHit": 2308, + "shotsFired": 12565, + "scopedKills": 523, + "spawns": 232, + "timeEquipped": 13867 + }, + { + "type": "Assault Rifles", + "weaponName": "NVO-228E", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_ACE32_PKG_Factory_MED-39a97220.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_ACE32_PKG_Factory_MED-39a97220.webp", + "id": "ar_nvo228e", + "kills": 960, + "damage": 61885, + "assistsDamage": 101, + "bodyKills": 611, + "headshotKills": 349, + "hipfireKills": 72, + "multiKills": 39, + "accuracy": "28.84%", + "killsPerMinute": 5.78, + "damagePerMinute": 372.69, + "headshots": "36.35%", + "hitVKills": 2.44, + "shotsHit": 2344, + "shotsFired": 8128, + "scopedKills": 888, + "spawns": 114, + "timeEquipped": 9963 + }, + { + "type": "Machine Guns", + "weaponName": "M/60", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M60E6_PKG_Factory_MED-e600bb28.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M60E6_PKG_Factory_MED-e600bb28.webp", + "id": "mg_m60", + "kills": 5, + "damage": 1191, + "assistsDamage": 5, + "bodyKills": 5, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 1, + "accuracy": "6.74%", + "killsPerMinute": 0.47, + "damagePerMinute": 112.01, + "headshots": "0.0%", + "hitVKills": 11.8, + "shotsHit": 59, + "shotsFired": 876, + "scopedKills": 5, + "spawns": 1, + "timeEquipped": 638 + }, + { + "type": "Rifles", + "weaponName": "PSR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MRAD_PKG_Factory_MED-5035ce99.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MRAD_PKG_Factory_MED-5035ce99.webp", + "id": "snp_psr", + "kills": 39, + "damage": 7457, + "assistsDamage": 11, + "bodyKills": 17, + "headshotKills": 22, + "hipfireKills": 22, + "multiKills": 0, + "accuracy": "30.75%", + "killsPerMinute": 0.49, + "damagePerMinute": 94.61, + "headshots": "56.41%", + "hitVKills": 3.56, + "shotsHit": 139, + "shotsFired": 452, + "scopedKills": 17, + "spawns": 9, + "timeEquipped": 4729 + }, + { + "type": "DMRs", + "weaponName": "SVDM", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SVDM_PKG_Factory_MED-b6c9aa50.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SVDM_PKG_Factory_MED-b6c9aa50.webp", + "id": "dmr_svdm", + "kills": 3, + "damage": 475, + "assistsDamage": 3, + "bodyKills": 1, + "headshotKills": 2, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "20.0%", + "killsPerMinute": 0.28, + "damagePerMinute": 44.88, + "headshots": "66.67%", + "hitVKills": 6.33, + "shotsHit": 19, + "shotsFired": 95, + "scopedKills": 3, + "spawns": 1, + "timeEquipped": 635 + }, + { + "type": "Assault Rifles", + "weaponName": "AK4D", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_G3A4_PKG_Factory_MED-0575cf00.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_G3A4_PKG_Factory_MED-0575cf00.webp", + "id": "ar_ak4d", + "kills": 155, + "damage": 17827, + "assistsDamage": 48, + "bodyKills": 147, + "headshotKills": 8, + "hipfireKills": 6, + "multiKills": 23, + "accuracy": "20.76%", + "killsPerMinute": 1.53, + "damagePerMinute": 176.24, + "headshots": "5.16%", + "hitVKills": 4.49, + "shotsHit": 696, + "shotsFired": 3353, + "scopedKills": 149, + "spawns": 80, + "timeEquipped": 6069 + }, + { + "type": "Carbines", + "weaponName": "SOR-300SC", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SCARSC_PKG_Factory_MED-7a6a50ff.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SCARSC_PKG_Factory_MED-7a6a50ff.webp", + "id": "crb_sor300sc", + "kills": 5, + "damage": 1016, + "assistsDamage": 4, + "bodyKills": 4, + "headshotKills": 1, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "12.99%", + "killsPerMinute": 0.24, + "damagePerMinute": 47.77, + "headshots": "20.0%", + "hitVKills": 20.0, + "shotsHit": 100, + "shotsFired": 770, + "scopedKills": 5, + "spawns": 0, + "timeEquipped": 1276 + }, + { + "type": "Carbines", + "weaponName": "SG 553R", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SIG553R_PKG_Factory_MED-afc2dfa8.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SIG553R_PKG_Factory_MED-afc2dfa8.webp", + "id": "crb_sg553r", + "kills": 4207, + "damage": 30073, + "assistsDamage": 119, + "bodyKills": 3204, + "headshotKills": 1003, + "hipfireKills": 1264, + "multiKills": 37, + "accuracy": "45.09%", + "killsPerMinute": 21.64, + "damagePerMinute": 154.71, + "headshots": "23.84%", + "hitVKills": 1.16, + "shotsHit": 4895, + "shotsFired": 10855, + "scopedKills": 2943, + "spawns": 200, + "timeEquipped": 11663 + }, + { + "type": "Carbines", + "weaponName": "GRT-BC", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MSBSGROTB_PKG_Factory_MED-25acf006.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MSBSGROTB_PKG_Factory_MED-25acf006.webp", + "id": "crb_grtbc", + "kills": 22, + "damage": 3216, + "assistsDamage": 20, + "bodyKills": 17, + "headshotKills": 5, + "hipfireKills": 7, + "multiKills": 1, + "accuracy": "12.16%", + "killsPerMinute": 0.76, + "damagePerMinute": 111.15, + "headshots": "22.73%", + "hitVKills": 7.95, + "shotsHit": 175, + "shotsFired": 1439, + "scopedKills": 15, + "spawns": 21, + "timeEquipped": 1736 + }, + { + "type": "Shotguns", + "weaponName": "18.5KS-K", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_185KSK_PKG_Factory_MED-432c353f.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MSBSGROTB_PKG_Factory_MED-25acf006.webp", + "id": "sg_185ksk", + "kills": 17, + "damage": 2390, + "assistsDamage": 9, + "bodyKills": 15, + "headshotKills": 2, + "hipfireKills": 17, + "multiKills": 1, + "accuracy": "22.83%", + "killsPerMinute": 0.87, + "damagePerMinute": 122.46, + "headshots": "11.76%", + "hitVKills": 2.94, + "shotsHit": 50, + "shotsFired": 219, + "scopedKills": 0, + "spawns": 30, + "timeEquipped": 1171 + }, + { + "type": "Pistols", + "weaponName": "ES 5.7", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M18_PKG_Factory_MED-88261bf8.webp", + "id": "pst_es57", + "kills": 9183, + "damage": 565421, + "assistsDamage": 7, + "bodyKills": 3568, + "headshotKills": 5615, + "hipfireKills": 2930, + "multiKills": 60, + "accuracy": "105.3%", + "killsPerMinute": 51.52, + "damagePerMinute": 3172.07, + "headshots": "61.15%", + "hitVKills": 2.51, + "shotsHit": 23019, + "shotsFired": 21860, + "scopedKills": 6253, + "spawns": 715, + "timeEquipped": 10695 + }, + { + "type": "DMRs", + "weaponName": "M39 EMR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SVCh_PKG_Factory_MED-bb06d385.webp", + "id": "dmr_m39emr", + "kills": 0, + "damage": 0, + "assistsDamage": 0, + "bodyKills": 0, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "0.0%", + "killsPerMinute": 0.0, + "damagePerMinute": 0.0, + "headshots": "0.0%", + "hitVKills": 0.0, + "shotsHit": 0, + "shotsFired": 0, + "scopedKills": 0, + "spawns": 0, + "timeEquipped": 45 + }, + { + "type": "Rifles", + "weaponName": "SV-98", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M2010ESR_PKG_Factory_MED-f94fdae6.webp", + "id": "snp_sv98", + "kills": 2, + "damage": 334, + "assistsDamage": 1, + "bodyKills": 1, + "headshotKills": 1, + "hipfireKills": 1, + "multiKills": 0, + "accuracy": "25.93%", + "killsPerMinute": 0.3, + "damagePerMinute": 50.1, + "headshots": "50.0%", + "hitVKills": 3.5, + "shotsHit": 7, + "shotsFired": 27, + "scopedKills": 1, + "spawns": 1, + "timeEquipped": 400 + } + ], +} +vehicle_data = { + "vehicles": [ + { + "type": "Air Combat", + "vehicleName": "Panthera KHT", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Eurocopter_VSD0001-8003028d.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Eurocopter_VSD0001-8003028d.webp", + "id": "air_panthera", + "kills": 166, + "killsPerMinute": 7.07, + "damage": 27206, + "spawns": 6, + "roadKills": 7, + "passengerAssists": 13, + "multiKills": 5, + "distanceTraveled": 50779, + "driverAssists": 1, + "vehiclesDestroyedWith": 7, + "assists": 14, + "damageTo": 3918, + "destroyed": 0, + "timeIn": 1408 + }, + { + "type": "Air Combat", + "vehicleName": "M77E Falchion", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "id": "air_m77efalchio", + "kills": 0, + "killsPerMinute": 0, + "damage": 0, + "spawns": 0, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 0, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 0, + "destroyed": 0, + "timeIn": 0 + }, + { + "type": "Ground Combat", + "vehicleName": "Leo A4", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Leopard_VSD0001-f8da51ee.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Leopard_VSD0001-f8da51ee.webp", + "id": "sur_leoa4", + "kills": 22, + "killsPerMinute": 0.74, + "damage": 19307, + "spawns": 8, + "roadKills": 1, + "passengerAssists": 1, + "multiKills": 2, + "distanceTraveled": 6115, + "driverAssists": 13, + "vehiclesDestroyedWith": 1, + "assists": 14, + "damageTo": 43760, + "destroyed": 6, + "timeIn": 1789 + }, + { + "type": "Ground Combat", + "vehicleName": "Strf 09 A4", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_CV90_VSD0001-acd942b6.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_CV90_VSD0001-acd942b6.webp", + "id": "sur_strf09a4", + "kills": 140, + "killsPerMinute": 1.76, + "damage": 25699, + "spawns": 196, + "roadKills": 0, + "passengerAssists": 52, + "multiKills": 27, + "distanceTraveled": 12701, + "driverAssists": 41, + "vehiclesDestroyedWith": 2, + "assists": 93, + "damageTo": 20875, + "destroyed": 1, + "timeIn": 4770 + }, + { + "type": "Ground Combat", + "vehicleName": "M1A2 SEPv3", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Abrams_VSD0001-5412a78d.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Abrams_VSD0001-5412a78d.webp", + "id": "sur_m1a2sepv3", + "kills": 236, + "killsPerMinute": 1.54, + "damage": 67333, + "spawns": 46, + "roadKills": 0, + "passengerAssists": 164, + "multiKills": 32, + "distanceTraveled": 19222, + "driverAssists": 102, + "vehiclesDestroyedWith": 6, + "assists": 266, + "damageTo": 50600, + "destroyed": 9, + "timeIn": 9195 + }, + { + "type": "Ground Combat", + "vehicleName": "Cheetah 1A2", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Gepard_VSD0001-d796732f.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Gepard_VSD0001-d796732f.webp", + "id": "sur_cheetah1a2", + "kills": 0, + "killsPerMinute": 0.0, + "damage": 1521, + "spawns": 1, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 737, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 9876, + "destroyed": 0, + "timeIn": 139 + }, + { + "type": "Ground Combat", + "vehicleName": "Glider 96", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Flyer60_VSD0005-1569869f.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Flyer60_VSD0005-1569869f.webp", + "id": "sur_glider96", + "kills": 6, + "killsPerMinute": 0.28, + "damage": 1648, + "spawns": 7, + "roadKills": 1, + "passengerAssists": 0, + "multiKills": 1, + "distanceTraveled": 9884, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 14447, + "destroyed": 0, + "timeIn": 1298 + }, + { + "type": "Ground Combat", + "vehicleName": "M3A3 Bradley", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_OB_VEH_Tank_Bradley_VSD0001_Dressing-66f252ca.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_OB_VEH_Tank_Bradley_VSD0001_Dressing-66f252ca.webp", + "id": "sur_bradley", + "kills": 82, + "killsPerMinute": 1.15, + "damage": 16995, + "spawns": 59, + "roadKills": 0, + "passengerAssists": 60, + "multiKills": 12, + "distanceTraveled": 14396, + "driverAssists": 14, + "vehiclesDestroyedWith": 2, + "assists": 74, + "damageTo": 30066, + "destroyed": 11, + "timeIn": 4296 + }, + { + "type": "Air Combat", + "vehicleName": "Su-57", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_SU57_VSD0001-1b5aa5ee.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_SU57_VSD0001-1b5aa5ee.webp", + "id": "air_su57", + "kills": 0, + "killsPerMinute": 0.0, + "damage": 204, + "spawns": 3, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 13458, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 1091, + "destroyed": 0, + "timeIn": 150 + }, + { + "type": "Air Combat", + "vehicleName": "F-61V", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_F16_VSD0001-5f951ec9.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_F16_VSD0001-5f951ec9.webp", + "id": "air_f61v", + "kills": 26, + "killsPerMinute": 4.53, + "damage": 6870, + "spawns": 4, + "roadKills": 26, + "passengerAssists": 0, + "multiKills": 1, + "distanceTraveled": 33186, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 204, + "destroyed": 0, + "timeIn": 344 + }, + { + "type": "Air Combat", + "vehicleName": "F-39E", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_JAS39_VSD0001-9313d717.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_JAS39_VSD0001-9313d717.webp", + "id": "air_f39e", + "kills": 16, + "killsPerMinute": 5.36, + "damage": 3016, + "spawns": 0, + "roadKills": 6, + "passengerAssists": 0, + "multiKills": 4, + "distanceTraveled": 14990, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 6196, + "destroyed": 1, + "timeIn": 179 + }, + { + "type": "Air Combat", + "vehicleName": "M77E Falchion", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "id": "air_m77efalchion", + "kills": 4, + "killsPerMinute": 0.62, + "damage": 3246, + "spawns": 7, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 14466, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 6151, + "destroyed": 4, + "timeIn": 390 + }, + { + "type": "Ground Transport", + "vehicleName": "VECTOR", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Vector_VSD0002-241efa80.webp", + "id": "sur_vector", + "kills": 0, + "killsPerMinute": 0.0, + "damage": 3, + "spawns": 1, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 1496, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 1525, + "destroyed": 2, + "timeIn": 169 + } + ], +} +sttr_list = ['CHEETAH 1A2.png', 'F-39E.png', 'F-61V.png', 'F-97 KESTREL.png', 'GE-26.png', 'GLIDER 96.png', + 'LEO A4.png', 'M1A2 SEPV3.png', 'M3A3 BRADLEY.png', 'M77E FALCHION.png', 'PANTHERA KHT.png', + 'STRF 09 A4.png', 'SU-57.png', 'UH-79 NATO.png', 'UH-79 PAX.png', 'VECTOR.png'] + +play_stat = { + "userId": 1008269664784, + "avatar": "https://eaavatarservice.akamaized.net/production/avatar/prod/userAvatar/52082828/416x416.PNG", + "userName": "Sansorano_Yume", + "id": 1004152464784, + "hasResults": True, + "platform": "pc", + "platformId": 0, + "weapons": [ + { + "type": "Machine Guns", + "weaponName": "L110", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Minimi_PKG_Factory_MED-0e29fce7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Minimi_PKG_Factory_MED-0e29fce7.webp", + "id": "mg_l110", + "kills": 74, + "damage": 15353, + "assistsDamage": 35, + "bodyKills": 61, + "headshotKills": 13, + "hipfireKills": 1, + "multiKills": 12, + "accuracy": "9.52%", + "killsPerMinute": 1.07, + "damagePerMinute": 222.29, + "headshots": "17.57%", + "hitVKills": 8.59, + "shotsHit": 636, + "shotsFired": 6683, + "scopedKills": 73, + "spawns": 39, + "timeEquipped": 4144 + }, + { + "type": "SMG-PDWs", + "weaponName": "PW5A3", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MP5MLI_PKG_Factory_MED-2d1944b7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MP5MLI_PKG_Factory_MED-2d1944b7.webp", + "id": "smg_pw5a3", + "kills": 7, + "damage": 1562, + "assistsDamage": 1, + "bodyKills": 7, + "headshotKills": 0, + "hipfireKills": 1, + "multiKills": 0, + "accuracy": "18.99%", + "killsPerMinute": 0.46, + "damagePerMinute": 102.99, + "headshots": "0.0%", + "hitVKills": 18.71, + "shotsHit": 131, + "shotsFired": 690, + "scopedKills": 6, + "spawns": 0, + "timeEquipped": 910 + }, + { + "type": "Assault Rifles", + "weaponName": "M433", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_HK433_PKG_Factory_MED-b06f02f7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_HK433_PKG_Factory_MED-b06f02f7.webp", + "id": "ar_m433", + "kills": 607, + "damage": 71600, + "assistsDamage": 284, + "bodyKills": 526, + "headshotKills": 81, + "hipfireKills": 96, + "multiKills": 78, + "accuracy": "13.12%", + "killsPerMinute": 1.71, + "damagePerMinute": 201.52, + "headshots": "13.34%", + "hitVKills": 4.84, + "shotsHit": 2939, + "shotsFired": 22402, + "scopedKills": 511, + "spawns": 390, + "timeEquipped": 21318 + }, + { + "type": "Machine Guns", + "weaponName": "RPKM", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_RPKM_PKG_Factory_MED-755b785f.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_RPKM_PKG_Factory_MED-755b785f.webp", + "id": "mg_rpkm", + "kills": 88, + "damage": 16592, + "assistsDamage": 22, + "bodyKills": 80, + "headshotKills": 8, + "hipfireKills": 6, + "multiKills": 9, + "accuracy": "24.84%", + "killsPerMinute": 1.08, + "damagePerMinute": 202.79, + "headshots": "9.09%", + "hitVKills": 12.9, + "shotsHit": 1135, + "shotsFired": 4570, + "scopedKills": 82, + "spawns": 1, + "timeEquipped": 4909 + }, + { + "type": "Shotguns", + "weaponName": "M87A1", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_590A1_PKG_Factory_MED-4b387330.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_590A1_PKG_Factory_MED-4b387330.webp", + "id": "sg_m87a1", + "kills": 351, + "damage": 22678, + "assistsDamage": 72, + "bodyKills": 166, + "headshotKills": 185, + "hipfireKills": 122, + "multiKills": 31, + "accuracy": "91.29%", + "killsPerMinute": 2.72, + "damagePerMinute": 175.44, + "headshots": "52.71%", + "hitVKills": 1.88, + "shotsHit": 660, + "shotsFired": 723, + "scopedKills": 229, + "spawns": 149, + "timeEquipped": 7756 + }, + { + "type": "Pistols", + "weaponName": "P18", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M18_PKG_Factory_MED-88261bf8.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M18_PKG_Factory_MED-88261bf8.webp", + "id": "pst_p18", + "kills": 14, + "damage": 2080, + "assistsDamage": 12, + "bodyKills": 9, + "headshotKills": 5, + "hipfireKills": 6, + "multiKills": 4, + "accuracy": "23.77%", + "killsPerMinute": 0.79, + "damagePerMinute": 116.85, + "headshots": "35.71%", + "hitVKills": 6.93, + "shotsHit": 97, + "shotsFired": 408, + "scopedKills": 8, + "spawns": 1336, + "timeEquipped": 1068 + }, + { + "type": "Carbines", + "weaponName": "M277", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_XM7_PKG_Factory_MED-26271094.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_XM7_PKG_Factory_MED-26271094.webp", + "id": "crb_x277", + "kills": 420, + "damage": 52607, + "assistsDamage": 174, + "bodyKills": 309, + "headshotKills": 111, + "hipfireKills": 17, + "multiKills": 38, + "accuracy": "17.03%", + "killsPerMinute": 1.85, + "damagePerMinute": 231.61, + "headshots": "26.43%", + "hitVKills": 4.32, + "shotsHit": 1813, + "shotsFired": 10649, + "scopedKills": 403, + "spawns": 238, + "timeEquipped": 13628 + }, + { + "type": "Assault Rifles", + "weaponName": "B36A4", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_G36_PKG_Factory_MED-fb5466ec.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_G36_PKG_Factory_MED-fb5466ec.webp", + "id": "ar_b36a4", + "kills": 1045, + "damage": 48359, + "assistsDamage": 141, + "bodyKills": 547, + "headshotKills": 498, + "hipfireKills": 44, + "multiKills": 24, + "accuracy": "19.59%", + "killsPerMinute": 3.73, + "damagePerMinute": 172.69, + "headshots": "47.66%", + "hitVKills": 3.22, + "shotsHit": 3363, + "shotsFired": 17165, + "scopedKills": 1001, + "spawns": 172, + "timeEquipped": 16802 + }, + { + "type": "Assault Rifles", + "weaponName": "L85A3", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_L85A3_PKG_Factory_MED-9bd0deaa.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_L85A3_PKG_Factory_MED-9bd0deaa.webp", + "id": "ar_l85a3", + "kills": 785, + "damage": 16153, + "assistsDamage": 60, + "bodyKills": 315, + "headshotKills": 470, + "hipfireKills": 8, + "multiKills": 4, + "accuracy": "28.29%", + "killsPerMinute": 7.26, + "damagePerMinute": 149.47, + "headshots": "59.87%", + "hitVKills": 2.05, + "shotsHit": 1609, + "shotsFired": 5687, + "scopedKills": 777, + "spawns": 111, + "timeEquipped": 6484 + }, + { + "type": "Rifles", + "weaponName": "M2010 ESR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M2010ESR_PKG_Factory_MED-f94fdae6.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M2010ESR_PKG_Factory_MED-f94fdae6.webp", + "id": "snp_m2010", + "kills": 553, + "damage": 53403, + "assistsDamage": 32, + "bodyKills": 150, + "headshotKills": 403, + "hipfireKills": 200, + "multiKills": 51, + "accuracy": "47.56%", + "killsPerMinute": 2.49, + "damagePerMinute": 240.36, + "headshots": "72.88%", + "hitVKills": 1.37, + "shotsHit": 760, + "shotsFired": 1598, + "scopedKills": 353, + "spawns": 81, + "timeEquipped": 13331 + }, + { + "type": "Shotguns", + "weaponName": "M1014", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M1014_PKG_Factory_MED-e011854a.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M1014_PKG_Factory_MED-e011854a.webp", + "id": "sg_m1014", + "kills": 142, + "damage": 15520, + "assistsDamage": 19, + "bodyKills": 127, + "headshotKills": 15, + "hipfireKills": 138, + "multiKills": 11, + "accuracy": "76.98%", + "killsPerMinute": 4.06, + "damagePerMinute": 444.27, + "headshots": "10.56%", + "hitVKills": 2.8, + "shotsHit": 398, + "shotsFired": 517, + "scopedKills": 4, + "spawns": 31, + "timeEquipped": 2096 + }, + { + "type": "Carbines", + "weaponName": "AK-205", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_AK205_PKG_Factory_MED-6d376081.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_AK205_PKG_Factory_MED-6d376081.webp", + "id": "crb_ak205", + "kills": 30, + "damage": 5519, + "assistsDamage": 29, + "bodyKills": 25, + "headshotKills": 5, + "hipfireKills": 6, + "multiKills": 0, + "accuracy": "12.01%", + "killsPerMinute": 0.76, + "damagePerMinute": 139.49, + "headshots": "16.67%", + "hitVKills": 12.8, + "shotsHit": 384, + "shotsFired": 3197, + "scopedKills": 24, + "spawns": 26, + "timeEquipped": 2374 + }, + { + "type": "DMRs", + "weaponName": "SVK-8.6", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SVCh_PKG_Factory_MED-bb06d385.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SVCh_PKG_Factory_MED-bb06d385.webp", + "id": "dmr_svk86", + "kills": 262, + "damage": 42653, + "assistsDamage": 95, + "bodyKills": 144, + "headshotKills": 118, + "hipfireKills": 2, + "multiKills": 36, + "accuracy": "33.32%", + "killsPerMinute": 1.31, + "damagePerMinute": 212.95, + "headshots": "45.04%", + "hitVKills": 3.19, + "shotsHit": 837, + "shotsFired": 2512, + "scopedKills": 260, + "spawns": 76, + "timeEquipped": 12018 + }, + { + "type": "SMG-PDWs", + "weaponName": "SGX", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MPX_PKG_Factory_MED-e822f017.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MPX_PKG_Factory_MED-e822f017.webp", + "id": "smg_sgx", + "kills": 9788, + "damage": 526470, + "assistsDamage": 7, + "bodyKills": 7110, + "headshotKills": 2678, + "hipfireKills": 3088, + "multiKills": 85, + "accuracy": "54.83%", + "killsPerMinute": 56.3, + "damagePerMinute": 3028.3, + "headshots": "27.36%", + "hitVKills": 2.37, + "shotsHit": 23240, + "shotsFired": 42387, + "scopedKills": 6700, + "spawns": 65, + "timeEquipped": 10431 + }, + { + "type": "DMRs", + "weaponName": "LMR27", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_ARADMR_PKG_Factory_MED-dfe224de.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_ARADMR_PKG_Factory_MED-dfe224de.webp", + "id": "dmr_lmr27", + "kills": 5, + "damage": 765, + "assistsDamage": 2, + "bodyKills": 5, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "30.0%", + "killsPerMinute": 1.18, + "damagePerMinute": 180.0, + "headshots": "0.0%", + "hitVKills": 7.2, + "shotsHit": 36, + "shotsFired": 120, + "scopedKills": 5, + "spawns": 3, + "timeEquipped": 255 + }, + { + "type": "Carbines", + "weaponName": "QBZ-192", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_QBZ192_PKG_Factory_MED-dc0a546b.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_QBZ192_PKG_Factory_MED-dc0a546b.webp", + "id": "crb_qbz192", + "kills": 75, + "damage": 10219, + "assistsDamage": 52, + "bodyKills": 72, + "headshotKills": 3, + "hipfireKills": 4, + "multiKills": 7, + "accuracy": "12.36%", + "killsPerMinute": 1.08, + "damagePerMinute": 147.64, + "headshots": "4.0%", + "hitVKills": 3.83, + "shotsHit": 287, + "shotsFired": 2322, + "scopedKills": 71, + "spawns": 104, + "timeEquipped": 4153 + }, + { + "type": "Carbines", + "weaponName": "M417 A2", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_HK417A2_PKG_Factory_MED-494ffe6e.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_HK417A2_PKG_Factory_MED-494ffe6e.webp", + "id": "crb_m417a2", + "kills": 1942, + "damage": 52408, + "assistsDamage": 156, + "bodyKills": 638, + "headshotKills": 1304, + "hipfireKills": 103, + "multiKills": 54, + "accuracy": "24.49%", + "killsPerMinute": 6.87, + "damagePerMinute": 185.47, + "headshots": "67.15%", + "hitVKills": 1.78, + "shotsHit": 3464, + "shotsFired": 14143, + "scopedKills": 1839, + "spawns": 266, + "timeEquipped": 16954 + }, + { + "type": "Machine Guns", + "weaponName": "DRS-IAR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M27IAR_PKG_Factory_MED-ae6675cd.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M27IAR_PKG_Factory_MED-ae6675cd.webp", + "id": "mg_drsiar", + "kills": 729, + "damage": 83389, + "assistsDamage": 45, + "bodyKills": 599, + "headshotKills": 130, + "hipfireKills": 115, + "multiKills": 61, + "accuracy": "28.88%", + "killsPerMinute": 5.56, + "damagePerMinute": 636.4, + "headshots": "17.83%", + "hitVKills": 4.49, + "shotsHit": 3270, + "shotsFired": 11323, + "scopedKills": 614, + "spawns": 77, + "timeEquipped": 7862 + }, + { + "type": "Assault Rifles", + "weaponName": "KORD 6P67", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_6P67_PKG_Factory_MED-827b9414.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_6P67_PKG_Factory_MED-827b9414.webp", + "id": "ar_kord6p67", + "kills": 502, + "damage": 64820, + "assistsDamage": 98, + "bodyKills": 429, + "headshotKills": 73, + "hipfireKills": 42, + "multiKills": 107, + "accuracy": "25.85%", + "killsPerMinute": 2.55, + "damagePerMinute": 328.9, + "headshots": "14.54%", + "hitVKills": 7.41, + "shotsHit": 3722, + "shotsFired": 14397, + "scopedKills": 460, + "spawns": 178, + "timeEquipped": 11825 + }, + { + "type": "SMG-PDWs", + "weaponName": "USG-90", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_P90_PKG_Factory_MED-2ab1db64.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_P90_PKG_Factory_MED-2ab1db64.webp", + "id": "smg_usg90", + "kills": 10, + "damage": 1217, + "assistsDamage": 4, + "bodyKills": 6, + "headshotKills": 4, + "hipfireKills": 3, + "multiKills": 1, + "accuracy": "16.58%", + "killsPerMinute": 0.75, + "damagePerMinute": 91.39, + "headshots": "40.0%", + "hitVKills": 6.6, + "shotsHit": 66, + "shotsFired": 398, + "scopedKills": 7, + "spawns": 0, + "timeEquipped": 799 + }, + { + "type": "Carbines", + "weaponName": "M4A1", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M4A1_PKG_Factory_MED-34529a82.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M4A1_PKG_Factory_MED-34529a82.webp", + "id": "crb_m4a1", + "kills": 2309, + "damage": 36071, + "assistsDamage": 141, + "bodyKills": 730, + "headshotKills": 1579, + "hipfireKills": 92, + "multiKills": 42, + "accuracy": "26.14%", + "killsPerMinute": 13.41, + "damagePerMinute": 209.53, + "headshots": "68.38%", + "hitVKills": 1.6, + "shotsHit": 3691, + "shotsFired": 14118, + "scopedKills": 2217, + "spawns": 199, + "timeEquipped": 10329 + }, + { + "type": "Machine Guns", + "weaponName": "KTS100 MK8", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Ultimax_PKG_Factory_MED-a8ebb482.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Ultimax_PKG_Factory_MED-a8ebb482.webp", + "id": "mg_kts100mk8", + "kills": 4524, + "damage": 25524, + "assistsDamage": 76, + "bodyKills": 1865, + "headshotKills": 2659, + "hipfireKills": 54, + "multiKills": 23, + "accuracy": "41.99%", + "killsPerMinute": 19.76, + "damagePerMinute": 111.48, + "headshots": "58.78%", + "hitVKills": 1.38, + "shotsHit": 6236, + "shotsFired": 14851, + "scopedKills": 4470, + "spawns": 88, + "timeEquipped": 13737 + }, + { + "type": "Pistols", + "weaponName": "M45A1", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M45A1_PKG_Factory_MED-8c41691b.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M45A1_PKG_Factory_MED-8c41691b.webp", + "id": "pst_m45a1", + "kills": 228, + "damage": 252, + "assistsDamage": 0, + "bodyKills": 30, + "headshotKills": 198, + "hipfireKills": 37, + "multiKills": 2, + "accuracy": "211.11%", + "killsPerMinute": 93.7, + "damagePerMinute": 103.56, + "headshots": "86.84%", + "hitVKills": 1.0, + "shotsHit": 228, + "shotsFired": 108, + "scopedKills": 191, + "spawns": 69, + "timeEquipped": 146 + }, + { + "type": "SMG-PDWs", + "weaponName": "KV9", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Vector_PKG_Factory_MED-b5631ed7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Vector_PKG_Factory_MED-b5631ed7.webp", + "id": "smg_kv9", + "kills": 169, + "damage": 21081, + "assistsDamage": 83, + "bodyKills": 148, + "headshotKills": 21, + "hipfireKills": 58, + "multiKills": 18, + "accuracy": "16.2%", + "killsPerMinute": 1.42, + "damagePerMinute": 177.47, + "headshots": "12.43%", + "hitVKills": 5.8, + "shotsHit": 981, + "shotsFired": 6057, + "scopedKills": 111, + "spawns": 142, + "timeEquipped": 7127 + }, + { + "type": "Assault Rifles", + "weaponName": "SOR-556 Mk2", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SCARL_PKG_Factory_MED-b44467bb.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SCARL_PKG_Factory_MED-b44467bb.webp", + "id": "ar_sor556mk2", + "kills": 451, + "damage": 54559, + "assistsDamage": 175, + "bodyKills": 367, + "headshotKills": 84, + "hipfireKills": 23, + "multiKills": 47, + "accuracy": "20.04%", + "killsPerMinute": 2.27, + "damagePerMinute": 274.14, + "headshots": "18.63%", + "hitVKills": 4.89, + "shotsHit": 2205, + "shotsFired": 11002, + "scopedKills": 428, + "spawns": 139, + "timeEquipped": 11941 + }, + { + "type": "SMG-PDWs", + "weaponName": "PW7A2", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MP7A2_PKG_Factory_MED-406bc965.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MP7A2_PKG_Factory_MED-406bc965.webp", + "id": "smg_pw7a2", + "kills": 216, + "damage": 20576, + "assistsDamage": 15, + "bodyKills": 201, + "headshotKills": 15, + "hipfireKills": 75, + "multiKills": 54, + "accuracy": "26.43%", + "killsPerMinute": 5.13, + "damagePerMinute": 488.55, + "headshots": "6.94%", + "hitVKills": 6.2, + "shotsHit": 1339, + "shotsFired": 5066, + "scopedKills": 141, + "spawns": 4, + "timeEquipped": 2527 + }, + { + "type": "Machine Guns", + "weaponName": "M123K", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MG4K_PKG_Factory_MED-cc064690.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MG4K_PKG_Factory_MED-cc064690.webp", + "id": "mg_m123k", + "kills": 84, + "damage": 15303, + "assistsDamage": 40, + "bodyKills": 75, + "headshotKills": 9, + "hipfireKills": 22, + "multiKills": 8, + "accuracy": "12.66%", + "killsPerMinute": 1.03, + "damagePerMinute": 187.92, + "headshots": "10.71%", + "hitVKills": 11.15, + "shotsHit": 937, + "shotsFired": 7403, + "scopedKills": 62, + "spawns": 63, + "timeEquipped": 4886 + }, + { + "type": "Pistols", + "weaponName": "M44", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_RagingHunter_PKG_Factory_MED-f9773307.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_RagingHunter_PKG_Factory_MED-f9773307.webp", + "id": "pst_m44", + "kills": 18, + "damage": 4263, + "assistsDamage": 14, + "bodyKills": 12, + "headshotKills": 6, + "hipfireKills": 4, + "multiKills": 0, + "accuracy": "34.78%", + "killsPerMinute": 0.27, + "damagePerMinute": 63.98, + "headshots": "33.33%", + "hitVKills": 5.78, + "shotsHit": 104, + "shotsFired": 299, + "scopedKills": 14, + "spawns": 854, + "timeEquipped": 3998 + }, + { + "type": "Machine Guns", + "weaponName": "M250", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M250_PKG_Factory_MED-6e230a71.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M250_PKG_Factory_MED-6e230a71.webp", + "id": "mg_xm250", + "kills": 328, + "damage": 38530, + "assistsDamage": 90, + "bodyKills": 289, + "headshotKills": 39, + "hipfireKills": 27, + "multiKills": 58, + "accuracy": "18.11%", + "killsPerMinute": 2.33, + "damagePerMinute": 273.68, + "headshots": "11.89%", + "hitVKills": 4.3, + "shotsHit": 1412, + "shotsFired": 7796, + "scopedKills": 301, + "spawns": 166, + "timeEquipped": 8447 + }, + { + "type": "SMG-PDWs", + "weaponName": "UMG-40", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_UMP40_PKG_Factory_MED-22afa646.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_UMP40_PKG_Factory_MED-22afa646.webp", + "id": "smg_umg40", + "kills": 4, + "damage": 926, + "assistsDamage": 1, + "bodyKills": 4, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 1, + "accuracy": "24.37%", + "killsPerMinute": 0.43, + "damagePerMinute": 98.51, + "headshots": "0.0%", + "hitVKills": 21.75, + "shotsHit": 87, + "shotsFired": 357, + "scopedKills": 4, + "spawns": 3, + "timeEquipped": 564 + }, + { + "type": "Assault Rifles", + "weaponName": "TR-7", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Tavor7_PKG_Factory_MED-e682f267.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Tavor7_PKG_Factory_MED-e682f267.webp", + "id": "ar_tr7", + "kills": 616, + "damage": 68498, + "assistsDamage": 107, + "bodyKills": 474, + "headshotKills": 142, + "hipfireKills": 143, + "multiKills": 55, + "accuracy": "16.89%", + "killsPerMinute": 2.46, + "damagePerMinute": 273.5, + "headshots": "23.05%", + "hitVKills": 3.68, + "shotsHit": 2268, + "shotsFired": 13428, + "scopedKills": 473, + "spawns": 252, + "timeEquipped": 15027 + }, + { + "type": "SMG-PDWs", + "weaponName": "SL9", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_APDW_PKG_Factory_MED-c4d1b829.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_APDW_PKG_Factory_MED-c4d1b829.webp", + "id": "smg_sl9", + "kills": 376, + "damage": 37358, + "assistsDamage": 17, + "bodyKills": 316, + "headshotKills": 60, + "hipfireKills": 19, + "multiKills": 77, + "accuracy": "21.84%", + "killsPerMinute": 4.86, + "damagePerMinute": 483.08, + "headshots": "15.96%", + "hitVKills": 4.85, + "shotsHit": 1824, + "shotsFired": 8350, + "scopedKills": 357, + "spawns": 25, + "timeEquipped": 4640 + }, + { + "type": "Machine Guns", + "weaponName": "M240L", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M240L_PKG_Factory_MED-1fa18e0c.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M240L_PKG_Factory_MED-1fa18e0c.webp", + "id": "mg_m240l", + "kills": 45, + "damage": 4029, + "assistsDamage": 0, + "bodyKills": 40, + "headshotKills": 5, + "hipfireKills": 3, + "multiKills": 3, + "accuracy": "31.3%", + "killsPerMinute": 7.03, + "damagePerMinute": 629.53, + "headshots": "11.11%", + "hitVKills": 3.31, + "shotsHit": 149, + "shotsFired": 476, + "scopedKills": 42, + "spawns": 1, + "timeEquipped": 384 + }, + { + "type": "SMG-PDWs", + "weaponName": "SCW-10", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_APC10_PKG_Factory_MED-716a97fb.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_APC10_PKG_Factory_MED-716a97fb.webp", + "id": "smg_scw10", + "kills": 571, + "damage": 61171, + "assistsDamage": 139, + "bodyKills": 495, + "headshotKills": 76, + "hipfireKills": 48, + "multiKills": 105, + "accuracy": "18.37%", + "killsPerMinute": 2.47, + "damagePerMinute": 264.68, + "headshots": "13.31%", + "hitVKills": 4.04, + "shotsHit": 2308, + "shotsFired": 12565, + "scopedKills": 523, + "spawns": 232, + "timeEquipped": 13867 + }, + { + "type": "Assault Rifles", + "weaponName": "NVO-228E", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_ACE32_PKG_Factory_MED-39a97220.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_ACE32_PKG_Factory_MED-39a97220.webp", + "id": "ar_nvo228e", + "kills": 960, + "damage": 61885, + "assistsDamage": 101, + "bodyKills": 611, + "headshotKills": 349, + "hipfireKills": 72, + "multiKills": 39, + "accuracy": "28.84%", + "killsPerMinute": 5.78, + "damagePerMinute": 372.69, + "headshots": "36.35%", + "hitVKills": 2.44, + "shotsHit": 2344, + "shotsFired": 8128, + "scopedKills": 888, + "spawns": 114, + "timeEquipped": 9963 + }, + { + "type": "Machine Guns", + "weaponName": "M/60", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M60E6_PKG_Factory_MED-e600bb28.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M60E6_PKG_Factory_MED-e600bb28.webp", + "id": "mg_m60", + "kills": 5, + "damage": 1191, + "assistsDamage": 5, + "bodyKills": 5, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 1, + "accuracy": "6.74%", + "killsPerMinute": 0.47, + "damagePerMinute": 112.01, + "headshots": "0.0%", + "hitVKills": 11.8, + "shotsHit": 59, + "shotsFired": 876, + "scopedKills": 5, + "spawns": 1, + "timeEquipped": 638 + }, + { + "type": "Rifles", + "weaponName": "PSR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MRAD_PKG_Factory_MED-5035ce99.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MRAD_PKG_Factory_MED-5035ce99.webp", + "id": "snp_psr", + "kills": 39, + "damage": 7457, + "assistsDamage": 11, + "bodyKills": 17, + "headshotKills": 22, + "hipfireKills": 22, + "multiKills": 0, + "accuracy": "30.75%", + "killsPerMinute": 0.49, + "damagePerMinute": 94.61, + "headshots": "56.41%", + "hitVKills": 3.56, + "shotsHit": 139, + "shotsFired": 452, + "scopedKills": 17, + "spawns": 9, + "timeEquipped": 4729 + }, + { + "type": "DMRs", + "weaponName": "SVDM", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SVDM_PKG_Factory_MED-b6c9aa50.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SVDM_PKG_Factory_MED-b6c9aa50.webp", + "id": "dmr_svdm", + "kills": 3, + "damage": 475, + "assistsDamage": 3, + "bodyKills": 1, + "headshotKills": 2, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "20.0%", + "killsPerMinute": 0.28, + "damagePerMinute": 44.88, + "headshots": "66.67%", + "hitVKills": 6.33, + "shotsHit": 19, + "shotsFired": 95, + "scopedKills": 3, + "spawns": 1, + "timeEquipped": 635 + }, + { + "type": "Assault Rifles", + "weaponName": "AK4D", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_G3A4_PKG_Factory_MED-0575cf00.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_G3A4_PKG_Factory_MED-0575cf00.webp", + "id": "ar_ak4d", + "kills": 155, + "damage": 17827, + "assistsDamage": 48, + "bodyKills": 147, + "headshotKills": 8, + "hipfireKills": 6, + "multiKills": 23, + "accuracy": "20.76%", + "killsPerMinute": 1.53, + "damagePerMinute": 176.24, + "headshots": "5.16%", + "hitVKills": 4.49, + "shotsHit": 696, + "shotsFired": 3353, + "scopedKills": 149, + "spawns": 80, + "timeEquipped": 6069 + }, + { + "type": "Carbines", + "weaponName": "SOR-300SC", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SCARSC_PKG_Factory_MED-7a6a50ff.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SCARSC_PKG_Factory_MED-7a6a50ff.webp", + "id": "crb_sor300sc", + "kills": 5, + "damage": 1016, + "assistsDamage": 4, + "bodyKills": 4, + "headshotKills": 1, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "12.99%", + "killsPerMinute": 0.24, + "damagePerMinute": 47.77, + "headshots": "20.0%", + "hitVKills": 20.0, + "shotsHit": 100, + "shotsFired": 770, + "scopedKills": 5, + "spawns": 0, + "timeEquipped": 1276 + }, + { + "type": "Carbines", + "weaponName": "SG 553R", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SIG553R_PKG_Factory_MED-afc2dfa8.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SIG553R_PKG_Factory_MED-afc2dfa8.webp", + "id": "crb_sg553r", + "kills": 4207, + "damage": 30073, + "assistsDamage": 119, + "bodyKills": 3204, + "headshotKills": 1003, + "hipfireKills": 1264, + "multiKills": 37, + "accuracy": "45.09%", + "killsPerMinute": 21.64, + "damagePerMinute": 154.71, + "headshots": "23.84%", + "hitVKills": 1.16, + "shotsHit": 4895, + "shotsFired": 10855, + "scopedKills": 2943, + "spawns": 200, + "timeEquipped": 11663 + }, + { + "type": "Carbines", + "weaponName": "GRT-BC", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MSBSGROTB_PKG_Factory_MED-25acf006.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MSBSGROTB_PKG_Factory_MED-25acf006.webp", + "id": "crb_grtbc", + "kills": 22, + "damage": 3216, + "assistsDamage": 20, + "bodyKills": 17, + "headshotKills": 5, + "hipfireKills": 7, + "multiKills": 1, + "accuracy": "12.16%", + "killsPerMinute": 0.76, + "damagePerMinute": 111.15, + "headshots": "22.73%", + "hitVKills": 7.95, + "shotsHit": 175, + "shotsFired": 1439, + "scopedKills": 15, + "spawns": 21, + "timeEquipped": 1736 + }, + { + "type": "Shotguns", + "weaponName": "18.5KS-K", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_185KSK_PKG_Factory_MED-432c353f.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MSBSGROTB_PKG_Factory_MED-25acf006.webp", + "id": "sg_185ksk", + "kills": 17, + "damage": 2390, + "assistsDamage": 9, + "bodyKills": 15, + "headshotKills": 2, + "hipfireKills": 17, + "multiKills": 1, + "accuracy": "22.83%", + "killsPerMinute": 0.87, + "damagePerMinute": 122.46, + "headshots": "11.76%", + "hitVKills": 2.94, + "shotsHit": 50, + "shotsFired": 219, + "scopedKills": 0, + "spawns": 30, + "timeEquipped": 1171 + }, + { + "type": "Pistols", + "weaponName": "ES 5.7", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M18_PKG_Factory_MED-88261bf8.webp", + "id": "pst_es57", + "kills": 9183, + "damage": 565421, + "assistsDamage": 7, + "bodyKills": 3568, + "headshotKills": 5615, + "hipfireKills": 2930, + "multiKills": 60, + "accuracy": "105.3%", + "killsPerMinute": 51.52, + "damagePerMinute": 3172.07, + "headshots": "61.15%", + "hitVKills": 2.51, + "shotsHit": 23019, + "shotsFired": 21860, + "scopedKills": 6253, + "spawns": 715, + "timeEquipped": 10695 + }, + { + "type": "DMRs", + "weaponName": "M39 EMR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SVCh_PKG_Factory_MED-bb06d385.webp", + "id": "dmr_m39emr", + "kills": 0, + "damage": 0, + "assistsDamage": 0, + "bodyKills": 0, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "0.0%", + "killsPerMinute": 0.0, + "damagePerMinute": 0.0, + "headshots": "0.0%", + "hitVKills": 0.0, + "shotsHit": 0, + "shotsFired": 0, + "scopedKills": 0, + "spawns": 0, + "timeEquipped": 45 + }, + { + "type": "Rifles", + "weaponName": "SV-98", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M2010ESR_PKG_Factory_MED-f94fdae6.webp", + "id": "snp_sv98", + "kills": 2, + "damage": 334, + "assistsDamage": 1, + "bodyKills": 1, + "headshotKills": 1, + "hipfireKills": 1, + "multiKills": 0, + "accuracy": "25.93%", + "killsPerMinute": 0.3, + "damagePerMinute": 50.1, + "headshots": "50.0%", + "hitVKills": 3.5, + "shotsHit": 7, + "shotsFired": 27, + "scopedKills": 1, + "spawns": 1, + "timeEquipped": 400 + } + ], + "vehicles": [ + { + "type": "Air Combat", + "vehicleName": "Panthera KHT", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Eurocopter_VSD0001-8003028d.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Eurocopter_VSD0001-8003028d.webp", + "id": "air_panthera", + "kills": 166, + "killsPerMinute": 7.07, + "damage": 27206, + "spawns": 6, + "roadKills": 7, + "passengerAssists": 13, + "multiKills": 5, + "distanceTraveled": 50779, + "driverAssists": 1, + "vehiclesDestroyedWith": 7, + "assists": 14, + "damageTo": 3918, + "destroyed": 0, + "timeIn": 1408 + }, + { + "type": "Air Combat", + "vehicleName": "M77E Falchion", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "id": "air_m77efalchio", + "kills": 0, + "killsPerMinute": 0, + "damage": 0, + "spawns": 0, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 0, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 0, + "destroyed": 0, + "timeIn": 0 + }, + { + "type": "Ground Combat", + "vehicleName": "Leo A4", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Leopard_VSD0001-f8da51ee.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Leopard_VSD0001-f8da51ee.webp", + "id": "sur_leoa4", + "kills": 22, + "killsPerMinute": 0.74, + "damage": 19307, + "spawns": 8, + "roadKills": 1, + "passengerAssists": 1, + "multiKills": 2, + "distanceTraveled": 6115, + "driverAssists": 13, + "vehiclesDestroyedWith": 1, + "assists": 14, + "damageTo": 43760, + "destroyed": 6, + "timeIn": 1789 + }, + { + "type": "Ground Combat", + "vehicleName": "Strf 09 A4", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_CV90_VSD0001-acd942b6.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_CV90_VSD0001-acd942b6.webp", + "id": "sur_strf09a4", + "kills": 140, + "killsPerMinute": 1.76, + "damage": 25699, + "spawns": 196, + "roadKills": 0, + "passengerAssists": 52, + "multiKills": 27, + "distanceTraveled": 12701, + "driverAssists": 41, + "vehiclesDestroyedWith": 2, + "assists": 93, + "damageTo": 20875, + "destroyed": 1, + "timeIn": 4770 + }, + { + "type": "Ground Combat", + "vehicleName": "M1A2 SEPv3", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Abrams_VSD0001-5412a78d.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Abrams_VSD0001-5412a78d.webp", + "id": "sur_m1a2sepv3", + "kills": 236, + "killsPerMinute": 1.54, + "damage": 67333, + "spawns": 46, + "roadKills": 0, + "passengerAssists": 164, + "multiKills": 32, + "distanceTraveled": 19222, + "driverAssists": 102, + "vehiclesDestroyedWith": 6, + "assists": 266, + "damageTo": 50600, + "destroyed": 9, + "timeIn": 9195 + }, + { + "type": "Ground Combat", + "vehicleName": "Cheetah 1A2", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Gepard_VSD0001-d796732f.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Gepard_VSD0001-d796732f.webp", + "id": "sur_cheetah1a2", + "kills": 0, + "killsPerMinute": 0.0, + "damage": 1521, + "spawns": 1, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 737, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 9876, + "destroyed": 0, + "timeIn": 139 + }, + { + "type": "Ground Combat", + "vehicleName": "Glider 96", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Flyer60_VSD0005-1569869f.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Flyer60_VSD0005-1569869f.webp", + "id": "sur_glider96", + "kills": 6, + "killsPerMinute": 0.28, + "damage": 1648, + "spawns": 7, + "roadKills": 1, + "passengerAssists": 0, + "multiKills": 1, + "distanceTraveled": 9884, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 14447, + "destroyed": 0, + "timeIn": 1298 + }, + { + "type": "Ground Combat", + "vehicleName": "M3A3 Bradley", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_OB_VEH_Tank_Bradley_VSD0001_Dressing-66f252ca.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_OB_VEH_Tank_Bradley_VSD0001_Dressing-66f252ca.webp", + "id": "sur_bradley", + "kills": 82, + "killsPerMinute": 1.15, + "damage": 16995, + "spawns": 59, + "roadKills": 0, + "passengerAssists": 60, + "multiKills": 12, + "distanceTraveled": 14396, + "driverAssists": 14, + "vehiclesDestroyedWith": 2, + "assists": 74, + "damageTo": 30066, + "destroyed": 11, + "timeIn": 4296 + }, + { + "type": "Air Combat", + "vehicleName": "Su-57", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_SU57_VSD0001-1b5aa5ee.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_SU57_VSD0001-1b5aa5ee.webp", + "id": "air_su57", + "kills": 0, + "killsPerMinute": 0.0, + "damage": 204, + "spawns": 3, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 13458, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 1091, + "destroyed": 0, + "timeIn": 150 + }, + { + "type": "Air Combat", + "vehicleName": "F-61V", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_F16_VSD0001-5f951ec9.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_F16_VSD0001-5f951ec9.webp", + "id": "air_f61v", + "kills": 26, + "killsPerMinute": 4.53, + "damage": 6870, + "spawns": 4, + "roadKills": 26, + "passengerAssists": 0, + "multiKills": 1, + "distanceTraveled": 33186, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 204, + "destroyed": 0, + "timeIn": 344 + }, + { + "type": "Air Combat", + "vehicleName": "F-39E", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_JAS39_VSD0001-9313d717.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_JAS39_VSD0001-9313d717.webp", + "id": "air_f39e", + "kills": 16, + "killsPerMinute": 5.36, + "damage": 3016, + "spawns": 0, + "roadKills": 6, + "passengerAssists": 0, + "multiKills": 4, + "distanceTraveled": 14990, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 6196, + "destroyed": 1, + "timeIn": 179 + }, + { + "type": "Air Combat", + "vehicleName": "M77E Falchion", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "id": "air_m77efalchion", + "kills": 4, + "killsPerMinute": 0.62, + "damage": 3246, + "spawns": 7, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 14466, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 6151, + "destroyed": 4, + "timeIn": 390 + }, + { + "type": "Ground Transport", + "vehicleName": "VECTOR", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Vector_VSD0002-241efa80.webp", + "id": "sur_vector", + "kills": 0, + "killsPerMinute": 0.0, + "damage": 3, + "spawns": 1, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 1496, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 1525, + "destroyed": 2, + "timeIn": 169 + } + ], + "weaponGroups": [ + { + "groupName": "Rifles", + "id": "snp", + "kills": 1317, + "damage": 134277, + "assistsDamage": 86, + "bodyKills": 524, + "headshotKills": 793, + "hipfireKills": 255, + "multiKills": 70, + "accuracy": "52.64%", + "killsPerMinute": 2.88, + "damagePerMinute": 293.22, + "headshots": "60.21%", + "hitVKills": 1.42, + "shotsHit": 1866, + "shotsFired": 3545, + "scopedKills": 1062, + "spawns": 190, + "timeEquipped": 27476 + }, + { + "groupName": "Carbines", + "id": "crb", + "kills": 9010, + "damage": 191129, + "assistsDamage": 695, + "bodyKills": 4999, + "headshotKills": 4011, + "hipfireKills": 1493, + "multiKills": 179, + "accuracy": "25.76%", + "killsPerMinute": 8.7, + "damagePerMinute": 184.63, + "headshots": "44.52%", + "hitVKills": 1.64, + "shotsHit": 14809, + "shotsFired": 57493, + "scopedKills": 7517, + "spawns": 1054, + "timeEquipped": 62113 + }, + { + "groupName": "Machine Guns", + "id": "mg", + "kills": 5878, + "damage": 200011, + "assistsDamage": 313, + "bodyKills": 3015, + "headshotKills": 2863, + "hipfireKills": 228, + "multiKills": 175, + "accuracy": "25.61%", + "killsPerMinute": 7.82, + "damagePerMinute": 266.14, + "headshots": "48.71%", + "hitVKills": 2.35, + "shotsHit": 13838, + "shotsFired": 54035, + "scopedKills": 5650, + "spawns": 436, + "timeEquipped": 45092 + }, + { + "groupName": "Shotguns", + "id": "sg", + "kills": 510, + "damage": 40588, + "assistsDamage": 100, + "bodyKills": 308, + "headshotKills": 202, + "hipfireKills": 277, + "multiKills": 43, + "accuracy": "75.94%", + "killsPerMinute": 2.77, + "damagePerMinute": 220.33, + "headshots": "39.61%", + "hitVKills": 2.17, + "shotsHit": 1108, + "shotsFired": 1459, + "scopedKills": 233, + "spawns": 210, + "timeEquipped": 11053 + }, + { + "groupName": "Assault Rifles", + "id": "ar", + "kills": 5121, + "damage": 403701, + "assistsDamage": 1014, + "bodyKills": 3416, + "headshotKills": 1705, + "hipfireKills": 434, + "multiKills": 377, + "accuracy": "20.04%", + "killsPerMinute": 3.09, + "damagePerMinute": 243.61, + "headshots": "33.29%", + "hitVKills": 3.74, + "shotsHit": 19146, + "shotsFired": 95562, + "scopedKills": 4687, + "spawns": 1436, + "timeEquipped": 99429 + }, + { + "groupName": "SMG-PDWs", + "id": "smg", + "kills": 11141, + "damage": 670361, + "assistsDamage": 267, + "bodyKills": 8287, + "headshotKills": 2854, + "hipfireKills": 3292, + "multiKills": 341, + "accuracy": "39.51%", + "killsPerMinute": 16.36, + "damagePerMinute": 984.26, + "headshots": "25.62%", + "hitVKills": 2.69, + "shotsHit": 29976, + "shotsFired": 75870, + "scopedKills": 7849, + "spawns": 471, + "timeEquipped": 40865 + }, + { + "groupName": "DMRs", + "id": "dmr", + "kills": 270, + "damage": 43893, + "assistsDamage": 100, + "bodyKills": 150, + "headshotKills": 120, + "hipfireKills": 2, + "multiKills": 36, + "accuracy": "32.71%", + "killsPerMinute": 1.25, + "damagePerMinute": 203.32, + "headshots": "44.44%", + "hitVKills": 3.3, + "shotsHit": 892, + "shotsFired": 2727, + "scopedKills": 268, + "spawns": 80, + "timeEquipped": 12953 + } + ], + "vehicleGroups": [ + { + "groupName": "Air Combat", + "id": "air", + "kills": 228, + "killsPerMinute": 3.74, + "damage": 52741, + "spawns": 32, + "roadKills": 43, + "passengerAssists": 13, + "multiKills": 12, + "distanceTraveled": 187925, + "driverAssists": 7, + "vehiclesDestroyedWith": 9, + "assists": 20, + "damageTo": 37134, + "destroyed": 14, + "timeIn": 3653 + }, + { + "groupName": "Ground Combat", + "id": "sur", + "kills": 486, + "killsPerMinute": 1.33, + "damage": 132612, + "spawns": 326, + "roadKills": 2, + "passengerAssists": 277, + "multiKills": 74, + "distanceTraveled": 66653, + "driverAssists": 170, + "vehiclesDestroyedWith": 11, + "assists": 447, + "damageTo": 175787, + "destroyed": 31, + "timeIn": 21931 + } + ], + "classes": [ + { + "className": "Assault", + "image": "https://cdn.gametools.network/classes/bf6/white/Assault.svg", + "altImage": "https://cdn.gametools.network/classes/bf6/black/Assault.svg", + "id": "assault", + "kills": 3691, + "deaths": 1168, + "kpm": 1.65, + "killDeath": 3.16, + "spawns": 1276, + "score": 938610, + "assists": 1501, + "secondsPlayed": 134495 + }, + { + "className": "Engineer", + "image": "https://cdn.gametools.network/classes/bf6/white/Engineer.svg", + "altImage": "https://cdn.gametools.network/classes/bf6/black/Engineer.svg", + "id": "engineer", + "kills": 6123, + "deaths": 266, + "kpm": 11.4, + "killDeath": 23.02, + "spawns": 301, + "score": 192225, + "assists": 523, + "secondsPlayed": 32218 + }, + { + "className": "Support", + "image": "https://cdn.gametools.network/classes/bf6/white/Support.svg", + "altImage": "https://cdn.gametools.network/classes/bf6/black/Support.svg", + "id": "support", + "kills": 27896, + "deaths": 1998, + "kpm": 7.82, + "killDeath": 13.96, + "spawns": 2208, + "score": 1790650, + "assists": 2667, + "secondsPlayed": 214172 + }, + { + "className": "Recon", + "image": "https://cdn.gametools.network/classes/bf6/white/Recon.svg", + "altImage": "https://cdn.gametools.network/classes/bf6/black/Recon.svg", + "id": "recon", + "kills": 8163, + "deaths": 304, + "kpm": 9.02, + "killDeath": 26.85, + "spawns": 348, + "score": 345815, + "assists": 954, + "secondsPlayed": 54308 + } + ], + "maps": [ + { + "mapName": "Siege of Cairo", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Abbasid_Large_OPT-49a3761a.webp", + "id": "mpabbasid", + "wins": 48, + "losses": 29, + "matches": 77, + "winPercent": "62.34%", + "secondsPlayed": 108122 + }, + { + "mapName": "Empire State", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Aftermath_Large_OPT-bf883df1.webp", + "id": "mpaftermath", + "wins": 39, + "losses": 16, + "matches": 55, + "winPercent": "70.91%", + "secondsPlayed": 63995 + }, + { + "mapName": "Iberian Offensive", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Battery_Large_OPT-034d4636.webp", + "id": "mpbattery", + "wins": 15, + "losses": 8, + "matches": 23, + "winPercent": "65.22%", + "secondsPlayed": 19596 + }, + { + "mapName": "Liberation Peak", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Capstone_Large_OPT-2ccae694.webp", + "id": "mpcapstone", + "wins": 27, + "losses": 14, + "matches": 41, + "winPercent": "65.85%", + "secondsPlayed": 56559 + }, + { + "mapName": "Manhattan Bridge", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Dumbo_Large_OPT-20de031f.webp", + "id": "mpdumbo", + "wins": 20, + "losses": 9, + "matches": 29, + "winPercent": "68.97%", + "secondsPlayed": 33388 + }, + { + "mapName": "Operation Firestorm", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Firestorm_Large_OPT-45d582ad.webp", + "id": "mpfirestorm", + "wins": 5, + "losses": 3, + "matches": 8, + "winPercent": "62.5%", + "secondsPlayed": 10892 + }, + { + "mapName": "Saints Quarter", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Limestone_Large_OPT-c9160897.webp", + "id": "mplimestone", + "wins": 34, + "losses": 10, + "matches": 44, + "winPercent": "77.27%", + "secondsPlayed": 23532 + }, + { + "mapName": "New Sobek City", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Outskirts_Large_OPT-bf08f756.webp", + "id": "mpoutskirts", + "wins": 16, + "losses": 7, + "matches": 23, + "winPercent": "69.57%", + "secondsPlayed": 37590 + }, + { + "mapName": "Mirak Valley", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Tungsten_Large_OPT-935da06b.webp", + "id": "mptungsten", + "wins": 10, + "losses": 4, + "matches": 14, + "winPercent": "71.43%", + "secondsPlayed": 20429 + }, + { + "mapName": "Blackwell Fields", + "image": "https://cdn.gametools.network/maps/bf6/Battlefield_6_Blackwell_Fields.webp", + "id": "mpbadlands", + "wins": 3, + "losses": 2, + "matches": 5, + "winPercent": "60.0%", + "secondsPlayed": 7833 + }, + { + "mapName": "REDSEC", + "image": "https://cdn.gametools.network/maps/bf6/Battlefield_6_Redsec.webp", + "id": "ftpgranite", + "wins": 25, + "losses": 118, + "matches": 143, + "winPercent": "17.48%", + "secondsPlayed": 142037 + } + ], + "gadgets": [ + { + "type": "Strike Packages", + "gadgetName": "Air Strike", + "image": "https://cdn.gametools.network/gadgets/bf6/T_UI_CALLINS_Airstrike_Thumb-638b4ee1.png", + "id": "callin_airstrike", + "kills": 0, + "assistsDamage": 0, + "assists": 0, + "spawns": 0, + "damage": 0, + "uses": 33, + "multiKills": 0, + "vehiclesDestroyedWith": 0, + "kpm": 0.0, + "dpm": 0.0, + "secondsPlayed": 703 + } + ], + "redsec": [ + { + "seasonId": "Season1", + "season": "Season 1", + "modes": [ + { + "modeId": "GraniteDuo0", + "mode": "Duos", + "matches": 1, + "wins": 1, + "losses": 18, + "kills": 42, + "deaths": 28, + "killDeath": 1.5, + "score": 55475, + "secondsPlayed": 13274, + "timePlayed": "3:41:14", + "extrActions": 0 + }, + { + "modeId": "GraniteSquad0", + "mode": "Quads", + "matches": 29, + "wins": 20, + "losses": 9, + "kills": 449, + "deaths": 165, + "killDeath": 2.72, + "score": 736765, + "secondsPlayed": 112415, + "timePlayed": "1 day, 7:13:35", + "extrActions": 2 + }, + { + "modeId": "GraniteGauntlet0", + "mode": "Gauntlet", + "matches": 5, + "wins": 4, + "losses": 1, + "kills": 200, + "deaths": 118, + "killDeath": 1.69, + "score": 167560, + "secondsPlayed": 16196, + "timePlayed": "4:29:56", + "extrActions": 6 + } + ] + } + ], + "bestClass": "Support", + "humanPrecentage": "13.64%", + "kills": 45873, + "deaths": 3736, + "wins": 244, + "loses": 112, + "killsPerMinute": 3.7, + "damagePerMinute": 0.0, + "killsPerMatch": 127.78, + "damagePerMatch": 0.0, + "headShots": 19649, + "winPercent": "68.54%", + "headshots": "42.83%", + "killDeath": 12.28, + "infantryKillDeath": 1.67, + "damage": 0, + "timePlayed": "8 days, 14:37:41", + "accuracy": "40.17%", + "revives": 1345, + "heals": 30606, + "resupplies": 4979, + "repairs": 7925, + "squadmateRevive": 529, + "thrownThrowables": 319, + "inRound": { + "revives": 122, + "resupplies": 138, + "spotAssists": 62, + "thrownThrowables": 37, + "playerTakeDowns": 5 + }, + "gadgetsDestoyed": 991, + "playerTakeDowns": 55, + "matchesPlayed": 359, + "secondsPlayed": 743861, + "dividedSecondsPlayed": { + "flying": 2021, + "driving": 11974 + }, + "saviorKills": 2015, + "shotsFired": 348851, + "shotsHit": 140150, + "killAssists": 6083, + "vehiclesDestroyed": 45, + "enemiesSpotted": 8040, + "dividedKills": { + "ads": 35149, + "grenades": 144, + "hipfire": 9044, + "longDistance": 695, + "melee": 76, + "multiKills": 1482, + "passenger": 377, + "vehicle": 739, + "roadkills": 45, + "human": 6255, + "weapons": { + "SMG": 11141, + "LMG": 0, + "DMR": 270, + "Shotguns": 510, + "Assault Rifles": 510 + }, + "inRound": { + "total": 4935, + "grenade": 24, + "headshots": 3824, + "melee": 34, + "multiKills": 157, + "weapons": { + "SMG": 2685, + "AR": 1600, + "DMR": 117 + } + } + }, + "devidedDamage": { + "passenger": 65107, + "vehicleDriver": 129750, + "toVehicle": 212921, + "inRound": { + "asVehicle": 33412 + } + }, + "devidedAssists": { + "driver": 177, + "passenger": 290, + "spot": 1283, + "pilot": 177, + "inRound": { + "total": 113 + } + }, + "distanceTraveled": { + "foot": 857640, + "passenger": 358029, + "vehicle": 565509 + }, + "sector": { + "captured": 366 + }, + "objective": { + "time": { + "total": 62374, + "attacked": 19898, + "defended": 32446 + }, + "armed": 128, + "captured": 296, + "neutralized": 187, + "defused": 34, + "destroyed": 59, + "inRound": { + "armed": 26, + "captured": 8, + "neutralized": 9, + "defused": 27, + "destroyed": 8 + } + }, + "XP": [ + { + "total": 15253700, + "performance": 6681800, + "accolades": 3311400 + } + ] +} + + +async def build_card(): + # logger.info(f"结果{play_stat}") + weapon, vehicle = await get_best_weapon_and_best_vehicle(play_stat) + pid = play_stat['id'] + kd = play_stat['killDeath'] + kpm = play_stat['killsPerMinute'] + acc = play_stat['accuracy'] + head_shots = play_stat['headshots'] + time_play = 100 + kills = int(play_stat['kills']) + kill_assists = int(play_stat['killAssists']) + revives = int(play_stat['revives']) + wins = int(play_stat['wins']) + loses = int(play_stat['loses']) + best_weapon = weapon + best_vehicle = vehicle + best_class = play_stat['bestClass'] + captured = play_stat['objective']['captured'] + score = sum(item.get("score", 0) for item in play_stat['classes']) + repairs = play_stat['repairs'] + img = await build_bf6_stats_card(game='bf6', + player='Sansorano_Yume', + pid=pid, + kd=kd, + kpm=1.11, + spm=256.3, + acc=acc, + head_shots="18.96%", + rank=110, + time_play=time_play, + kills=kills, + kill_assists=kill_assists, + revives=revives, + repairs=repairs, + captured=captured, + score=score, + wins=wins, + loses=loses, + destroyed=120, + best_weapon=best_weapon, + best_vehicle=best_vehicle, + best_class=best_class) + tmimg = Image.open(img) + tmimg.show() + if __name__ == "__main__": - # name = "A.R.O.N.A" - name = "Dog" - - asyncio.run(get_info(name, 0)) + asyncio.run(fetch_tracker_search( + "https://api.tracker.gg/api/v2/bf6/standard/search?platform=origin&query=ABrokenWill&autocomplete=true", + "D:/QQ Bot/BF_BOT/src/plugins/bf_bot/cookies/tracker.txt")) diff --git a/src/plugins/bf_bot/tracker_data.py b/src/plugins/bf_bot/tracker_data.py new file mode 100644 index 0000000..cf01bbf --- /dev/null +++ b/src/plugins/bf_bot/tracker_data.py @@ -0,0 +1,110 @@ +import asyncio +import os +from pathlib import Path +from typing import List, Dict, Optional +from nonebot import logger +from playwright.async_api import async_playwright, Response + + +async def fetch_tracker_search( + search_url: str, + cookies_txt: str, + wait_seconds: int = 5, +) -> Optional[Dict]: + """ + 使用 Playwright + cookies 访问 tracker.gg API 并截获响应数据 + """ + cookies = parse_netscape_cookies(cookies_txt) + if not cookies: + logger.error("cookies.txt 解析失败或为空") + return None + + result: Optional[Dict] = None + + async with async_playwright() as p: + browser = await p.chromium.launch( + executable_path="C:/Program Files/Google/Chrome/Application/chrome.exe", + headless=True, # False 可以看到浏览器操作 + args=[ + "--autoplay-policy=no-user-gesture-required", + "--disable-features=AutoplayDisableSuppression", + "--use-fake-ui-for-media-stream", + ] + ) + + context = await browser.new_context( + viewport={"width": 640, "height": 320}, + user_agent=( + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " + "AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/143.0.0.0 Safari/537.36" + ), + ) + + await context.add_cookies(cookies) + page = await context.new_page() + + # 响应监听 + async def handle_response(response: Response): + nonlocal result + try: + if search_url in response.url: + # 尝试解析 JSON + data = await response.json() + if data and "data" in data: + result = data + logger.info(f"成功截获响应数据: {data}") + except Exception as e: + logger.warning(f"解析响应失败: {e}") + + page.on("response", handle_response) + + try: + # 直接访问 API 链接 + await page.goto(search_url, wait_until="domcontentloaded", timeout=60000) + # 等待响应截获 + await page.wait_for_timeout(wait_seconds * 1000) + except Exception as e: + logger.error(f"访问页面出错: {e}") + finally: + await browser.close() + + return result + + +def parse_netscape_cookies(cookies_txt_path: str) -> List[Dict]: + """ + 解析 Netscape HTTP Cookie File -> Playwright cookies + """ + cookies: List[Dict] = [] + + if not os.path.exists(cookies_txt_path): + return cookies + + with open(cookies_txt_path, "r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line or line.startswith("#"): + continue + + parts = line.split("\t") + if len(parts) != 7: + continue + + domain, include_sub, path, secure, expiry, name, value = parts + + cookie = { + "name": name, + "value": value, + "domain": domain, + "path": path, + "secure": secure.upper() == "TRUE", + "httpOnly": False, + } + + if expiry.isdigit() and int(expiry) > 0: + cookie["expires"] = int(expiry) + + cookies.append(cookie) + + return cookies diff --git a/src/plugins/bf_bot/user_data/data_utils.py b/src/plugins/bf_bot/user_data/data_utils.py index ea62bb7..a07d583 100644 --- a/src/plugins/bf_bot/user_data/data_utils.py +++ b/src/plugins/bf_bot/user_data/data_utils.py @@ -1,10 +1,12 @@ import sqlite3 +import os from typing import List, Dict, Any, Optional class TableManager: def __init__(self, db_path: str = 'user_data.db'): - self.db_path = db_path + base_dir = os.path.dirname(os.path.abspath(__file__)) + self.db_path = os.path.join(base_dir, 'user_data.db') def _execute(self, sql: str, params: tuple = ()) -> sqlite3.Cursor: """执行SQL语句的通用方法""" @@ -17,76 +19,115 @@ class TableManager: class UserManager(TableManager): - def add_user(self, qq_id: str, ea_id: str, dog_tag_list: str) -> int: - """添加用户记录""" + def add_user(self, qq_id: str, ea_player_name: str, ea_player_id: str, ea_user_id: str, designation: str, + medals: str) -> int: + """添加用户""" cursor = self._execute( - "INSERT INTO users (qq_id, ea_id, dog_tag_list) VALUES (?, ?, ?)", - (qq_id, ea_id, dog_tag_list) + "INSERT INTO users (qq_id, ea_player_name,ea_player_id,ea_user_id, designation,medals) VALUES (?, ?, ?, ?, ?,?)", + (qq_id, ea_player_name, ea_player_id, ea_user_id, designation, medals) ) return cursor.lastrowid + def update_user(self, qq_id: str, ea_player_name: str, ea_player_id: str, ea_user_id: str, designation: str, + medals: str) -> int: + """修改用户""" + cursor = self._execute( + "UPDATE users SET ea_player_name = ?, ea_player_id = ?,ea_user_id = ? WHERE qq_id = ?", + (ea_player_name, ea_player_id, ea_user_id, qq_id) + ) + return cursor.rowcount + def get_user_by_qq(self, qq_id: str) -> Optional[Dict[str, Any]]: - """通过QQ号查询用户""" cursor = self._execute( "SELECT * FROM users WHERE qq_id = ?", (qq_id,) ) - return dict(cursor.fetchone()) if cursor.fetchone() else None + row = cursor.fetchone() + return dict(row) if row else None - def update_dog_tags(self, user_id: int, new_tags: str) -> bool: + def get_user_by_ea_id(self, ea_user_id: str) -> Optional[Dict[str, Any]]: + cursor = self._execute( + "SELECT * FROM users WHERE ea_user_id = ?", + (ea_user_id,) + ) + row = cursor.fetchone() + return dict(row) if row else None + + def delete_user_by_qq(self, qq_id: str) -> Optional[Dict[str, Any]]: + cursor = self._execute( + "DELETE FROM users WHERE qq_id = ?", + (qq_id,) + ) + return cursor.rowcount + + def update_dog_tags(self, qq_id: int, medals: str) -> bool: """更新用户的狗牌列表""" self._execute( - "UPDATE users SET dog_tag_list = ? WHERE id = ?", - (new_tags, user_id) + "UPDATE users SET medals = ? WHERE id = ?", + (medals, qq_id) ) return True -class DogTagManager(TableManager): - def create_tag(self, name: str) -> int: - """创建新狗牌""" +class DesignationManager(TableManager): + def create_designation(self, name: str, icon_path: str) -> int: + """创建新标签""" cursor = self._execute( - "INSERT INTO dog_tag (name) VALUES (?)", - (name,) + "INSERT INTO designation (name,icon_path) VALUES (?,?)", + (name, icon_path) ) return cursor.lastrowid - def get_all_tags(self) -> List[Dict[str, Any]]: - """获取所有狗牌""" - cursor = self._execute("SELECT * FROM dog_tag") + def get_all_designation(self) -> List[Dict[str, Any]]: + """获取所有标签""" + cursor = self._execute("SELECT * FROM designation") + return [dict(row) for row in cursor.fetchall()] + + def get_designation_by_id_list(self, ids: List[int]) -> List[Dict[str, Any]]: + """根据 ID 列表获取标签""" + + if not ids: + return [] + + placeholders = ",".join(["?"] * len(ids)) + sql = f""" + SELECT * + FROM designation + WHERE id IN ({placeholders}) + """ + + cursor = self._execute(sql, ids) return [dict(row) for row in cursor.fetchall()] -class QueryRecordManager(TableManager): - def log_query(self, user_id: str, target_id: str, status: str) -> int: - """记录查询操作""" - cursor = self._execute( - """INSERT INTO query_record - (user_id, target_id, status) - VALUES (?, ?, ?)""", - (user_id, target_id, status) - ) - return cursor.lastrowid - - def get_user_history(self, user_id: str) -> List[Dict[str, Any]]: - """获取用户查询历史""" - cursor = self._execute( - "SELECT * FROM query_record WHERE user_id = ?", - (user_id,) - ) - return [dict(row) for row in cursor.fetchall()] +# class QueryRecordManager(TableManager): +# def log_query(self, user_id: str, target_id: str, status: str) -> int: +# """记录查询操作""" +# cursor = self._execute( +# """INSERT INTO query_record +# (user_id, target_id, status) +# VALUES (?, ?, ?)""", +# (user_id, target_id, status) +# ) +# return cursor.lastrowid +# +# def get_user_history(self, user_id: str) -> List[Dict[str, Any]]: +# """获取用户查询历史""" +# cursor = self._execute( +# "SELECT * FROM query_record WHERE user_id = ?", +# (user_id,) +# ) +# return [dict(row) for row in cursor.fetchall()] if __name__ == "__main__": - # 使用示例 - user_db = UserManager() - user_id = user_db.add_user("123456", "EA_001", "tag1,tag2") - print(f"Created user with ID: {user_id}") + tag_db = DesignationManager() + # tag_id = tag_db.create_designation("DEV","DEV.png") + # tag_id = tag_db.create_designation("DICE", "DICE.png") + # tag_id = tag_db.create_designation("IC", "IC.png") + # tag_id = tag_db.create_designation("OWNER", "OWNER.png") + # print(f"Created tag with ID: {tag_id}") - tag_db = DogTagManager() - tag_id = tag_db.create_tag("新狗牌") - print(f"Created tag with ID: {tag_id}") + record_id = tag_db.get_designation_by_id_list([1, 2, 3]) - record_db = QueryRecordManager() - record_id = record_db.log_query("123", "456", "success") print(f"Logged query with ID: {record_id}") diff --git a/src/plugins/bf_bot/user_data/init_database.py b/src/plugins/bf_bot/user_data/init_database.py index eb36628..316da69 100644 --- a/src/plugins/bf_bot/user_data/init_database.py +++ b/src/plugins/bf_bot/user_data/init_database.py @@ -11,20 +11,32 @@ class DatabaseManager: 'users': [ ('id', 'INTEGER PRIMARY KEY AUTOINCREMENT'), ('qq_id', 'TEXT NOT NULL'), - ('ea_id', 'TEXT UNIQUE'), - ('dog_tag_list', 'TEXT NOT NULL'), + ('ea_player_name', 'TEXT UNIQUE'), + ('ea_player_id', 'TEXT UNIQUE'), + ('ea_user_id', 'TEXT UNIQUE'), + ('designation', 'TEXT NOT NULL'), + ('medals', 'TEXT NOT NULL'), ('create_time', 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP') ], - 'dog_tag': [ + 'designation': [ ('id', 'INTEGER PRIMARY KEY'), ('name', 'TEXT NOT NULL'), + ('icon_path', 'TEXT NOT NULL'), + ('create_time', 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP') + ], + 'medals': [ + ('id', 'INTEGER PRIMARY KEY'), + ('name', 'TEXT NOT NULL'), + ('icon_path', 'TEXT NOT NULL'), ('create_time', 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP') ] , 'query_record': [ ('id', 'INTEGER PRIMARY KEY'), ('user_id', 'TEXT NOT NULL'), - ('target_id', 'TEXT NOT NULL'), + ('ea_player_name', 'TEXT NOT NULL'), + ('ea_player_id', 'TEXT NOT NULL'), + ('ea_user_id', 'TEXT NOT NULL'), ('status', 'TEXT NOT NULL'), ('create_time', 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP') ]