forked from jacklee1792/BWBot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbwbot.py
executable file
·249 lines (212 loc) · 7.37 KB
/
bwbot.py
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
import os
import requests
import json
import datetime
import dotenv
import discord
from discord.ext import commands
dotenv.load_dotenv()
# retrieve api keys and discord token
API_KEY = os.environ.get("hypixel-api-key")
TOKEN = os.environ.get("discord-bot-token")
# modify this to change bot prefix
bot = commands.Bot(command_prefix='!')
item_cnt = 5
last_time = datetime.datetime.now()
pull_cnt = 0
menu_items = ['STARS', 'IGN', 'FKDR', 'WR', 'WS']
longest = []
# function used to get the json files according to info_type
def get_json(API_KEY, uuid_string, info_type):
api_json = None
try:
api_response = requests.get(f'https://api.hypixel.net/{info_type}?key={API_KEY}&uuid={uuid_string}')
api_json = json.loads(api_response.text)
except:
pass
return api_json
# Get the uuid of username
def get_uuid(username):
uuid_response = requests.get(f'https://api.mojang.com/users/profiles/minecraft/{username}')
uuid_string = None
username_string = None
try:
uuid_json = json.loads(uuid_response.text)
uuid_string = uuid_json['id']
username_string = uuid_json['name']
except:
username_string = username
return (uuid_string, username_string)
# get statistics function
def get_stats(username):
global longest_star, longest_username, longest_fkdr, longest_winrate, longest_winstreak
username_is_valid = None
# Get the uuid of username
uuid_string, username_string = get_uuid(username)
# Get the stats
api_json = get_json(API_KEY, uuid_string, "player")
# Stars
stars = ''
try:
stars = api_json['player']['achievements']['bedwars_level']
except:
stars = '?'
stars_string = f'[{stars}✫]'
# Final kill-death ratio
fkdr_string = ''
try:
final_kills = int(api_json['player']['stats']['Bedwars']['final_kills_bedwars'])
final_deaths = int(api_json['player']['stats']['Bedwars']['final_deaths_bedwars'])
fkdr = final_kills / final_deaths
fkdr_string += f'{fkdr:.2f}'
fkdr_string += f'({final_kills}/{final_deaths})'
except:
fkdr_string += '?'
# Winrate
winrate_string = ''
try:
wins = int(api_json['player']['stats']['Bedwars']['wins_bedwars'])
losses = int(api_json['player']['stats']['Bedwars']['losses_bedwars'])
winrate = wins / (wins + losses) * 100
winrate_string += f'{winrate:.2f}%'
except:
winrate_string += '?'
# Winstreak
winstreak_string = ''
try:
winstreak = api_json['player']['stats']['Bedwars']['winstreak']
winstreak_string += str(winstreak)
except:
winstreak_string += '?'
ret = []
ret.append(stars_string)
ret.append(username_string)
ret.append(fkdr_string)
ret.append(winrate_string)
ret.append(winstreak_string)
for i in range(item_cnt):
longest[i] = max(longest[i], len(ret[i]) + 2)
return ret
# Stats command
@bot.command(name='stats')
async def stats(ctx, *username_args):
global longest, last_time, pull_cnt
# Impose 6 argument limit
longest = [7, 6, 6, 4, 4]
if len(username_args) > 6:
await ctx.send(ctx.message.author.mention)
return await ctx.send('Too many arguments! Please input between 1 and 6 usernames')
elif len(username_args) == 0:
await ctx.send(ctx.message.author.mention)
return await ctx.send('Too few arguments! Please input between 1 and 6 usernames')
current_time = datetime.datetime.now()
# print log
with open("log.txt", "a") as log:
log.write(f"[{current_time}] New stats query about {len(username_args)} players from {ctx.author}\n")
# Check if sufficient time has passed since last query
delta_seconds = (current_time - last_time).total_seconds();
# At most 6 calls every 3.5 seconds, at most ~100 queries per minute
# print(current_time, last_time)
if delta_seconds < 3.5 and len(username_args) + pull_cnt >= 6:
await ctx.send(ctx.message.author.mention)
return await ctx.send(f'Please wait {3.5 - delta_seconds:.2f}s before sending another query!')
# if the cooldown has passed, reset the cnt and time
elif delta_seconds >= 3.5:
last_time = current_time
pull_cnt = 0
pull_cnt += len(username_args)
# Output stats table
output = '```py\n# '
# Fetch results
results = []
for username in username_args:
results.append(get_stats(username))
# add menu items to output
for item_idx in range(item_cnt):
output += menu_items[item_idx].ljust(longest[item_idx])
output += '\n'
# add each query's result to output
splitter = ''
for idx in range(len(results)):
current_string = f'{idx + 1}. '
for item_idx in range(item_cnt):
current_string += results[idx][item_idx].ljust(longest[item_idx])
current_string += '\n'
splitter = '—' * len(current_string) + '\n'
output += splitter
output += current_string
output += splitter + '```\n'
await ctx.send(ctx.message.author.mention)
return await ctx.send(output)
# get status of the player
@bot.command(name="status")
async def status(ctx, *username_arg):
global last_time, pull_cnt
if(len(username_arg) > 1):
await ctx.send(ctx.message.author.mention)
return await ctx.send("Please input 1 username only for each query!")
elif len(username_arg) == 0:
await ctx.send(ctx.message.author.mention)
return await ctx.send("Please input 1 username for each query!")
# print(current_time, last_time)
current_time = datetime.datetime.now()
delta_seconds = (current_time - last_time).total_seconds();
# print log
with open("log.txt", "a") as log:
log.write(f"[{current_time}] New status query about \"{username_arg[0]}\" from {ctx.author}\n")
# print(f"{last_time} - {current_time} : {delta_seconds}")
# print(f"pull cnt: {pull_cnt + 1}")
# At most 6 calls every 3.5 seconds, at most ~100 queries per minute
if delta_seconds < 3.5 and len(username_arg) + pull_cnt >= 6:
await ctx.send(ctx.message.author.mention)
return await ctx.send(f'Please wait {3.5 - delta_seconds:.2f}s before sending another query!')
# if the cooldown has passed, reset the cnt and time
elif delta_seconds >= 3.5:
last_time = current_time
pull_cnt = 0
pull_cnt += len(username_arg)
# get uuid and username
uuid_string, username_string = get_uuid(username_arg[0])
api_json = get_json(API_KEY, uuid_string, "status")
if not bool(api_json["success"]):
await ctx.send(ctx.message.author.mention)
return await ctx.send(embed=discord.Embed(description = f'The player "{username_string}" doesn\'t exist or has not logged on to Hypixel before!'))
# first retrieve the player model
image = f"https://mc-heads.net/head/{uuid_string}/128"
#default embed
embed = discord.Embed(
title = "Status",
description = "Online",
colour = discord.Colour.blue()
)
embed.set_author(
name = username_string,
icon_url = image
)
embed.set_thumbnail(url = image)
# if player is online
if bool(api_json["session"]["online"]):
# displays gamemode, status and mode
embed.add_field(name="gameType",value=api_json["session"]["gameType"])
embed.add_field(name="mode", value=api_json["session"]["mode"])
else:
# displays status as offline
embed.description = "Offline"
# return the embed
await ctx.send(ctx.message.author.mention)
return await ctx.send(embed=embed)
# only admin accessible kill command
@bot.command(name='kill')
@commands.has_permissions(administrator=True)
async def kill(ctx):
with open("log.txt", "a") as log:
log.write(f"[{datetime.datetime.now()}] Shutting Down command from {ctx.author}\n")
await ctx.send("shutting down...")
return await ctx.bot.logout()
# main function
def main():
with open("log.txt", "w") as log:
log.write(f"[{datetime.datetime.now()}] Bot Started! Waiting for Query...\n")
bot.run(TOKEN)
if __name__ == '__main__':
main()