-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrun_level.py
More file actions
155 lines (132 loc) · 5.43 KB
/
Copy pathrun_level.py
File metadata and controls
155 lines (132 loc) · 5.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/env python3
"""
Standalone Level Bot Runner
Quick start without the full CLI.
Usage:
python run_level.py --uid 12345678 --password abc123 --team-code 654321
python run_level.py --accounts-file accounts.json --team-code 654321
python run_level.py --uid 12345678 --password abc123 --team-code 654321 --max-cycles 0
"""
import asyncio
import argparse
import json
import logging
import sys
import os
# Add project root to path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
def setup_logging(verbose: bool = False):
"""Configure logging."""
level = logging.DEBUG if verbose else logging.INFO
logging.basicConfig(
level=level,
format="%(asctime)s | %(levelname)-8s | [%(name)s] %(message)s",
handlers=[
logging.StreamHandler(sys.stdout),
logging.FileHandler("data/level_bot.log"),
],
)
# Suppress noisy libraries
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("httpcore").setLevel(logging.WARNING)
async def run_single(uid: str, password: str, team_code: str, args):
"""Run a single level bot instance."""
from src.level.bot import LevelBot
bot = LevelBot(
uid=uid,
password=password,
team_code=team_code,
max_cycles=args.max_cycles,
spam_duration=args.spam_duration,
spam_delay=args.spam_delay,
wait_after_match=args.wait_after,
)
try:
stats = await bot.start()
print(f"\n{'='*50}")
print(f" Bot finished!")
print(f" UID: {stats.uid}")
print(f" Team Code: {stats.team_code}")
print(f" Connected: {'✅' if stats.connected else '❌'}")
print(f" Cycles: {stats.cycles}")
print(f" Matches: {stats.matches}")
print(f" Uptime: {stats.uptime_seconds:.0f}s")
print(f" Final State: {stats.state}")
print(f"{'='*50}")
except KeyboardInterrupt:
print("\n⏹️ Stopping bot...")
await bot.stop()
except Exception as e:
logging.error(f"Bot error: {e}", exc_info=True)
return 1
return 0
async def run_multi(accounts: dict, team_code: str, args):
"""Run multiple level bot instances concurrently."""
from src.level.bot import LevelBot
tasks = []
for uid, password in accounts.items():
bot = LevelBot(
uid=uid,
password=password,
team_code=team_code,
max_cycles=args.max_cycles,
spam_duration=args.spam_duration,
spam_delay=args.spam_delay,
wait_after_match=args.wait_after,
)
tasks.append(bot.start())
results = await asyncio.gather(*tasks, return_exceptions=True)
for i, (uid, result) in enumerate(zip(accounts.keys(), results)):
if isinstance(result, Exception):
print(f"❌ {uid}: {result}")
else:
print(f"✅ {uid}: {result.cycles} cycles, {result.matches} matches")
def main():
parser = argparse.ArgumentParser(
description="Free Fire Level Bot — Auto level-up via team match spam",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Single account
python run_level.py --uid 12345678 --password abc123 --team-code 654321
# Multiple accounts from JSON file
python run_level.py --accounts-file accounts.json --team-code 654321
# Infinite loops, faster cycles
python run_level.py --uid 12345678 --password abc123 --team-code 654321 --max-cycles 0 --spam-duration 10 --wait-after 15
""",
)
parser.add_argument("--uid", "-u", help="Guest account UID")
parser.add_argument("--password", "-p", help="Guest account password")
parser.add_argument("--team-code", "-t", required=True, help="Team/squad code (digits only)")
parser.add_argument("--accounts-file", "-f", help="JSON file with {uid: password} pairs")
parser.add_argument("--max-cycles", type=int, default=1000, help="Max match cycles (0 = infinite)")
parser.add_argument("--spam-duration", type=int, default=18, help="Seconds to spam start packets")
parser.add_argument("--spam-delay", type=float, default=0.2, help="Delay between start packets")
parser.add_argument("--wait-after", type=int, default=20, help="Seconds to wait after match")
parser.add_argument("--verbose", "-v", action="store_true", help="Debug logging")
args = parser.parse_args()
# Ensure data directory exists
os.makedirs("data", exist_ok=True)
setup_logging(args.verbose)
logger = logging.getLogger("levelbot")
if args.accounts_file:
if not os.path.exists(args.accounts_file):
print(f"❌ Accounts file not found: {args.accounts_file}")
sys.exit(1)
with open(args.accounts_file) as f:
accounts = json.load(f)
if not accounts:
print("❌ No accounts in file")
sys.exit(1)
print(f"🚀 Starting {len(accounts)} bot instance(s) | Team: {args.team_code}")
asyncio.run(run_multi(accounts, args.team_code, args))
elif args.uid and args.password:
print(f"🚀 Starting level bot | UID: {args.uid} | Team: {args.team_code}")
exit_code = asyncio.run(run_single(args.uid, args.password, args.team_code, args))
sys.exit(exit_code)
else:
print("❌ Either --uid + --password or --accounts-file is required")
parser.print_help()
sys.exit(1)
if __name__ == "__main__":
main()