Whenever I tried running the code below it but it just doesn't seem to work. I am really new to all of this.
import discord
from discord.ext import commands
import json
client = commands.Bot(command_prefix='')
class lvls(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener
async def on_member_join(self, member):
with open(r"C:\Users\Frank\Desktop\BOTZS\test.py", 'r') as f:
users = json.load(f)
await update_data(users, member)
with open('LvlUP.json', 'w') as f:
json.dump(users, f)
#commands.Cog.listener()
async def on_message(self, message):
if message.author.bot == False:
with open('LvlUP.json', 'r') as f:
users = json.load(f)
await update_data(users, message.author)
await add_experience(users, message.author, 5)
await level_up(users, message.author, message)
with open('LvlUP.json', 'w') as f:
json.dump(users, f)
async def update_data(self, users, user):
if not f'{user.id}' in users:
users[f'{user.id}'] = {}
users[f'{user.id}']['experience'] = 0
users[f'{user.id}']['level'] = 1
async def add_experience(self, users, user, exp):
users[f'{user.id}']['experience'] += exp
async def level_up(self, users, user, message):
experience = users[f'{user.id}']['experience']
lvl_start = users[f'{user.id}']['level']
lvl_end = int(experience ** (1 / 4))
if lvl_start < lvl_end:
embed = discord.Embed(title="**LEVEL UP!**",
description=f'{user.mention} has leveled up to level {lvl_end}! :fire: 'f'\n Soundwave Superior,{user.mention} Inferior ',
color=discord.Color.dark_red())
embed.set_thumbnail(url=user.avatar_url)
users[f'{user.id}']['level'] = lvl_end
await message.channel.send(embed=embed)
def setup(client):
client.add_cog(lvls(client))
You need to add () for commands.Cog.listener:
# Your code
#commands.Cog.listener()
async def on_member_join(self, member):
# Your code
You need to setup client in the end of the file:
# Your code
setup(client)
And you need to run client after setup:
# Your code
setup(client)
client.run('YOUR_TOKEN') # Set your token for the bot
Full code if you don't understand my comments:
import discord
from discord.ext import commands
import json
client = commands.Bot(command_prefix='')
class lvls(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener()
async def on_member_join(self, member):
with open(r"C:\Users\Frank\Desktop\BOTZS\test.py", 'r') as f:
users = json.load(f)
await update_data(users, member)
with open('LvlUP.json', 'w') as f:
json.dump(users, f)
#commands.Cog.listener()
async def on_message(self, message):
if message.author.bot == False:
with open('LvlUP.json', 'r') as f:
users = json.load(f)
await update_data(users, message.author)
await add_experience(users, message.author, 5)
await level_up(users, message.author, message)
with open('LvlUP.json', 'w') as f:
json.dump(users, f)
async def update_data(self, users, user):
if not f'{user.id}' in users:
users[f'{user.id}'] = {}
users[f'{user.id}']['experience'] = 0
users[f'{user.id}']['level'] = 1
async def add_experience(self, users, user, exp):
users[f'{user.id}']['experience'] += exp
async def level_up(self, users, user, message):
experience = users[f'{user.id}']['experience']
lvl_start = users[f'{user.id}']['level']
lvl_end = int(experience ** (1 / 4))
if lvl_start < lvl_end:
embed = discord.Embed(title="**LEVEL UP!**",
description=f'{user.mention} has leveled up to level {lvl_end}! :fire: 'f'\n Soundwave Superior,{user.mention} Inferior ',
color=discord.Color.dark_red())
embed.set_thumbnail(url=user.avatar_url)
users[f'{user.id}']['level'] = lvl_end
await message.channel.send(embed=embed)
def setup(client):
client.add_cog(lvls(client))
setup(client)
client.run('YOUR_TOKEN')
I hope it's help you.
UPD: Try to add self. for your functions:
# on_member_join
await self.update_data(users, member)
# on_message
await self.update_data(users, message.author)
await self.add_experience(users, message.author, 5)
await self.level_up(users, message.author, message)
Related
class DetectClient(object):
def __init__(self, url):
self.url = url
self.ws = None
self.connect()
PeriodicCallback(self.heartbeat, 3000).start()
IOLoop.instance().start()
#gen.coroutine
def connect(self):
try:
self.ws = yield websocket_connect(self.url)
except Exception as e:
print("connection error, %s" % e)
else:
print("detect connected.")
self.run()
it seems only one client instance can be started by some reason.
like this, how to start two instances of this client in the main function?
if __name__ == "__main__":
DetectClient('ws.//1231231')
DetectClient('ws.//1231231')
Don't start IOLoop in every client. You only have to start the IOLoop once globally.
For running multiple coroutines simultaneously, you can use gen.multi:
Here's a modified code example (I've not tested it):
from tornado import gen, ioloop
class DetectClient(object):
def __init__(self, url):
self.url = url
self.ws = None
#gen.coroutine
def connect(self):
try:
self.ws = yield websocket_connect(self.url)
except Exception as e:
print("connection error, %s" % e)
else:
print("detect connected.")
self.run()
PeriodicCallback(self.heartbeat, 3000).start()
#gen.coroutine
def main():
waiter = gen.WaitIterator(
DetectClient('ws.//1231231').connect(),
DetectClient('ws.//1231231').connect()
)
while not waiter.done():
try:
yield waiter.next()
except Exception as e:
print(e)
continue
if __name__ == '__main__':
loop = ioloop.IOLoop.current()
loop.run_sync(main)
The title pretty much explains it self but I'll explain it again.
So basically when I have 2 #client.event or 1 #client.command and 1 #client.event line in the code, the whole thing breaks except for the last block of code.
Like in my code here, the first #client.event works fine. The second one doesn't, but the third one does, now if I switch the second one and the third ones place then the second ones works but the third doesn't.
import discord
from discord.ext.commands import Bot
from discord.ext import commands
import asyncio
import time
import random
from discord import Game
Client = discord.client
client = commands.Bot(command_prefix = " ")
Clientdiscord = discord.Client()
#client.event
async def on_ready():
print('{0.user}'.format(client))
print('Is Online')
#client.command
async def cmds(ctx):
await ctx.send('Prefix: v!')
await client.process_commands(ctx)
#client.event
async def on_message(message):
if message.content == 'v!coin':
variable = [
'flip',
'stay',
]
await message.channel.send((random.choice)(variable))
await client.process_commands(message)
client.run("TOKEN")
If you're using the commands framework, you should add all your commands using the #client.commands decorator instead of having logic in your on_message event handler.
If you need to handle on_message events for another reason (examokeL autoresponse to non commands), you need to call await client.process_commands(message) at the end of your on_message event handler function. It should be outside any if statements but still inside the function. Only call process_commands once in your on_message, and never call it inside your commands unless you know exactly what you are doing. Your on_message function should look something like this:
#client.event
async def on_message(message):
# Do whatever here, but don't handle commands
# If you return early, any commands in the message will be skipped
await client.process_commands(message)
So instead of this:
#client.command
async def cmds(ctx):
await ctx.send('Prefix: v!')
await client.process_commands(ctx)
#client.event
async def on_message(message):
if message.content == 'v!coin':
variable = [
'flip',
'stay',
]
await message.channel.send((random.choice)(variable))
await client.process_commands(message)
You should have something like this:
#client.command()
async def cmds(ctx):
await ctx.send('Prefix: v!')
# Send a list of commands here or do whatever this command is supposed to do
# Don't call client.process_commands here
#client.command()
async def coin(ctx):
# Coinflip logic here
# I've added the original logic you had in your question
variable = [
'flip',
'stay',
]
await ctx.send((random.choice)(variable))
# no #client.event or def on_message unless you need to handle raw messages
Also, you don't need these lines of code:
Client = discord.client
client = commands.Bot(command_prefix = " ")
Clientdiscord = discord.Client()
You can just use this:
client = commands.Bot(command_prefix = "v!")
If you are using commands.Bot already, you don't need another discord.Client.
Instead of placing await client.process_commands(message) within your if statement, place it outside of it. Please review the revised code below.
#client.event
async def on_message(message):
if message.content == 'v!coin':
variable = [
'flip',
'stay',
]
await message.channel.send((random.choice)(variable))
await client.process_commands(message)
Please note that you do not need to include await client.process_commands(message) in a command, only in your on_message event.
I have some code for a cog that looks something like this:
class Example(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.counter = 0
#commands.Cog.listener()
async def on_message(self, message):
print("Listener triggered")
self.counter += 1
#commands.group()
async def first(self, ctx):
if ctx.invoked_subcommand is None:
await ctx.send("Invalid subcommand")
#first.command()
async def second(self, ctx):
print("Command triggered")
await ctx.send(f"Current counter: {self.counter}")
When I run this code and send a message to my bot, second gets called before on_message. I have some code in second that expects on_message to be executed first, but I can't figure out a good way to make this happen. Suggestions?
check wait_for event.
and I think you are trying to make a bot count the number of valid uses of command. To do this, try:
def check(message):
#here put ur condition for message is a valide command
await client.wait_for('message', check=check)
I have the following code:
self.current_task = self.bot.wait_for('message', check=check, timeout=10 * 60)
response = await self.current_task
However I want the bot.wait_for to cancel if a condition becomes true in another function within the same class. I've tried doing self.current_task.close(), however it still waits for a response/timeout before returning a nonetype.
You can have a variable which evaluates if the condition is met, in the check func simply check if it's met and raise an error and catch it in a try/except block
def check(m):
if self.is_condition_met: # Change the variable accordingly
raise # Whatever error you want
return # normal check
An example would be
class SomeCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.is_condition_met = False
#commands.command()
async def met(self, ctx):
self.is_condition_met = True
#commands.command()
async def foo(self, ctx):
await ctx.send("Please send a message")
def check(m):
if self.is_condition_met:
raise RuntimeError("condition is met")
return ctx.author == m.author
try:
message = await bot.wait_for("message", check=check, timeout=20.0)
except RuntimeError:
await ctx.send("Condition was met")
except asyncio.TimeoutError:
await ctx.send("Time is over")
If you invoke the foo command first, and then the met command the wait should be cancelled as soon as someone sends a message
I'm making an Administration cog for my discord bot and my code wouldn't identify 'ctx'. PyCharm suggested to replace 'ctx' with 'self' and I have no idea what 'self' does. And from what PyCharm is saying, There are millions of other stuff which I have to write down what it is. PyCharm couldn't identify guild, send, author and channel and it also says that return ctx.author.guild_permissions.manage_messages is an unreachable code. As a note if this seems to be a really stupid question, I am a beginner who started 2 weeks ago.
As for the code:
class Administration(commands.Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_ready(self):
print("Admin cog ready")
async def cog_check(self, ctx):
admin = get(ctx.guild.roles, name="Admin")
return admin in ctx.author.roles
return ctx.author.guild_permissions.manage_messages
#commands.command(aliases=["purge"])
async def clear(ctx, amount=3):
"""Clears 3 messages"""
await ctx.channel.purge(limit=amount)
#commands.command(pass_context=True)
async def giverole(ctx, user: discord.Member, role: discord.Role):
"""Gives a role to a user"""
await user.add_roles(role)
await ctx.send(f"hey {ctx.author.name}, {user.name} has been giving a role called: {role.name}")
#commands.command(aliases=['make_role'])
#commands.has_permissions(manage_roles=True)
async def create_role(ctx, *, name):
"""Creates a role"""
guild = ctx.guild
await guild.create_role(name=name)
await ctx.send(f'Role `{name}` has been created')
#commands.command(name="slap", aliases=["warn"])
async def slap(ctx, members: commands.Greedy[discord.Member], *, reason='no reason'):
"""Warns someone"""
slapped = ", ".join(x.name for x in members)
await ctx.send('{} just got slapped for {}'.format(slapped, reason))
def setup(client):
client.add_cog(Administration(client))
In classes, (unless it's a staticmethod or classmethod) you always pass self as the first argument.
#commands.command(aliases=["purge"])
async def clear(self, ctx, amount=3): # Note how I put `self` as the first arg, do the same in all commands in the cog
"""Clears 3 messages"""
await ctx.channel.purge(limit=amount)
Also, this will never work
async def cog_check(self, ctx):
admin = get(ctx.guild.roles, name="Admin")
return admin in ctx.author.roles
return ctx.author.guild_permissions.manage_messages
The function will end no matter what when it reaches the first return, you can simply use the AND or OR logical operator if you want to also evaluate the second return statement
async def cog_check(self, ctx):
admin = get(ctx.guild.roles, name="Admin")
return admin in ctx.author.roles and/or ctx.author.guild_permissions.manage_messages