diff --git a/src/main.lua b/src/main.lua index ba2209d..e80d873 100644 --- a/src/main.lua +++ b/src/main.lua @@ -1,80 +1,45 @@ -local discordia = require('discordia') -local dcmd = require('discordia-slash') -local token = require('./modules/token.lua') -local commands=require('./modules/commands.lua') -local prefix = ',' -local client = discordia.Client() -client:useSlashCommands() -_G.dcmd=dcmd -_G.client = client -_G.locked = false +local Discordia = require('discordia') +local DiscordiaSlash = require('discordia-slash') +local Token = require('./Modules/Token.lua') +local CommandCollector = require('./Modules/CommandCollector.lua') +local Client = Discordia.Client():useApplicationCommands() +Discordia.extensions() -discordia.extensions() +local MessageCommandCollector = CommandCollector.new('Message'):Collect() +local SlashCommandCollector = CommandCollector.new('Slash'):Collect() +local UserCommandCollector = CommandCollector.new('User'):Collect() -client:on('ready',function() - commands:INIT() - local f=io.open('restart.txt','r+'):read() - local t=tostring(f):split(',') - if #t==3 then - client:getGuild(t[1]):getChannel(t[2]):send( - { - content='bot ready', - reference={ - message=client:getChannel(t[2]):getMessage(t[3]), - mention=true - } - } - ) - io.open('restart.txt','w+'):write(''):close() - else - print('restart.txt is empty or something so probably a first start') - end +Client:on('ready', function() + -- local GlobalCommands = Client:getGlobalApplicationCommands() + + -- for CommandId in pairs(GlobalCommands) do + -- Client:deleteGlobalApplicationCommand(CommandId) + -- end + + MessageCommandCollector:Publish(Client) + SlashCommandCollector:Publish(Client) + UserCommandCollector:Publish(Client) end) -function parseMentions(message) - local content=message.content - local usersMentioned={} - if #message.mentionedUsers>0 then - for user in message.mentionedUsers:iter() do - usersMentioned[user.id]=user - end - end - local msgSplit=content:split(' ') - for i,v in next, msgSplit do - if v:match('<@![0-9]+>') then - local id=v:match('<@!([0-9]+)>') - if usersMentioned[id] then - msgSplit[i]=usersMentioned[id].mentionString - end - end - end - return table.concat(msgSplit,' ') or '',usersMentioned -end -client:on('messageCreate', function(message) - if message.author.bot then return end - local content,mentions=parseMentions(message) - if content:sub(1,#prefix)==prefix and content~=prefix then - local cmd=content:sub(#prefix+1,#content) - local args=cmd:split(' ') - local cmdName=args[1] - table.remove(args,1) - local command=commands.command_list[cmdName] - if command~=nil then - if message.guild~=nil then - local tb - local s,e=xpcall(function() - command.exec({message=message,args=args,mentions=mentions,t={client,discordia,token}}) - end,function(err) - tb = debug.traceback() - return err - end) - if not s then - message:reply('tripped : '..e:split('/')[#e:split('/')]) - print(e,tb) - end - end - end +Client:on('slashCommand', function(Interaction, Command, Args) + local SlashCommand = SlashCommandCollector:Get(Command.name) + if SlashCommand then + SlashCommand.Callback(Interaction, Command, Args) end end) -client:run('Bot '..token) \ No newline at end of file +Client:on('messageCommand', function(Interaction, Command, Message) + local MessageCommand = MessageCommandCollector:Get(Command.name) + if MessageCommand then + MessageCommand.Callback(Interaction, Command, Message) + end +end) + +Client:on('userCommand', function(Interaction, Command, Member) + local UserCommand = UserCommandCollector:Get(Command.name) + if UserCommand then + UserCommand.Callback(Interaction, Command, Member) + end +end) + +Client:run('Bot '..Token) \ No newline at end of file diff --git a/src/modules/commands.lua b/src/modules/commands.lua deleted file mode 100644 index a802bf3..0000000 --- a/src/modules/commands.lua +++ /dev/null @@ -1,34 +0,0 @@ -local discordia=require('discordia') -discordia.extensions() -local commands={command_list={}} -setmetatable(commands.command_list,{__index=function(self,index) - for i,v in pairs(self) do - for i2,v2 in pairs(v.alias) do - if v2==index then - return self[i] - end - end - end - return nil -end}) -function commands:Add(name,alias,desc,exec) - name=type(name)=='string' and name or ('Command'..#self.command_list) - self.command_list[name]={ - name=name, - alias=type(alias)=='table'and alias or {'None'}, - desc=type(desc)=='string'and desc or ('No description provided'), - exec=type(exec)=='function'and exec or function(message) - return message:reply('No command assigned') - end - } - return self.command_list[name] -end -function commands:Get(name) - return self.command_list[name] -end -function commands:INIT() - for file in io.popen([[dir "./src/modules/commands" /b]]):lines() do require('./commands/'..file) end - print('commands done') -end - -return commands \ No newline at end of file diff --git a/src/modules/commands/cmds.lua b/src/modules/commands/cmds.lua deleted file mode 100644 index 7a0f5e8..0000000 --- a/src/modules/commands/cmds.lua +++ /dev/null @@ -1,14 +0,0 @@ -local discordia=require('discordia') -local commands=require('./../commands.lua') -discordia.extensions() -commands:Add('cmds',{'commands','cmd','help'},'Returns a list of all commands',function(t) - local final='```\n' - for i,v in pairs(commands.command_list) do - local name=v.name - local alias=table.concat(v.alias,', ') or 'None' - local desc=v.desc - final=final..'Name: '..name..'\nDescription: '..desc..'\n'..'Aliases: '..alias..'\n\n' - end - final=final..'```' - t.message:reply(final) -end) \ No newline at end of file diff --git a/src/modules/commands/download.lua b/src/modules/commands/download.lua deleted file mode 100644 index 34c2ac1..0000000 --- a/src/modules/commands/download.lua +++ /dev/null @@ -1,78 +0,0 @@ -local discordia=require('discordia') -local commands=require('./../commands.lua') -discordia.extensions() - -function split(s,d) - local t,c,i={},'',0 - for k in s:gmatch('.') do - i=i+1 - if k==d and string.sub(s,i+1)~='' then - t[#t+1]=c - c='' - goto continue - end - c=c..k - ::continue:: - end - t[#t+1]=c - return t -end - -function clearTmp() - for file in io.popen([[dir "./tmp" /b]]):lines() do - if file then - os.remove('./tmp/'..file) - end - end -end -function isTmpEmpty() - local dir = io.popen([[dir "./tmp" /b]]):read() - return dir==nil, dir, dir~=nil and split(dir,'\n') or {} -end - -commands:Add('sc',{},'download soundcloud song (usage: "sc [link]")', function(t) - local args = t.args - local message = t.message - if args[1] then - if args[1]:match('https://soundcloud.com/[%w-_]+/[%w-_]+') then - clearTmp() - local link=args[1]:match('https://soundcloud.com/[%w-_]+/[%w-_]+') - message:reply('Attempting to download song from <'..link..'>') - local filepath = '' - local s=io.popen('ytdl.exe -o "./tmp/%(uploader_id)s-%(display_id)s.%(ext)s" '..link) - local songName - repeat - local str = s:read() - if str then - local tag = str:match('^%[(.+)%]') - if tag=='soundcloud' then - local song = str:match('^%[soundcloud%] (.+):') - if song:match('%d+')~=song then - songName = song:match('.+/(.+)') - end - end - end - until s:read()==nil - s:close() - if type(songName)=='string' and songName~='' then - message:reply('found song: '..songName) - local empty,file = isTmpEmpty() - if not empty then - message:reply({file='./tmp/'..file}) - os.remove('./tmp/'..file) - end - end - else - message:reply('Invalid URL') - end - else - message:reply('No URL provided') - end -end) - --- commands:Add('ct',{},'',function() --- clearTmp() --- end) --- commands:Add('ft',{},'',function() --- filterTmp() --- end) \ No newline at end of file diff --git a/src/modules/commands/map.lua b/src/modules/commands/map.lua deleted file mode 100644 index 9552d23..0000000 --- a/src/modules/commands/map.lua +++ /dev/null @@ -1,28 +0,0 @@ -local discordia=require('discordia') -local API=require('./../strafes_net.lua') -local commands=require('./../commands.lua') -discordia.extensions() - -commands:Add('map',{},'get map info', function(t) - local args = t.args - local message = t.message - - local game = API.GAMES[args[1]] - local map - if not game then - local str = table.concat(args,' ') - map = API.MAPS[1][str] or API.MAPS[2][str] - else - map = API.MAPS[game][table.concat(args,' ',2)] - end - - if not map then return message:reply('```No map found```') end - local formatted_message = '```'.. - 'Map: '..map.DisplayName..' ('..API.GAMES[map.Game]..')\n'.. - 'ID: '..map.ID..'\n'.. - 'Creator: '..map.Creator..'\n'.. - 'PlayCount: '..map.PlayCount..'\n'.. - 'Published: '..os.date('%A, %B %d %Y @ %I:%M (%p)',map.Date).. - '```' - return message:reply(formatted_message) -end) \ No newline at end of file diff --git a/src/modules/commands/maps_init.lua b/src/modules/commands/maps_init.lua deleted file mode 100644 index e9ec84b..0000000 --- a/src/modules/commands/maps_init.lua +++ /dev/null @@ -1,71 +0,0 @@ --- local discordia=require('discordia') --- local API=require('./../strafes_net.lua') --- discordia.extensions() --- API.MAPS={} - --- local function insert(t, value) --- local start, ending, mid, state = 1, #t, 1, 0 - --- while start <= ending do --- mid = math.floor((start + ending) / 2) --- if #value.DisplayName < #t[mid].DisplayName then --- ending, state = mid - 1, 0 --- else --- start, state = mid + 1, 1 --- end --- end - --- table.insert(t, mid + state, value) --- end - --- for _, game in next, API.GAMES do --- if type(tonumber(game)) == 'number' then --- local count = 0 -- add into the maps table afterwards --- local maps = {} --- local res, headers = API:GetMaps(game) --- local pages = tonumber(headers['Pagination-Count']) - --- count = count + #res - --- for _, v in next, res do --- insert(maps, v) --- end - --- if pages > 1 then --- for i = 2, pages do --- res, headers = API:GetMaps(game, i) --- count = count + #res - --- for _, j in next, res do --- insert(maps, j) --- end --- end --- end - --- setmetatable(maps, {__index = function(self, k) --- if k=='count' then return self.count end - --- -- Just to make sure it goes in the right order --- if type(k)=='string' then --- for i = 1, self.count do --- local v = self[i] --- if type(v) == 'table' and v.DisplayName:lower():find(tostring(k:gsub('%%', '%%%%'):gsub('^%^', '%%^'):gsub('%$$', '%%$'):gsub('%(', '%%('):gsub('%)', '%%)'):gsub('%.', '%%.'):gsub('%[', '%%['):gsub('%]', '%%]'):gsub('%*', '%%*'):gsub('%+', '%%+'):gsub('%-', '%%-'):gsub('%?', '%%?')):lower()) then --- return v --- end --- end --- elseif type(k)=='number' then --- for i = 1, self.count do --- local v = self[i] - --- if type(v) == 'table' and v.ID==k then --- return v --- end --- end --- end --- end}) - --- maps.count = count --- API.MAPS[game] = maps --- print('map init done for game:', API.GAMES[game], 'count:', API.MAPS[game].count) --- end --- end \ No newline at end of file diff --git a/src/modules/commands/minecraft.lua b/src/modules/commands/minecraft.lua deleted file mode 100644 index 0f0d1a4..0000000 --- a/src/modules/commands/minecraft.lua +++ /dev/null @@ -1,114 +0,0 @@ -local discordia=require('discordia') -local json=require('json') -local http_request=require('./../http.lua') -local Commands=require('./../commands.lua') -discordia.extensions() - -local COLOURS={ - GREEN=0x00ff00, - RED=0xff0000 -} - ---initialize minecraft ip data -local MinecraftDataFile=io.open('minecraft_data.json','r') -if not MinecraftDataFile or (MinecraftDataFile and MinecraftDataFile:read('*a')=='') then - print('no such file exists! so make it') - io.open('minecraft_data.json','w+'):write(json.encode({})):close() -end -if MinecraftDataFile then - MinecraftDataFile:close() -end - -Commands:Add('setip',{},'set ip for status',function(CommandData) - local CommandArgs=CommandData.args - local CommandMessage=CommandData.message - local ServerIPStr=CommandArgs[1] - if not ServerIPStr then - return CommandMessage:reply('No IP provided') - end - - local ServerIP=ServerIPStr:match("(%d+%.%d+%.%d+%.%d+)") or ServerIPStr:match("(%w*%.?%w+%.%w+)") - if not ServerIP then - return CommandMessage:reply('Invalid server IP') - end - local ServerPort=ServerIPStr:match(ServerIP..':(%d+)') or 25565 - - local GuildId=CommandMessage.guild.id - if not GuildId then - return CommandMessage:reply('You cannot use this command outside of a Discord server') - end - - local GuildMinecraftData={IP=ServerIP,PORT=ServerPort} - - local GlobalMinecraftData=json.decode(io.open('minecraft_data.json','r'):read('*a')) - GlobalMinecraftData[GuildId]=GuildMinecraftData - io.open('minecraft_data.json','w+'):write(json.encode(GlobalMinecraftData)):close() - - return CommandMessage:reply({ - content='Successfully added `'..ServerIP..':'..ServerPort..'` for ServerId='..GuildId, - reference={ - message=CommandMessage, - mention=true - } - }) -end) - -Commands:Add('status',{},'get status for minecraft server',function(CommandData) - local CommandMessage=CommandData.message - - local GuildId=CommandMessage.guild.id - if not GuildId then - return CommandMessage:reply('You cannot use this command outside of a Discord server') - end - - local GlobalMinecraftData=json.decode(io.open('minecraft_data.json','r'):read('*a')) - if not GlobalMinecraftData then - return CommandMessage:reply('Could not read server data') - end - - local ServerMinecraftData=GlobalMinecraftData[GuildId] - if not ServerMinecraftData then - return CommandMessage:reply('There is no data for this Discord server') - end - - local ServerIPStr=ServerMinecraftData.IP..':'..ServerMinecraftData.PORT - local Response,Headers=http_request('GET',('https://api.mcsrvstat.us/3/%s'):format(ServerIPStr)) - - local IsOnline=Response.online - local EmbedData - if IsOnline then - local MaxPlayers=Response.players.max - local OnlinePlayers=Response.players.online - local AnonymousPlayers=OnlinePlayers - local Players={} - if OnlinePlayers>0 then - for PlayerIndex,PlayerData in next,Response.players.list do - table.insert(Players,PlayerData.name) - AnonymousPlayers=AnonymousPlayers-1 - end - else - table.insert(Players,'No players online') - end - if AnonymousPlayers>0 then - for AnonymousPlayerIndex=1,AnonymousPlayers do - table.insert(Players,'Anonymous Player') - end - end - EmbedData={ - title='Server Status for '..ServerIPStr, - description=Response.motd.clean[1]..' ('..Response.version..')', - fields={ - {name='Players',value=OnlinePlayers..'/'..MaxPlayers,inline=true}, - {name='List of players',value=table.concat(Players,'\n'),inline=true} - }, - color=COLOURS.GREEN - } - else - EmbedData={ - title='Server Status for '..ServerIPStr, - description='Server is offline', - color=COLOURS.RED - } - end - return CommandMessage:reply({embed=EmbedData}) -end) \ No newline at end of file diff --git a/src/modules/commands/pb.lua b/src/modules/commands/pb.lua deleted file mode 100644 index bb306f7..0000000 --- a/src/modules/commands/pb.lua +++ /dev/null @@ -1,60 +0,0 @@ -local discordia=require('discordia') -local API=require('./../strafes_net.lua') -local commands=require('./../commands.lua') -local pad = API.Pad - -discordia.extensions() - --- args: user, game, style, map -commands:Add('pb', {}, 'get placement on map', function(t) - local args = t.args - local message = t.message - - if #args < 4 then return message:reply('invalid arguments') end - - local user = API:GetUserFromAny(args[1],message) - local sn_info = API:GetUser(user.id) - local game = API.GAMES[args[2]] - local style = API.STYLES[args[3]] - local map = API.MAPS[game][table.concat(args,' ',4)] - - -- i love checks - if not game then return message:reply('invalid game') end - if not style then return message:reply('invalid style') end - if not map then return message:reply('invalid map') end - if not sn_info.ID then return message:reply('```No data with StrafesNET is associated with that user.```') end - if sn_info.State==2 then return message:reply('```This user is currently blacklisted```') end - - local time = API:GetUserTimes(user.id, map.ID, style, game)[1] - - if not time then return message:reply('```No time was found.```') end - - local rank = API:GetTimeRank(time.ID).Rank - local count = tonumber(API:GetMapCompletionCount(time.Map, style)) - - if not rank or not count then - rank = 1 - count = 1 - end - - local time_formatted = API.FormatTime(time.Time) - local date = os.date("%x", time.Date) - local placement = rank .. '/' .. count - local points = API.CalculatePoint(rank, count) - - local t_n, d_n, p_n= #time_formatted, 8, math.max(#placement, 10) - - local first_line = 'PB Time for map: '..map.DisplayName..' ('..API.GAMES[game]..', '..API.STYLES_LIST[style]..')' - - local second_line = pad('Time:', t_n + 1) .. '| ' - .. pad('Date:', d_n + 1) .. '| ' - .. pad('Placement:', p_n + 1) .. '| ' - .. 'Points:' - - local third_line = pad(time_formatted, t_n + 1) .. '| ' - .. pad(date, d_n + 1) .. '| ' - .. pad(placement, p_n + 1) .. '| ' - .. tostring(points) - - return message:reply('```' .. first_line .. '\n' .. second_line .. '\n' .. third_line .. '```') -end) diff --git a/src/modules/commands/rank.lua b/src/modules/commands/rank.lua deleted file mode 100644 index e13e930..0000000 --- a/src/modules/commands/rank.lua +++ /dev/null @@ -1,40 +0,0 @@ -local discordia=require('discordia') -local API=require('./../strafes_net.lua') -local commands=require('./../commands.lua') -function dump(a,b,c,d)b=b or 50;d=d or("DUMP START "..tostring(a))c=c or 0;for e,f in next,a do local g;if type(f)=="string"then g="\""..f.."\""else g=tostring(f)end;d=d.."\nD "..string.rep(" ",c*2)..tostring(e)..": "..g;if type(f)=="table"then if c>=b then d=d.." [ ... ]"else d=dump(f,b,c+1,d)end end end;return d end -discordia.extensions() -commands:Add('rank',{},'rank