2020-08-31 19:58:01 +02:00
import asyncio
2020-09-01 02:08:49 +02:00
import itertools
2020-09-01 16:17:56 +02:00
import math
2020-09-01 02:08:49 +02:00
2020-08-31 19:58:01 +02:00
from redbot . core import commands
from redbot . core import Config , checks
from discord import TextChannel
2020-08-31 23:56:09 +02:00
import discord
2020-08-31 19:58:01 +02:00
import traceback
import requests
2020-09-01 16:12:08 +02:00
from datetime import datetime , timezone , timedelta
def utc_to_local ( utc_dt ) :
return utc_dt . replace ( tzinfo = timezone . utc ) . astimezone ( tz = None )
2020-08-31 19:58:01 +02:00
class WynncraftCog ( commands . Cog ) :
2020-08-31 20:03:24 +02:00
def __init__ ( self , bot ) :
self . bot = bot
2020-08-31 19:58:01 +02:00
self . config = Config . get_conf ( self , identifier = 48775419874 )
default_guild = {
2020-08-31 23:56:09 +02:00
" guild_name " : None , # OK
" ping_levels " : False , # OK
" ping_channel " : None , # OK
" role_levels " : [
750098524976185525 , # 0-9
750098542802239488 , # 10-19
750098546883166292 , # 20-29
750098551756947496 , # 30-39
750098557444292740 , # 40-49
750098560732889088 , # 50-59
750098568194424872 , # 60-69
750098573353418822 , # 70-79
750098579535822918 , # 80-89
750098584082448434 , # 90-99
750098593976811550 , # 100+
] ,
" role_class " : {
" mage " : 750097053840965752 ,
" assassin " : 750097058362425417 ,
" shaman " : 750097056093438012 ,
" archer " : 750097050867204246 ,
" warrior " : 750097044433272833
} ,
2020-09-01 02:08:49 +02:00
" update_msg " : 750124413529358467 ,
" role_professions " : {
" farming " : [
743544309059551292 , # 0-9
750103671077077004 , # 10-19
750103673178423397 , # 20-29
750103675195752528 , # 30-39
750103677011755080 , # 40-49
750103681046675527 , # 50-59
750103683349479452 , # 60-69
750103692182552667 , # 70-79
750103687589920789 , # 80-89
750103685295767734 , # 90-99
750103689536077966 , # 100-109
750103679314558980 , # 110
] ,
" mining " : [
743544348821553305 , # 0-9
750105003464851508 , # 10-19
750105011173851176 , # 20-29
750105019260469288 , # 30-39
750104996204380211 , # 40-49
750105001522888874 , # 50-59
750105005759135805 , # 60-69
750105016433377380 , # 70-79
750105008644554783 , # 80-89
750105013749153792 , # 90-99
750104998670762075 , # 100-109
750104994392309801 , # 110
] ,
" fishing " : [
743544397152518146 , # 0-9
750105742127923303 , # 10-19
750105731482779779 , # 20-29
750105744774529124 , # 30-39
750105734615662672 , # 40-49
750105754739933345 , # 50-59
750105729284964472 , # 60-69
750105749899837551 , # 70-79
750105752374345769 , # 80-89
750105747219546122 , # 90-99
750105737254011051 , # 100-109
750105739716067488 , # 110
] ,
" woodcutting " : [
743920688607264818 , # 0-9
750106425174261771 , # 10-19
750106428253012048 , # 20-29
750106431033835570 , # 30-39
750106433785430126 , # 40-49
750106436419452949 , # 50-59
750106438931579032 , # 60-69
750106441557475430 , # 70-79
750106444493488129 , # 80-89
750106446883979326 , # 90-99
750106449790631937 , # 100-109
750106452277985301 , # 110
]
}
2020-08-31 19:58:01 +02:00
}
2020-08-31 20:25:45 +02:00
default_global = {
" log " : True
}
2020-08-31 19:58:01 +02:00
self . config . register_guild ( * * default_guild )
2020-08-31 20:25:45 +02:00
self . config . register_global ( * * default_global )
2020-08-31 19:58:01 +02:00
@commands.command ( )
@checks.admin_or_permissions ( manage_guild = True )
2020-08-31 23:56:09 +02:00
async def ping_channel ( self , ctx , channel : TextChannel ) :
i = channel . id
await self . config . guild ( ctx . guild ) . ping_channel . set ( i )
await self . config . guild ( ctx . guild ) . ping_levels . set ( True )
await ctx . send ( " Les messages de montée de niveau seront désormais envoyés dans %s " % channel . mention )
2020-08-31 19:58:01 +02:00
@commands.command ( )
@checks.admin_or_permissions ( manage_guild = True )
2020-08-31 23:56:09 +02:00
async def ping_levels ( self , ctx , state ) :
if state == " true " or state == " on " :
await self . config . ping_levels . set ( True )
await ctx . send ( " :white_check_mark: Activé! " )
elif state == " false " or state == " off " :
await self . config . ping_levels . set ( False )
await ctx . send ( " :white_check_mark: Désactivé! " )
2020-08-31 19:58:01 +02:00
else :
2020-08-31 23:56:09 +02:00
await ctx . send ( " :x: " )
2020-08-31 19:58:01 +02:00
@commands.command ( )
@checks.admin_or_permissions ( manage_guild = True )
2020-08-31 23:56:09 +02:00
async def set_guild ( self , ctx , guild_name ) :
await self . config . guild ( ctx . guild ) . guild_name . set ( guild_name )
await ctx . send ( " :white_check_mark: Votre guilde est désormais ** %s ** " % guild_name )
2020-08-31 19:58:01 +02:00
2020-09-07 20:07:13 +02:00
@commands.command ( )
async def player ( self , ctx , player_name ) :
req = requests . get ( " https://api.wynncraft.com/v2/player/ %s /stats " % player_name ) . json ( )
if not req [ " data " ] :
await ctx . send ( " :x: joueur non trouvé " )
return
player_data = req [ " data " ] [ 0 ]
real_player_name = player_data [ " username " ]
2020-09-07 20:09:13 +02:00
output = " **__ %s __** \n " % real_player_name
output + = " :black_square_button: **Joueur depuis:** %s \n " % player_data [ " meta " ] [ " firstJoin " ]
output + = " :black_square_button: **Niveau total:** %s \n " % player_data [ " global " ] [ " totalLevel " ] [ " combat " ]
2020-09-07 20:10:18 +02:00
output + = " :black_square_button: **__Classes__**: \n "
2020-09-07 20:07:13 +02:00
for c in player_data [ " classes " ] :
2020-09-07 20:09:13 +02:00
output + = " \t :diamond_shape_with_a_dot_inside: ** %s :** level %s \n " % ( c [ " name " ] , c [ " professions " ] [ " combat " ] [ " level " ] )
2020-09-07 20:07:13 +02:00
await ctx . send ( output )
2020-08-31 20:25:45 +02:00
@commands.command ( )
@checks.is_owner ( )
async def log ( self , ctx , state ) :
state = state . lower ( )
if state == " true " or state == " on " :
await self . config . log . set ( True )
await ctx . send ( " :white_check_mark: " )
2020-08-31 23:56:09 +02:00
print ( " Logs on " )
2020-08-31 20:25:45 +02:00
elif state == " false " or state == " off " :
await self . config . log . set ( False )
await ctx . send ( " :white_check_mark: " )
2020-08-31 23:56:09 +02:00
print ( " Logs off " )
2020-08-31 20:25:45 +02:00
else :
await ctx . send ( " :x: " )
2020-08-31 20:26:35 +02:00
async def _log ( self , s ) :
2020-08-31 20:25:45 +02:00
if await self . config . log ( ) :
print ( s )
2020-08-31 19:58:01 +02:00
async def loop ( self ) :
await self . bot . wait_until_ready ( )
last_status = { }
while self is self . bot . get_cog ( " WynncraftCog " ) :
2020-08-31 20:26:35 +02:00
await self . _log ( " Looping guilds " )
2020-09-01 00:13:00 +02:00
for guild in self . bot . guilds :
2020-08-31 23:56:09 +02:00
roles_combat_level = await self . config . guild ( guild ) . role_levels ( )
2020-09-01 01:10:39 +02:00
roles_classes = await self . config . guild ( guild ) . role_class ( )
2020-09-01 02:08:49 +02:00
roles_professions = await self . config . guild ( guild ) . role_professions ( )
2020-08-31 19:58:01 +02:00
guild_id = guild . id
2020-09-01 01:10:39 +02:00
online_players = [ ]
2020-09-01 16:12:08 +02:00
almost_online_players = [ ]
2020-08-31 20:26:35 +02:00
await self . _log ( " Loop id %s " % guild_id )
2020-08-31 19:58:01 +02:00
try :
2020-08-31 23:56:09 +02:00
guild_name = await self . config . guild ( guild ) . guild_name ( )
2020-08-31 23:59:10 +02:00
if not guild_name :
continue
2020-08-31 23:56:09 +02:00
r = requests . get ( " https://api.wynncraft.com/public_api.php?action=guildStats&command= %s " % guild_name ) . json ( )
for member in r [ " members " ] :
member_name = member [ " name " ]
await self . _log ( " calling API for player %s " % member_name )
r = requests . get ( " https://api.wynncraft.com/v2/player/ %s /stats " % member_name ) . json ( )
max_combat_lvl_class = None
2020-09-01 02:08:49 +02:00
best_professions = dict . fromkeys ( list ( roles_professions . keys ( ) ) , 0 )
2020-09-01 00:07:20 +02:00
if not r [ " data " ] :
2020-09-01 02:08:49 +02:00
await self . _log ( " %s had empty data %s " % ( member_name , r [ " data " ] ) )
2020-09-01 00:07:20 +02:00
continue
2020-08-31 23:56:09 +02:00
for cl in r [ " data " ] [ 0 ] [ " classes " ] :
if guild_id not in last_status :
last_status [ guild_id ] = { }
if member_name not in last_status [ guild_id ] :
last_status [ guild_id ] [ member_name ] = { }
if cl [ " name " ] not in last_status [ guild_id ] [ member_name ] :
last_status [ guild_id ] [ member_name ] [ cl [ " name " ] ] = cl
# ping level up
ping_channel_id = await self . config . guild ( guild ) . ping_channel ( )
if await self . config . guild ( guild ) . ping_levels ( ) and ping_channel_id :
await self . _log ( " Checking for level up " )
if cl [ " professions " ] [ " combat " ] [ " level " ] > last_status [ guild_id ] [ member_name ] [ cl [ " name " ] ] [ " professions " ] [ " combat " ] [ " level " ] :
ping_channel = self . bot . get_channel ( ping_channel_id )
await ping_channel . send ( " :high_brightness: %s a level up au niveau %s ! GG! " % ( member_name , cl [ " professions " ] [ " combat " ] [ " level " ] ) )
2020-08-31 20:06:55 +02:00
else :
2020-08-31 23:56:09 +02:00
await self . _log ( " Player %s had last level %s and current %s " % ( member_name , last_status [ guild_id ] [ member_name ] [ cl [ " name " ] ] [ " professions " ] [ " combat " ] [ " level " ] , cl [ " professions " ] [ " combat " ] [ " level " ] ) )
last_status [ guild_id ] [ member_name ] [ cl [ " name " ] ] = cl
# get max_combat_lvl_class
2020-09-01 00:00:46 +02:00
if not max_combat_lvl_class or cl [ " professions " ] [ " combat " ] [ " level " ] > max_combat_lvl_class [ " professions " ] [ " combat " ] [ " level " ] :
2020-08-31 23:56:09 +02:00
max_combat_lvl_class = cl
2020-09-01 02:08:49 +02:00
# set max_lvl_professions
for prof_name in list ( roles_professions . keys ( ) ) :
if cl [ " professions " ] [ prof_name ] [ " level " ] > best_professions [ prof_name ] :
best_professions [ prof_name ] = cl [ " professions " ] [ prof_name ] [ " level " ]
2020-09-01 01:31:20 +02:00
if r [ " data " ] [ 0 ] [ " meta " ] [ " location " ] [ " online " ] :
2020-09-01 01:25:00 +02:00
await self . _log ( " %s is online " % member_name )
2020-09-01 01:10:39 +02:00
online_players . append ( r )
2020-09-01 01:25:00 +02:00
else :
2020-09-01 16:12:08 +02:00
last_join_dt_utc = datetime . strptime ( r [ " data " ] [ 0 ] [ " meta " ] [ " lastJoin " ] , " % Y- % m- %d T % H: % M: % S. %f Z " )
last_join_dt_local = utc_to_local ( last_join_dt_utc )
2020-09-01 16:15:30 +02:00
if last_join_dt_local + timedelta ( minutes = 10 ) > datetime . now ( last_join_dt_local . tzinfo ) :
2020-09-01 16:12:08 +02:00
await self . _log ( " %s is ALMOST online " % member_name )
almost_online_players . append ( r )
else :
await self . _log ( " %s was offline: %s " % ( member_name , r [ " data " ] [ 0 ] [ " meta " ] [ " location " ] ) )
2020-09-01 01:10:39 +02:00
2020-09-01 01:25:00 +02:00
await self . _log ( " Setting roles " )
2020-08-31 23:56:09 +02:00
# set max_combat_lvl_class role
2020-09-01 01:25:00 +02:00
discord_member = discord . utils . find ( lambda m : m . display_name . lower ( ) == member_name . lower ( ) , guild . members )
2020-08-31 23:56:09 +02:00
if max_combat_lvl_class and discord_member :
await self . _log ( " max_combat_lvl_class and discord_member True " )
2020-09-01 01:10:39 +02:00
# update level
2020-08-31 23:56:09 +02:00
max_combat_lvl = max_combat_lvl_class [ " professions " ] [ " combat " ] [ " level " ]
combat_role_index = max_combat_lvl / / 10
if combat_role_index > 10 : combat_role_index = 10
combat_role_id = roles_combat_level [ combat_role_index ]
2020-09-01 00:18:56 +02:00
combat_role = guild . get_role ( combat_role_id )
2020-08-31 23:56:09 +02:00
if combat_role not in discord_member . roles :
await self . _log ( " Add role: %s " % combat_role )
2020-09-01 00:24:03 +02:00
await discord_member . add_roles ( combat_role )
2020-08-31 23:56:09 +02:00
2020-09-01 00:39:10 +02:00
roles_to_remove = list ( filter ( lambda role : role . id in roles_combat_level and role . id != combat_role_id , discord_member . roles ) )
2020-08-31 23:56:09 +02:00
if roles_to_remove :
await self . _log ( " remove roles: %s " % roles_to_remove )
2020-09-01 00:44:11 +02:00
await discord_member . remove_roles ( * roles_to_remove )
2020-09-01 01:10:39 +02:00
# update class
class_name = max_combat_lvl_class [ " name " ]
class_role_id = None
if class_name . startswith ( " archer " ) or class_name . startswith ( " hunter " ) :
class_role_id = roles_classes [ " archer " ]
if class_name . startswith ( " mage " ) or class_name . startswith ( " darkwizard " ) :
class_role_id = roles_classes [ " mage " ]
if class_name . startswith ( " assassin " ) or class_name . startswith ( " ninja " ) :
class_role_id = roles_classes [ " assassin " ]
if class_name . startswith ( " warrior " ) or class_name . startswith ( " knight " ) :
class_role_id = roles_classes [ " warrior " ]
if class_name . startswith ( " shaman " ) or class_name . startswith ( " skyseer " ) :
class_role_id = roles_classes [ " shaman " ]
class_role = guild . get_role ( class_role_id )
if class_role not in discord_member . roles :
await self . _log ( " Add role: %s " % class_role )
await discord_member . add_roles ( class_role )
2020-09-01 01:14:47 +02:00
roles_to_remove = list ( filter ( lambda role : role . id in list ( roles_classes . values ( ) ) and role . id != class_role_id , discord_member . roles ) )
2020-09-01 01:10:39 +02:00
if roles_to_remove :
await self . _log ( " remove roles: %s " % roles_to_remove )
await discord_member . remove_roles ( * roles_to_remove )
2020-09-01 02:08:49 +02:00
# update professions
role_ids_to_add = [ ]
for prof_name in best_professions :
prof_level = best_professions [ prof_name ]
if prof_level < 5 : continue # do not add roles for professions < lvl 5
prof_role_index = prof_level / / 10
if prof_role_index > 10 : prof_role_index = 10
role_ids_to_add . append ( roles_professions [ prof_name ] [ prof_role_index ] )
roles_to_add = [ ]
for role_id_to_add in role_ids_to_add :
roles_to_add . append ( guild . get_role ( role_id_to_add ) )
await self . _log ( " Add role: %s " % roles_to_add )
await discord_member . add_roles ( * roles_to_add )
all_prof_ids = list ( itertools . chain . from_iterable ( [ roles_professions [ b ] for b in roles_professions ] ) )
2020-09-01 02:09:49 +02:00
roles_to_remove = list ( filter ( lambda role : role . id in all_prof_ids and role . id not in role_ids_to_add , discord_member . roles ) )
2020-09-01 02:08:49 +02:00
if roles_to_remove :
await self . _log ( " remove roles: %s " % roles_to_remove )
await discord_member . remove_roles ( * roles_to_remove )
2020-08-31 23:56:09 +02:00
else :
2020-09-01 00:10:15 +02:00
await self . _log ( " max_combat_lvl_class: %s , discord_member: %s (name: %s ) " % ( max_combat_lvl_class , discord_member , member_name ) )
2020-09-01 01:10:39 +02:00
# update online players
2020-09-01 01:25:00 +02:00
await self . _log ( " Updating online list " )
2020-09-01 01:10:39 +02:00
full_text = " "
for online_player in online_players :
s = " :green_circle: ** %s ** connecté sur %s " % ( online_player [ " data " ] [ 0 ] [ " username " ] , online_player [ " data " ] [ 0 ] [ " meta " ] [ " location " ] [ " server " ] )
full_text + = s + " \n "
2020-09-01 16:12:08 +02:00
for almost_online_player in almost_online_players :
last_join_dt_utc = datetime . strptime ( almost_online_player [ " data " ] [ 0 ] [ " meta " ] [ " lastJoin " ] , " % Y- % m- %d T % H: % M: % S. %f Z " )
last_join_dt_local = utc_to_local ( last_join_dt_utc )
2020-09-01 16:17:56 +02:00
mins = math . ceil ( ( datetime . now ( last_join_dt_local . tzinfo ) - last_join_dt_local ) . total_seconds ( ) / / 60 )
2020-09-01 16:12:08 +02:00
s = " :grey_question: ** %s ** était connecté il y a %s minutes " % ( almost_online_player [ " data " ] [ 0 ] [ " username " ] , mins )
full_text + = s + " \n "
if not online_players and not almost_online_players :
2020-09-01 01:32:12 +02:00
full_text = " Personne n ' est connecté :disappointed_relieved: \n "
2020-09-01 16:12:08 +02:00
full_text + = " \n *Dernière mise à jour: %s * \n *Les vraies informations peuvent prendre jusqu ' à 5 minutes de plus* " % datetime . now ( ) . strftime ( " %d / % m/ % Y % H: % M: % S " )
2020-09-01 01:10:39 +02:00
online_channel = self . bot . get_channel ( 750100968766701708 )
update_msg = await online_channel . fetch_message ( await self . config . guild ( guild ) . update_msg ( ) )
await update_msg . edit ( content = full_text )
2020-08-31 19:58:01 +02:00
except :
2020-08-31 20:25:45 +02:00
if await self . config . log ( ) :
traceback . print_exc ( )
2020-08-31 19:58:01 +02:00
await asyncio . sleep ( 30 )