diff --git a/src/main/java/net/tylermurphy/ken/Ken.java b/src/main/java/net/tylermurphy/ken/Ken.java index b03ea3d..b9b6cba 100644 --- a/src/main/java/net/tylermurphy/ken/Ken.java +++ b/src/main/java/net/tylermurphy/ken/Ken.java @@ -8,17 +8,19 @@ import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.requests.GatewayIntent; import net.dv8tion.jda.api.utils.MemberCachePolicy; import net.tylermurphy.ken.command.Responder; import net.tylermurphy.ken.database.Database; import net.tylermurphy.ken.music.PlayerManager; +import net.tylermurphy.ken.util.ImageFetcher; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.awt.Color; +import java.awt.*; import java.io.File; import java.io.InputStream; @@ -32,12 +34,14 @@ public class Ken { private final YouTube youTube; private final Responder responder; private final Database database; + private final ImageFetcher imageFetcher; private Ken(){ Ken.instance = this; this.config = Config.create("config.yml"); this.log = LoggerFactory.getLogger(Ken.class); this.database = new Database(); + this.imageFetcher = new ImageFetcher(); try { api = JDABuilder.createDefault(config.getString("botToken")) .setActivity(Activity.playing("@Ken | /help")) @@ -91,6 +95,8 @@ public class Ken { public Database getDatabase() { return database; } + public ImageFetcher getImageFetcher() { return imageFetcher; } + public Role getRoleById(long id) { return api.getRoleById(id); } public EmbedBuilder getDefaultEmbed() { diff --git a/src/main/java/net/tylermurphy/ken/api/Request.java b/src/main/java/net/tylermurphy/ken/api/Request.java index 8daa899..4c7ba7d 100644 --- a/src/main/java/net/tylermurphy/ken/api/Request.java +++ b/src/main/java/net/tylermurphy/ken/api/Request.java @@ -1,5 +1,6 @@ package net.tylermurphy.ken.api; +import javax.imageio.ImageIO; import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; @@ -77,4 +78,16 @@ public abstract class Request { return null; } + public static HttpURLConnection getConnection(String link){ + try { + final URL url = new URL(link); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0"); + return connection; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + } diff --git a/src/main/java/net/tylermurphy/ken/command/Responder.java b/src/main/java/net/tylermurphy/ken/command/Responder.java index 3dfc644..bd4e0e1 100644 --- a/src/main/java/net/tylermurphy/ken/command/Responder.java +++ b/src/main/java/net/tylermurphy/ken/command/Responder.java @@ -20,15 +20,18 @@ import net.dv8tion.jda.api.interactions.components.selections.SelectMenu; import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction; import net.dv8tion.jda.api.utils.FileUpload; import net.tylermurphy.ken.Ken; -import net.tylermurphy.ken.command.fun.Claim; -import net.tylermurphy.ken.command.fun.Eject; -import net.tylermurphy.ken.command.fun.Money; -import net.tylermurphy.ken.command.fun.Slots; +import net.tylermurphy.ken.command.game.Claim; +import net.tylermurphy.ken.command.game.Money; +import net.tylermurphy.ken.command.game.Roulette; +import net.tylermurphy.ken.command.game.Slots; +import net.tylermurphy.ken.command.fun.*; import net.tylermurphy.ken.command.game.*; import net.tylermurphy.ken.command.main.*; +import net.tylermurphy.ken.command.moderation.*; import net.tylermurphy.ken.command.music.*; import net.tylermurphy.ken.command.music.Queue; import net.tylermurphy.ken.command.nsfw.*; +import net.tylermurphy.ken.command.selfrole.*; import java.awt.*; import java.lang.reflect.Method; @@ -79,6 +82,20 @@ public class Responder extends ListenerAdapter { new Money(), new Slots(), new Claim(), + new Headpat(), + new Roulette(), + new GayMeme(), + new CrabRave(), + new Wank(), + new Ban(), + new TempBan(), + new Kick(), + new UnBan(), + new Mute(), + new UnMute(), + new OpenServer(), + new CloseServer(), + new History(), }; Arrays.stream(objects).forEach(register::register); } @@ -136,6 +153,7 @@ public class Responder extends ListenerAdapter { .setTitle(":x: **Error**") .setDescription(e.getCause() != null ? e.getCause().getMessage() : e.getMessage()); event.replyEmbeds(builder.build()).setEphemeral(true).queue(); + e.printStackTrace(); } } @@ -283,6 +301,7 @@ public class Responder extends ListenerAdapter { switch (option.getType()) { case STRING -> args.add(option.getAsString()); case INTEGER -> args.add(option.getAsInt()); + case NUMBER -> args.add(option.getAsDouble()); case BOOLEAN -> args.add(option.getAsBoolean()); case USER -> args.add(option.getAsMember()); case CHANNEL -> args.add(option.getAsChannel()); diff --git a/src/main/java/net/tylermurphy/ken/command/fun/CrabRave.java b/src/main/java/net/tylermurphy/ken/command/fun/CrabRave.java new file mode 100644 index 0000000..b0d3b0f --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/fun/CrabRave.java @@ -0,0 +1,74 @@ +package net.tylermurphy.ken.command.fun; + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.tylermurphy.ken.Ken; +import net.tylermurphy.ken.api.Request; +import net.tylermurphy.ken.command.Response; +import net.tylermurphy.ken.command.annotation.Command; +import net.tylermurphy.ken.command.annotation.Option; +import net.tylermurphy.ken.util.GifSequenceWriter; + +import javax.imageio.ImageIO; +import javax.imageio.stream.ImageOutputStream; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; + +public class CrabRave { + + @Command(name="crabrave", description="Crav rave a server member") + @Option(name="member", description="Server member to rave", type= OptionType.USER, required=true) + public Response execute(Member sender, List args){ + Member ejected = (Member) args.get(0); + try { + byte[] data = generateGif(ejected.getUser()); + return Response.success(ejected.getEffectiveName() +" was raved by "+sender.getEffectiveName()).setFile(data, "eject.gif"); + } catch (IOException e) { + return Response.error("Failed to generate gif"); + } + } + + private byte[] generateGif(User u) throws IOException, NullPointerException { + BufferedImage crab = Ken.getInstance().getImageFetcher().getImage("https://cdn.tylermurphy.net/ken/crab.png", true); + BufferedImage avatar = Ken.getInstance().getImageFetcher().getImage(u.getAvatarUrl(), false); + BufferedImage[] frames = new BufferedImage[26]; + for(int i = 0; i < frames.length; i++) { + frames[i] = generateFrame(i, avatar, crab); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageOutputStream ios = ImageIO.createImageOutputStream(baos); + GifSequenceWriter writer = new GifSequenceWriter(ios, frames[0].getType(), 10, true); + + for (BufferedImage img : frames) { + writer.writeToSequence(img); + } + + writer.close(); + ios.close(); + return baos.toByteArray(); + + } + + private BufferedImage generateFrame(int frame, BufferedImage avatar, BufferedImage crab) { + int w = 500; + int h = 275; + BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + + Graphics2D g2d = img.createGraphics(); + + g2d.drawImage(crab, 500*-frame,0, 13000, 275, null); + g2d.drawImage(avatar,60,175, 75, 75, null); + g2d.setFont(new Font("Dialog", Font.BOLD, 50)); + g2d.setColor(Color.black); + g2d.drawString("IS GONE", 180, 225); + g2d.dispose(); + + return img; + } + +} diff --git a/src/main/java/net/tylermurphy/ken/command/fun/Eject.java b/src/main/java/net/tylermurphy/ken/command/fun/Eject.java index fda1e18..29900be 100644 --- a/src/main/java/net/tylermurphy/ken/command/fun/Eject.java +++ b/src/main/java/net/tylermurphy/ken/command/fun/Eject.java @@ -1,12 +1,21 @@ package net.tylermurphy.ken.command.fun; import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.tylermurphy.ken.Ken; +import net.tylermurphy.ken.api.Request; import net.tylermurphy.ken.command.annotation.Command; import net.tylermurphy.ken.command.annotation.Option; import net.tylermurphy.ken.command.Response; -import net.tylermurphy.ken.image.GifFactory; +import net.tylermurphy.ken.util.GifSequenceWriter; +import javax.imageio.ImageIO; +import javax.imageio.stream.ImageOutputStream; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.List; public class Eject { @@ -15,8 +24,79 @@ public class Eject { @Option(name="member", description="Server member to eject", type=OptionType.USER, required=true) public Response execute(Member sender, List args){ Member ejected = (Member) args.get(0); - byte[] data = GifFactory.generateEjectGif(ejected.getUser()); - return Response.success(ejected.getEffectiveName() +" was ejected by "+sender.getEffectiveName()).setFile(data, "eject.gif"); + try { + byte[] data = generateGif(ejected.getUser()); + return Response.success(ejected.getEffectiveName() +" was ejected by "+sender.getEffectiveName()).setFile(data, "eject.gif"); + } catch (IOException e) { + return Response.error("Failed to generate gif"); + } + } + + private byte[] generateGif(User u) throws IOException { + String message; + if (Math.random() > .5) + message = u.getName() + " was An Impostor"; + else + message = u.getName() + " was not An Impostor"; + + BufferedImage space = Ken.getInstance().getImageFetcher().getImage("https://cdn.tylermurphy.net/ken/space.jpg", true); + BufferedImage avatar = Ken.getInstance().getImageFetcher().getImage(u.getAvatarUrl(), false); + + BufferedImage[] frames = new BufferedImage[30]; + for (int i = 0; i < frames.length; i++) { + frames[i] = generateFrame(message, Math.min(i, 23), 24, space, avatar); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageOutputStream ios = ImageIO.createImageOutputStream(baos); + GifSequenceWriter writer = new GifSequenceWriter(ios, frames[0].getType(), 8, true); + + for (BufferedImage img : frames) { + writer.writeToSequence(img); + } + + writer.close(); + ios.close(); + return baos.toByteArray(); + } + + public BufferedImage generateFrame(String message, int frame, float totalFrames, BufferedImage space1, BufferedImage avatar) { + int w = 600; + int h = 400; + BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + + Graphics2D g2d = img.createGraphics(); + g2d.drawImage(space1, (int) (-100+100/totalFrames*frame), 0, (int)(w*1.5), (int)(h*1.5), null); + + BufferedImage ravater = rotate(avatar, 180/24*frame); + g2d.drawImage(ravater, (w+2*avatar.getWidth()+100)/24*frame-avatar.getWidth()-50, h/2-avatar.getHeight()/2, 150, 150, null); + + if(frame > 12) { + int length = (message.length() * (frame-11)/12); + message = message.substring(0, length); + + g2d.setFont(new Font("Dialog", Font.BOLD, 25)); + FontMetrics fm = g2d.getFontMetrics(); + int x = w/2 - fm.stringWidth(message)/2; + int y = h/2; + g2d.drawString(message, x, y); + } + + g2d.dispose(); + + return img; + } + + private BufferedImage rotate(BufferedImage img, double angle) { + int w = img.getWidth()+50; + int h = img.getHeight()+50; + + BufferedImage rotated = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D graphic = rotated.createGraphics(); + graphic.rotate(Math.toRadians(angle), w/2, h/2); + graphic.drawImage(img, null, w/2-img.getWidth()/2, h/2-img.getHeight()/2); + graphic.dispose(); + return rotated; } } diff --git a/src/main/java/net/tylermurphy/ken/command/fun/GayMeme.java b/src/main/java/net/tylermurphy/ken/command/fun/GayMeme.java new file mode 100644 index 0000000..b538606 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/fun/GayMeme.java @@ -0,0 +1,82 @@ +package net.tylermurphy.ken.command.fun; + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.tylermurphy.ken.Ken; +import net.tylermurphy.ken.api.Request; +import net.tylermurphy.ken.command.Response; +import net.tylermurphy.ken.command.annotation.Command; +import net.tylermurphy.ken.command.annotation.Option; +import net.tylermurphy.ken.util.GifSequenceWriter; + +import javax.imageio.ImageIO; +import javax.imageio.stream.ImageOutputStream; +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; + +public class GayMeme { + + @Command(name="gaymeme", description="Generate a gay meme about a fellow server member") + @Option(name="member", description="Server member to make the meme about", type= OptionType.USER, required=true) + public Response execute(Member sender, List args){ + Member ejected = (Member) args.get(0); + try { + byte[] data = generateGif(ejected.getUser()); + return Response.success(sender.getEffectiveName() +" thinks "+ejected.getEffectiveName()+ " is gay!").setFile(data, "eject.gif"); + } catch (IOException e) { + return Response.error("Failed to generate gif"); + } + } + + private byte[] generateGif(User u) throws IOException, NullPointerException { + BufferedImage avatar = Ken.getInstance().getImageFetcher().getImage(u.getAvatarUrl(), false); + BufferedImage background = Ken.getInstance().getImageFetcher().getImage("https://cdn.tylermurphy.net/ken/theMoreYouKnow.png", true); + BufferedImage gay = Ken.getInstance().getImageFetcher().getImage("https://cdn.tylermurphy.net/ken/gay.png", true); + + BufferedImage[] frames = new BufferedImage[40]; + for(int i = 0; i < frames.length; i++) { + frames[i] = generateFrame(i, avatar, background, gay); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageOutputStream ios = ImageIO.createImageOutputStream(baos); + GifSequenceWriter writer = new GifSequenceWriter(ios, frames[0].getType(), 16, true); + + for (BufferedImage img : frames) { + writer.writeToSequence(img); + } + + writer.close(); + ios.close(); + return baos.toByteArray(); + + } + + private BufferedImage generateFrame(int frame, BufferedImage avatar, BufferedImage background, BufferedImage gay) { + int w = 400; + int h = 200; + BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = img.createGraphics(); + + if(frame < 25) { + g2d.drawImage(gay, 0, 0, 400, 200, null); + if (frame % 2 == 0) { + g2d.setColor(Color.black); + g2d.fillRect(0, 50, 400, 100); + } + g2d.drawImage(avatar, 150, 50, 100, 100, null); + } else { + g2d.drawImage(background, (400*3)*-Math.min(7, frame-24), 0, 9600, 200, null); + } + + g2d.dispose(); + + return img; + } + +} diff --git a/src/main/java/net/tylermurphy/ken/command/fun/Headpat.java b/src/main/java/net/tylermurphy/ken/command/fun/Headpat.java new file mode 100644 index 0000000..5a2239e --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/fun/Headpat.java @@ -0,0 +1,84 @@ +package net.tylermurphy.ken.command.fun; + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.tylermurphy.ken.Ken; +import net.tylermurphy.ken.api.Request; +import net.tylermurphy.ken.command.Response; +import net.tylermurphy.ken.command.annotation.Command; +import net.tylermurphy.ken.command.annotation.Option; +import net.tylermurphy.ken.util.GifSequenceWriter; + +import javax.imageio.ImageIO; +import javax.imageio.stream.ImageOutputStream; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; + +public class Headpat { + + @Command(name="headpat", description="Head pat a fellow server member") + @Option(name="member", description="Server member to head pat", type= OptionType.USER, required=true) + public Response execute(Member sender, List args){ + Member ejected = (Member) args.get(0); + try { + byte[] data = generateGif(ejected.getUser()); + return Response.success(sender.getEffectiveName() +" head patted "+ejected.getEffectiveName()).setFile(data, "eject.gif"); + } catch (IOException e) { + return Response.error("Failed to generate gif"); + } + } + + private byte[] generateGif(User u) throws IOException, NullPointerException { + BufferedImage hand = Ken.getInstance().getImageFetcher().getImage("https://cdn.tylermurphy.net/ken/headpat.png", true); + BufferedImage avatar = Ken.getInstance().getImageFetcher().getImage(u.getAvatarUrl(), false); + + BufferedImage[] frames = new BufferedImage[5]; + for(int i = 0; i < frames.length; i++) { + frames[i] = generateFrame(i, hand, avatar); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageOutputStream ios = ImageIO.createImageOutputStream(baos); + GifSequenceWriter writer = new GifSequenceWriter(ios, frames[0].getType(), 4, true); + + for (BufferedImage img : frames) { + writer.writeToSequence(img); + } + + writer.close(); + ios.close(); + return baos.toByteArray(); + + } + + private BufferedImage generateFrame(int frame, BufferedImage hand, BufferedImage avatar){ + int w = 400; + int h = 400; + BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + + Graphics2D g2d = img.createGraphics(); + + + if(frame == 0) + g2d.drawImage(avatar, 140, 140, 260, 260, null); + else if(frame == 1) + g2d.drawImage(avatar, 120, 160, 280, 240, null); + else if(frame == 2) + g2d.drawImage(avatar, 100, 180, 300, 220, null); + else if(frame == 3) + g2d.drawImage(avatar, 110, 160, 280, 240, null); + else if(frame == 4) + g2d.drawImage(avatar, 130, 140, 260, 260, null); + + g2d.drawImage(hand, frame*-400,0, 2000, 400, null); + + g2d.dispose(); + + return img; + } + +} diff --git a/src/main/java/net/tylermurphy/ken/command/fun/Wank.java b/src/main/java/net/tylermurphy/ken/command/fun/Wank.java new file mode 100644 index 0000000..c2cb6f1 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/fun/Wank.java @@ -0,0 +1,84 @@ +package net.tylermurphy.ken.command.fun; + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.tylermurphy.ken.Ken; +import net.tylermurphy.ken.command.Response; +import net.tylermurphy.ken.command.annotation.Command; +import net.tylermurphy.ken.command.annotation.Option; +import net.tylermurphy.ken.util.GifSequenceWriter; + +import javax.imageio.ImageIO; +import javax.imageio.stream.ImageOutputStream; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; + +public class Wank { + + @Command(name="wank", description="Wank to a fellow crew member") + @Option(name="member", description="Server member to wank", type= OptionType.USER, required=true) + public Response execute(Member sender, List args){ + Member ejected = (Member) args.get(0); + try { + byte[] data = generateGif(ejected.getUser()); + return Response.success(sender.getEffectiveName() +" wanked to "+ejected.getEffectiveName()).setFile(data, "eject.gif"); + } catch (IOException e) { + return Response.error("Failed to generate gif"); + } + } + + private byte[] generateGif(User u) throws IOException { + BufferedImage wank = Ken.getInstance().getImageFetcher().getImage("https://cdn.tylermurphy.net/ken/laptop.png", true); + BufferedImage avatar = Ken.getInstance().getImageFetcher().getImage(u.getAvatarUrl(), false); + + BufferedImage[] frames = new BufferedImage[4]; + for (int i = 0; i < frames.length; i++) { + frames[i] = generateFrame(i, rotate(avatar, -35), wank); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageOutputStream ios = ImageIO.createImageOutputStream(baos); + GifSequenceWriter writer = new GifSequenceWriter(ios, frames[0].getType(), 8, true); + + for (BufferedImage img : frames) { + writer.writeToSequence(img); + } + + writer.close(); + ios.close(); + return baos.toByteArray(); + } + + public BufferedImage generateFrame(int frame, BufferedImage avatar, BufferedImage wank) { + int w = 640; + int h = 360; + BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + + Graphics2D g2d = img.createGraphics(); + + g2d.drawImage(avatar, 100, 95, 300, 140, null); + g2d.drawImage(wank, 640*-frame,0, 2560, 360, null); + + g2d.dispose(); + + return img; + } + + private BufferedImage rotate(BufferedImage img, double angle) { + int w = img.getWidth()+50; + int h = img.getHeight()+50; + + BufferedImage rotated = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D graphic = rotated.createGraphics(); + graphic.rotate(Math.toRadians(angle), w/2, h/2); + graphic.drawImage(img, null, w/2-img.getWidth()/2, h/2-img.getHeight()/2); + graphic.dispose(); + return rotated; + } + + +} diff --git a/src/main/java/net/tylermurphy/ken/command/fun/Claim.java b/src/main/java/net/tylermurphy/ken/command/game/Claim.java similarity index 94% rename from src/main/java/net/tylermurphy/ken/command/fun/Claim.java rename to src/main/java/net/tylermurphy/ken/command/game/Claim.java index bc53b83..1016935 100644 --- a/src/main/java/net/tylermurphy/ken/command/fun/Claim.java +++ b/src/main/java/net/tylermurphy/ken/command/game/Claim.java @@ -1,4 +1,4 @@ -package net.tylermurphy.ken.command.fun; +package net.tylermurphy.ken.command.game; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; @@ -17,7 +17,7 @@ public class Claim { @Command(name="claim",description="Claim a random amount of moneys per 24h") public Response execute(Member sender, Guild guild){ String data = Ken.getInstance().getDatabase().getEconomyData().getData(guild.getIdLong(), sender.getUser().getIdLong()); - JSONObject json = Ken.getInstance().getDatabase().getEconomyData().updateData(guild.getIdLong(), sender.getUser().getIdLong(), data); + JSONObject json = Ken.getInstance().getDatabase().getEconomyData().updateData(data); int money = json.getInt("money"); long claim = json.getLong("claim"); long currentTime = new Date().getTime(); diff --git a/src/main/java/net/tylermurphy/ken/command/fun/Money.java b/src/main/java/net/tylermurphy/ken/command/game/Money.java similarity index 89% rename from src/main/java/net/tylermurphy/ken/command/fun/Money.java rename to src/main/java/net/tylermurphy/ken/command/game/Money.java index 7d399e2..b1fb1b5 100644 --- a/src/main/java/net/tylermurphy/ken/command/fun/Money.java +++ b/src/main/java/net/tylermurphy/ken/command/game/Money.java @@ -1,4 +1,4 @@ -package net.tylermurphy.ken.command.fun; +package net.tylermurphy.ken.command.game; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; @@ -15,7 +15,7 @@ public class Money { @Command(name="money",description="Get the amount of money you have") public Response execute(Member sender, Guild guild){ String data = Ken.getInstance().getDatabase().getEconomyData().getData(guild.getIdLong(), sender.getUser().getIdLong()); - JSONObject json = Ken.getInstance().getDatabase().getEconomyData().updateData(guild.getIdLong(), sender.getUser().getIdLong(), data); + JSONObject json = Ken.getInstance().getDatabase().getEconomyData().updateData(data); int money = json.getInt("money"); MessageEmbed embed = Ken.getInstance().getDefaultEmbed() .setColor(Color.green) diff --git a/src/main/java/net/tylermurphy/ken/command/game/Roulette.java b/src/main/java/net/tylermurphy/ken/command/game/Roulette.java new file mode 100644 index 0000000..05a9d1b --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/game/Roulette.java @@ -0,0 +1,105 @@ +package net.tylermurphy.ken.command.game; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.tylermurphy.ken.Ken; +import net.tylermurphy.ken.command.Response; +import net.tylermurphy.ken.command.annotation.Command; +import net.tylermurphy.ken.command.annotation.Option; +import net.tylermurphy.ken.command.annotation.Selection; +import org.json.JSONObject; + +import java.util.List; + +public class Roulette { + + @Command(name="roulette", description="Bet on a game of roulette") + @Option(name="bet", description="How much you want to bet", type=OptionType.INTEGER, required=true) + @Selection(name="type", description="What type of bet do you want to place", type=OptionType.STRING, choices={"red","black","green","odd","even","high","low","1st dozen","2nd dozen","3rd dozen","first four"}, required=true) + public Response execute(Member sender ,Guild guild, List args){ + String data = Ken.getInstance().getDatabase().getEconomyData().getData(guild.getIdLong(), sender.getUser().getIdLong()); + JSONObject json = Ken.getInstance().getDatabase().getEconomyData().updateData(data); + int money = json.getInt("money"); + int bet = (int)args.get(0); + if(bet < 5){ + return Response.error("You cannot bet anything less than 5 moneys"); + } else if(bet > money){ + return Response.error("You don't have enough moneys to bet this much"); + } + String guess = (String)args.get(1); + int rand = (int)(Math.random()*38); + boolean win = switch (guess) { + case "green" -> getColor(rand).equals("green"); + case "black" -> getColor(rand).equals("black"); + case "red" -> getColor(rand).equals("red"); + case "even" -> rand>1 && (rand)%2==1; + case "odd" -> rand>1 && rand%2==0; + case "low" -> rand>=2 && rand<=19; + case "high" -> rand>19; + case "1st dozen" -> rand>=2 && rand<=13; + case "2nd dozen" -> rand>=14 && rand<=25; + case "3rd dozen" -> rand>25; + case "first four" -> rand<3; + default -> false; + }; + int rate = getWinRate(guess); + int balance = win ? money -bet + bet * rate : money - bet; + EmbedBuilder builder = Ken.getInstance().getDefaultEmbed() + .setAuthor("Roulette") + .appendDescription("`Balance:` "+money+"\n") + .appendDescription("`Bet:` "+bet+"\n") + .appendDescription(getEmoji(rand) + getNumber(rand)+"\n") + .appendDescription("`New Balance:` "+balance+"\n") + .setFooter(win ? "You win! ("+rate+"x)" : "You loose, bet lost"); + json.put("money",balance); + Ken.getInstance().getDatabase().getEconomyData().setData(guild.getIdLong(), sender.getUser().getIdLong(), json.toString()); + return Response.success(builder.build()); + } + + private String getColor(int rand){ + boolean even = (rand&2)==1; + if(rand<3) return "green"; + if(rand<=10) + if(even) return "black"; + else return "red"; + else if(rand<=18) + if(even) return "red"; + else return "black"; + else if(rand<=28) + if(even) return "black"; + else return "red"; + else + if(even) return "red"; + else return "black"; + } + + private int getWinRate(String guess){ + return switch (guess) { + case "green" -> 17; + case "black", "red", "even", "odd", "low", "high" -> 2; + case "1st dozen", "2nd dozen", "3rd dozen" -> 3; + case "first four" -> 6; + default -> 1; + }; + } + + private String getEmoji(int rand){ + String color = getColor(rand); + if(color.equals("green")) + return ":green_square:"; + else if(color.equals("red")) + return ":red_square:"; + else + return ":black_large_square:"; + } + + private String getNumber(int rand){ + if(rand<2) + return rand == 0 ? "00" : "0"; + else + return String.valueOf(rand-1); + } + +} diff --git a/src/main/java/net/tylermurphy/ken/command/fun/Slots.java b/src/main/java/net/tylermurphy/ken/command/game/Slots.java similarity index 89% rename from src/main/java/net/tylermurphy/ken/command/fun/Slots.java rename to src/main/java/net/tylermurphy/ken/command/game/Slots.java index f03d50c..2ccdef1 100644 --- a/src/main/java/net/tylermurphy/ken/command/fun/Slots.java +++ b/src/main/java/net/tylermurphy/ken/command/game/Slots.java @@ -1,4 +1,4 @@ -package net.tylermurphy.ken.command.fun; +package net.tylermurphy.ken.command.game; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Guild; @@ -31,7 +31,7 @@ public class Slots { @Option(name="amount", description="Amount to bet", type=OptionType.INTEGER, required=true) public Response execute(Member sender, Guild guild, List args){ String data = Ken.getInstance().getDatabase().getEconomyData().getData(guild.getIdLong(), sender.getUser().getIdLong()); - JSONObject json = Ken.getInstance().getDatabase().getEconomyData().updateData(guild.getIdLong(), sender.getUser().getIdLong(), data); + JSONObject json = Ken.getInstance().getDatabase().getEconomyData().updateData(data); int money = json.getInt("money"); int bet = (int)args.get(0); if(bet < 5){ @@ -46,9 +46,7 @@ public class Slots { .setTitle("Slot Machine") .appendDescription("`Balance:` "+money+"\n") .appendDescription("`Bet:` "+bet+"\n") - .appendDescription(":black_large_square:".repeat(5)+"\n") - .appendDescription(":black_large_square:" + slot1.emoji + slot2.emoji + slot3.emoji +":black_large_square:\n") - .appendDescription(":black_large_square:".repeat(5)+"\n"); + .appendDescription(slot1.emoji + slot2.emoji + slot3.emoji + "\n"); if(slot1.emoji.equals(slot2.emoji) && slot1.emoji.equals(slot3.emoji)){ // 3 of a kind money += bet * slot2.full_reward; diff --git a/src/main/java/net/tylermurphy/ken/command/main/Help.java b/src/main/java/net/tylermurphy/ken/command/main/Help.java index 4b13bba..316ba24 100644 --- a/src/main/java/net/tylermurphy/ken/command/main/Help.java +++ b/src/main/java/net/tylermurphy/ken/command/main/Help.java @@ -63,6 +63,14 @@ public class Help { .appendDescription("**/remove ** Remove a song from the queue\n") .appendDescription("**/nowplaying** See what track is currently playing\n") .appendDescription("**/queue** View the current song queue\n"), + Ken.getInstance().getDefaultEmbed() + .setAuthor("Command List") + .setTitle(":camera: **Gif Commands**") + .appendDescription("**/crabrave ** Crab rave on someone\n") + .appendDescription("**/eject ** Eject someone because they are sus\n") + .appendDescription("**/gaymeme ** Warn someone that they are gay\n") + .appendDescription("**/headpat ** Pat someone on the head\n") + .appendDescription("**/wank ** Wank to someone\n"), Ken.getInstance().getDefaultEmbed() .setAuthor("Command List") .setTitle(":game_die: **Game Commands**") @@ -70,7 +78,11 @@ public class Help { .appendDescription("**/d8** Roll a d8 die\n") .appendDescription("**/d12** Roll a d12 die\n") .appendDescription("**/d20** Roll a d20 die\n") - .appendDescription("**/dice ** Roll a dice with set sides\n"), + .appendDescription("**/dice ** Roll a dice with set sides\n") + .appendDescription("**/claim** Claim moneys every 24h\n") + .appendDescription("**/money** Check how much moneys you have\n") + .appendDescription("**/roulette ** Gamble on roulette\n") + .appendDescription("**/slots ** Gamble on slots\n"), Ken.getInstance().getDefaultEmbed() .setAuthor("Command List") .setTitle(":man_detective: **Self Roles**") diff --git a/src/main/java/net/tylermurphy/ken/command/moderation/Ban.java b/src/main/java/net/tylermurphy/ken/command/moderation/Ban.java new file mode 100644 index 0000000..95ee7e7 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/moderation/Ban.java @@ -0,0 +1,86 @@ +package net.tylermurphy.ken.command.moderation; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.exceptions.ErrorResponseException; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.tylermurphy.ken.Ken; +import net.tylermurphy.ken.command.Response; +import net.tylermurphy.ken.command.annotation.Command; +import net.tylermurphy.ken.command.annotation.Option; +import net.tylermurphy.ken.command.annotation.Requirement; +import net.tylermurphy.ken.database.ModerationTable; +import net.tylermurphy.ken.util.Checks; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.awt.*; +import java.util.Date; +import java.util.List; + +public class Ban { + + @Command(name="ban", description="Perm ban a user and delete all messages in past 24h") + @Option(name="member", description="Member to ban", type=OptionType.USER, required=true) + @Option(name="reason", description="Reason to ban", type=OptionType.STRING, required=true) + @Option(name="deletemessages", description="Delete messages from past 24h", type=OptionType.BOOLEAN, required=true) + @Requirement(Permission.BAN_MEMBERS) + public Response execute(Member sender, List args, Guild guild){ + Member target = (Member) args.get(0); + String reason = (String) args.get(1); + boolean purge = (boolean) args.get(2); + if(target == sender){ + return Response.error("You are not allowed to do this to yourself"); + } + Role low = Checks.getHighestRole(target); + Role high = Checks.getHighestRole(sender); + if(!Checks.getRolePermission(high, low)){ + return Response.error("You need a higher role than the target"); + } + Role self = Checks.getHighestRole(guild.getSelfMember()); + if(!Checks.getRolePermission(self, low)){ + return Response.error("I need a higher role than the target"); + } + + try { + guild.retrieveBan(target).complete(); + return Response.error("User is already banned from this server"); + } catch (ErrorResponseException ignored) {} + + ModerationTable table = Ken.getInstance().getDatabase().getModerationTable(); + String data = table.getData(guild.getIdLong(), target.getUser().getIdLong()); + JSONObject json = table.updateData(data); + + JSONObject status = json.getJSONObject("status"); + status.put("type", "ban"); + status.put("reason", reason); + status.put("until", 0L); + json.put("status", status); + + JSONArray history = json.getJSONArray("history"); + history.put(new JSONObject().put("type", "ban").put("reason", reason).put("date",new Date().getTime())); + json.put("history", history); + + table.setData(guild.getIdLong(), target.getUser().getIdLong(), json.toString()); + + PrivateChannel channel = target.getUser().openPrivateChannel().complete(); + if(channel != null){ + EmbedBuilder builder = Ken.getInstance().getDefaultEmbed() + .setColor(Color.red) + .setTitle("**Banned**") + .appendDescription("You have been permanently banned from "+guild.getName()+"\n") + .appendDescription("`By:` " + sender.getEffectiveName()+"\n") + .appendDescription("`Reason:` " + reason); + channel.sendMessageEmbeds(builder.build()).queue(); + } + guild.ban(target,purge ? 1 : 0,reason).queue(); + EmbedBuilder builder = Ken.getInstance().getDefaultEmbed() + .appendDescription(String.format("Permanently banned %s for %s", target.getEffectiveName(), reason)); + return Response.success(builder.build()); + } + +} diff --git a/src/main/java/net/tylermurphy/ken/command/moderation/CloseServer.java b/src/main/java/net/tylermurphy/ken/command/moderation/CloseServer.java new file mode 100644 index 0000000..b6638d7 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/moderation/CloseServer.java @@ -0,0 +1,4 @@ +package net.tylermurphy.ken.command.moderation; + +public class CloseServer { +} diff --git a/src/main/java/net/tylermurphy/ken/command/moderation/History.java b/src/main/java/net/tylermurphy/ken/command/moderation/History.java new file mode 100644 index 0000000..cc598f9 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/moderation/History.java @@ -0,0 +1,4 @@ +package net.tylermurphy.ken.command.moderation; + +public class History { +} diff --git a/src/main/java/net/tylermurphy/ken/command/moderation/Kick.java b/src/main/java/net/tylermurphy/ken/command/moderation/Kick.java new file mode 100644 index 0000000..aad0de1 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/moderation/Kick.java @@ -0,0 +1,4 @@ +package net.tylermurphy.ken.command.moderation; + +public class Kick { +} diff --git a/src/main/java/net/tylermurphy/ken/command/moderation/Mute.java b/src/main/java/net/tylermurphy/ken/command/moderation/Mute.java new file mode 100644 index 0000000..6e23d74 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/moderation/Mute.java @@ -0,0 +1,4 @@ +package net.tylermurphy.ken.command.moderation; + +public class Mute { +} diff --git a/src/main/java/net/tylermurphy/ken/command/moderation/OpenServer.java b/src/main/java/net/tylermurphy/ken/command/moderation/OpenServer.java new file mode 100644 index 0000000..ce2b32a --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/moderation/OpenServer.java @@ -0,0 +1,4 @@ +package net.tylermurphy.ken.command.moderation; + +public class OpenServer { +} diff --git a/src/main/java/net/tylermurphy/ken/command/moderation/TempBan.java b/src/main/java/net/tylermurphy/ken/command/moderation/TempBan.java new file mode 100644 index 0000000..62696ad --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/moderation/TempBan.java @@ -0,0 +1,109 @@ +package net.tylermurphy.ken.command.moderation; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.exceptions.ErrorResponseException; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.tylermurphy.ken.Ken; +import net.tylermurphy.ken.command.Response; +import net.tylermurphy.ken.command.annotation.Command; +import net.tylermurphy.ken.command.annotation.Option; +import net.tylermurphy.ken.command.annotation.Requirement; +import net.tylermurphy.ken.database.ModerationTable; +import net.tylermurphy.ken.util.Checks; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.awt.*; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +public class TempBan { + + @Command(name="tempban", description="Temp ban a user and delete all messages in past 24h") + @Option(name="member", description="Member to temp-ban", type= OptionType.USER, required=true) + @Option(name="days", description="Days for temp ban", type= OptionType.INTEGER, required=true) + @Option(name="hours", description="Hours for temp ban", type= OptionType.INTEGER, required=true) + @Option(name="reason", description="Reason to temp-ban", type=OptionType.STRING, required=true) + @Option(name="deletemessages", description="Delete messages from past 24h", type=OptionType.BOOLEAN, required=true) + @Requirement(Permission.BAN_MEMBERS) + public Response execute(Member sender, List args, Guild guild){ + Member target = (Member) args.get(0); + int days = (int) args.get(1); + int hours = (int) args.get(2); + String reason = (String) args.get(3); + boolean purge = (boolean) args.get(4); + if(target == sender){ + return Response.error("You are not allowed to do this to yourself"); + } + Role low = Checks.getHighestRole(target); + Role high = Checks.getHighestRole(sender); + if(!Checks.getRolePermission(high, low)){ + return Response.error("You need a higher role than the target"); + } + Role self = Checks.getHighestRole(guild.getSelfMember()); + if(!Checks.getRolePermission(self, low)){ + return Response.error("I need a higher role than the target"); + } + if(hours < 0){ + return Response.error("Hours must be 0 or greater"); + } + if(days < 0){ + return Response.error("Days must be 0 or greater"); + } + if(days == 0 && hours == 0){ + return Response.error("Time to ban cannot be 0"); + } + + try { + guild.retrieveBan(target).complete(); + return Response.error("User is already banned from this server"); + } catch (ErrorResponseException ignored) {} + + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + cal.add(Calendar.DATE, days); + cal.add(Calendar.HOUR, hours); + SimpleDateFormat format = new SimpleDateFormat("L d, y ha zz"); + String date = format.format(cal.getTime()); + + ModerationTable table = Ken.getInstance().getDatabase().getModerationTable(); + String data = table.getData(guild.getIdLong(), target.getUser().getIdLong()); + JSONObject json = table.updateData(data); + + JSONObject status = json.getJSONObject("status"); + status.put("type", "temp-ban"); + status.put("reason", reason); + status.put("until", cal.getTime().getTime()); + json.put("status", status); + + JSONArray history = json.getJSONArray("history"); + history.put(new JSONObject().put("type", "temp-ban").put("reason", reason).put("date",new Date().getTime())); + json.put("history", history); + + table.setData(guild.getIdLong(), target.getUser().getIdLong(), json.toString()); + + PrivateChannel channel = target.getUser().openPrivateChannel().complete(); + if(channel != null){ + EmbedBuilder builder = Ken.getInstance().getDefaultEmbed() + .setColor(Color.red) + .setTitle("**Temp Banned**") + .appendDescription("You have been temporarily banned from "+guild.getName()+"\n") + .appendDescription("`By:` " + sender.getEffectiveName()+"\n") + .appendDescription("`Reason:` " + reason) + .appendDescription("`Until:` " + date); + channel.sendMessageEmbeds(builder.build()).queue(); + } + guild.ban(target,purge ? 1 : 0,reason).queue(); + EmbedBuilder builder = Ken.getInstance().getDefaultEmbed() + .appendDescription(String.format("Temporarily banned %s for %s until %s", target.getEffectiveName(), reason, date)); + return Response.success(builder.build()); + } + +} diff --git a/src/main/java/net/tylermurphy/ken/command/moderation/UnBan.java b/src/main/java/net/tylermurphy/ken/command/moderation/UnBan.java new file mode 100644 index 0000000..b259002 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/moderation/UnBan.java @@ -0,0 +1,88 @@ +package net.tylermurphy.ken.command.moderation; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.exceptions.ErrorResponseException; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.tylermurphy.ken.Ken; +import net.tylermurphy.ken.command.Response; +import net.tylermurphy.ken.command.annotation.Command; +import net.tylermurphy.ken.command.annotation.Option; +import net.tylermurphy.ken.command.annotation.Requirement; +import net.tylermurphy.ken.database.ModerationTable; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.awt.*; +import java.util.Date; +import java.util.List; + +public class UnBan { + + @Command(name="unban", description="Unban a user") + @Option(name="username", description="Username", type= OptionType.STRING, required=true) + @Option(name="discriminator", description="Discriminator", type=OptionType.INTEGER, required=true) + @Option(name="reason", description="Reason to unban", type=OptionType.STRING, required=true) + @Requirement(Permission.BAN_MEMBERS) + public Response execute(Member sender, Guild guild, List args){ + String username = (String) args.get(0); + String discriminator = String.valueOf(args.get(1)); + String reason = (String) args.get(2); + + User target = null; + for(Guild.Ban ban : guild.retrieveBanList()){ + User temp = ban.getUser(); + if(temp.getName().equals(username) && temp.getDiscriminator().equals(discriminator)){ + target = temp; + break; + } + } + + if(target == null){ + return Response.error("Unable to find this user"); + } + + if(target == sender.getUser()){ + return Response.error("You are not allowed to do this to yourself"); + } + + try { + guild.retrieveBan(target).complete(); + } catch (ErrorResponseException e) { + return Response.error("User is not banned from this server"); + } + + ModerationTable table = Ken.getInstance().getDatabase().getModerationTable(); + String data = table.getData(guild.getIdLong(), target.getIdLong()); + JSONObject json = table.updateData(data); + + JSONObject status = json.getJSONObject("status"); + status.put("type", "None"); + status.put("reason", ""); + status.put("until", 0L); + json.put("status", status); + + JSONArray history = json.getJSONArray("history"); + history.put(new JSONObject().put("type", "unban").put("reason", reason).put("date",new Date().getTime())); + json.put("history", history); + + table.setData(guild.getIdLong(), target.getIdLong(), json.toString()); + + PrivateChannel channel = target.openPrivateChannel().complete(); + if(channel != null){ + EmbedBuilder builder = Ken.getInstance().getDefaultEmbed() + .setColor(Color.green) + .setTitle("**Unbanned**") + .appendDescription("You have been unbanned from "+guild.getName()+"\n") + .appendDescription("`By:` " + sender.getEffectiveName()+"\n") + .appendDescription("`Reason:` " + reason); + channel.sendMessageEmbeds(builder.build()).queue(); + } + guild.unban(target).queue(); + EmbedBuilder builder = Ken.getInstance().getDefaultEmbed() + .appendDescription(String.format("Unbanned %s for %s", target, reason)); + return Response.success(builder.build()); + } + +} diff --git a/src/main/java/net/tylermurphy/ken/command/moderation/UnMute.java b/src/main/java/net/tylermurphy/ken/command/moderation/UnMute.java new file mode 100644 index 0000000..99ef6de --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/moderation/UnMute.java @@ -0,0 +1,4 @@ +package net.tylermurphy.ken.command.moderation; + +public class UnMute { +} diff --git a/src/main/java/net/tylermurphy/ken/command/main/AddRole.java b/src/main/java/net/tylermurphy/ken/command/selfrole/AddRole.java similarity index 97% rename from src/main/java/net/tylermurphy/ken/command/main/AddRole.java rename to src/main/java/net/tylermurphy/ken/command/selfrole/AddRole.java index 4aefa9a..cd8a7cd 100644 --- a/src/main/java/net/tylermurphy/ken/command/main/AddRole.java +++ b/src/main/java/net/tylermurphy/ken/command/selfrole/AddRole.java @@ -1,4 +1,4 @@ -package net.tylermurphy.ken.command.main; +package net.tylermurphy.ken.command.selfrole; import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.Guild; diff --git a/src/main/java/net/tylermurphy/ken/command/main/AddRolesPage.java b/src/main/java/net/tylermurphy/ken/command/selfrole/AddRolesPage.java similarity index 97% rename from src/main/java/net/tylermurphy/ken/command/main/AddRolesPage.java rename to src/main/java/net/tylermurphy/ken/command/selfrole/AddRolesPage.java index b29daeb..b5719c6 100644 --- a/src/main/java/net/tylermurphy/ken/command/main/AddRolesPage.java +++ b/src/main/java/net/tylermurphy/ken/command/selfrole/AddRolesPage.java @@ -1,4 +1,4 @@ -package net.tylermurphy.ken.command.main; +package net.tylermurphy.ken.command.selfrole; import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.Guild; diff --git a/src/main/java/net/tylermurphy/ken/command/main/DeleteRole.java b/src/main/java/net/tylermurphy/ken/command/selfrole/DeleteRole.java similarity index 97% rename from src/main/java/net/tylermurphy/ken/command/main/DeleteRole.java rename to src/main/java/net/tylermurphy/ken/command/selfrole/DeleteRole.java index 9d39a50..9d8b25f 100644 --- a/src/main/java/net/tylermurphy/ken/command/main/DeleteRole.java +++ b/src/main/java/net/tylermurphy/ken/command/selfrole/DeleteRole.java @@ -1,4 +1,4 @@ -package net.tylermurphy.ken.command.main; +package net.tylermurphy.ken.command.selfrole; import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.Guild; diff --git a/src/main/java/net/tylermurphy/ken/command/main/DeleteRolesPage.java b/src/main/java/net/tylermurphy/ken/command/selfrole/DeleteRolesPage.java similarity index 96% rename from src/main/java/net/tylermurphy/ken/command/main/DeleteRolesPage.java rename to src/main/java/net/tylermurphy/ken/command/selfrole/DeleteRolesPage.java index 76128fd..cbea176 100644 --- a/src/main/java/net/tylermurphy/ken/command/main/DeleteRolesPage.java +++ b/src/main/java/net/tylermurphy/ken/command/selfrole/DeleteRolesPage.java @@ -1,4 +1,4 @@ -package net.tylermurphy.ken.command.main; +package net.tylermurphy.ken.command.selfrole; import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.Guild; diff --git a/src/main/java/net/tylermurphy/ken/command/main/Roles.java b/src/main/java/net/tylermurphy/ken/command/selfrole/Roles.java similarity index 98% rename from src/main/java/net/tylermurphy/ken/command/main/Roles.java rename to src/main/java/net/tylermurphy/ken/command/selfrole/Roles.java index 0fc482b..238a8de 100644 --- a/src/main/java/net/tylermurphy/ken/command/main/Roles.java +++ b/src/main/java/net/tylermurphy/ken/command/selfrole/Roles.java @@ -1,4 +1,4 @@ -package net.tylermurphy.ken.command.main; +package net.tylermurphy.ken.command.selfrole; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.*; diff --git a/src/main/java/net/tylermurphy/ken/database/Database.java b/src/main/java/net/tylermurphy/ken/database/Database.java index 8e209fb..2c46c68 100644 --- a/src/main/java/net/tylermurphy/ken/database/Database.java +++ b/src/main/java/net/tylermurphy/ken/database/Database.java @@ -13,6 +13,7 @@ public class Database { private final DatabaseConnection connection; private final SelfRoleTable selfRoleTable; private final EconomyTable economyTable; + private final ModerationTable moderationTable; public Database(){ if(Ken.getInstance().getConfig().getBoolean("database.sqlite")) { @@ -22,6 +23,7 @@ public class Database { } selfRoleTable = new SelfRoleTable(this); economyTable = new EconomyTable(this); + moderationTable = new ModerationTable(this); } public SelfRoleTable getSelfRoleData(){ @@ -32,6 +34,8 @@ public class Database { return economyTable; } + public ModerationTable getModerationTable() { return moderationTable; } + protected Connection connect() throws SQLException { return connection.connect(); } diff --git a/src/main/java/net/tylermurphy/ken/database/EconomyTable.java b/src/main/java/net/tylermurphy/ken/database/EconomyTable.java index 589a204..9a716a5 100644 --- a/src/main/java/net/tylermurphy/ken/database/EconomyTable.java +++ b/src/main/java/net/tylermurphy/ken/database/EconomyTable.java @@ -55,7 +55,7 @@ public class EconomyTable { } } - public JSONObject updateData(long guildId, long userId, String data) { + public JSONObject updateData(String data) { JSONObject object = data == null ? new JSONObject() : new JSONObject(data); if(!object.has("money")) object.put("money", 0); if(!object.has("claim")) object.put("claim", 0L); diff --git a/src/main/java/net/tylermurphy/ken/database/ModerationTable.java b/src/main/java/net/tylermurphy/ken/database/ModerationTable.java new file mode 100644 index 0000000..9e0061d --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/database/ModerationTable.java @@ -0,0 +1,84 @@ +package net.tylermurphy.ken.database; + +import net.tylermurphy.ken.Ken; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.sql.*; +import java.util.function.Consumer; + +public class ModerationTable { + + private final Database database; + + public ModerationTable(Database database){ + + String sql = """ + CREATE TABLE IF NOT EXISTS moderation_data ( + guild_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + data TEXT NOT NULL, + until BIGINT NOT NULL, + PRIMARY KEY (guild_id,user_id) + );"""; + + try(Connection connection = database.connect(); Statement statement = connection.createStatement()) { + statement.executeUpdate(sql); + } catch (SQLException e) { + Ken.getInstance().getLogger().error("SQL Error: " + e.getMessage()); + } + + this.database = database; + } + + public String getData(long guildId, long userId){ + String sql = "SELECT * FROM moderation_data WHERE guild_id=? AND user_id=?"; + try(Connection connection = database.connect(); PreparedStatement statement = connection.prepareStatement(sql)) { + statement.setLong(1, guildId); + statement.setLong(2, userId); + ResultSet rs = statement.executeQuery(); + if(rs.next()) return rs.getString("data"); + else return null; + } catch (SQLException e) { + Ken.getInstance().getLogger().error("SQL Error: " + e.getMessage()); + return null; + } + } + + public boolean setData(long guildId, long userId, String data) { + String sql = "INSERT OR REPLACE INTO moderation_data (guild_id, user_id, data, until) VALUES(?,?,?,?)"; + try(Connection connection = database.connect(); PreparedStatement statement = connection.prepareStatement(sql)) { + statement.setLong(1, guildId); + statement.setLong(2, userId); + statement.setString(3, data); + statement.setLong(4, new JSONObject(data).getJSONObject("status").getLong("until")); + return statement.executeUpdate() != 0; + } catch (SQLException e) { + Ken.getInstance().getLogger().error("SQL Error: " + e.getMessage()); + return false; + } + } + + public void callOverdue(long date, Consumer callback){ + String sql = "SELECT * FROM moderation_data WHERE until < ? AND until > 0"; + try(Connection connection = database.connect(); PreparedStatement statement = connection.prepareStatement(sql)) { + statement.setLong(1, date); + ResultSet rs = statement.executeQuery(); + while (rs.next()){ + String[] data = {String.valueOf(rs.getLong("guild_id")), String.valueOf(rs.getLong("user_id")), rs.getString("data")}; + callback.accept(data); + } + } catch (SQLException e) { + Ken.getInstance().getLogger().error("SQL Error: " + e.getMessage()); + } + } + + public JSONObject updateData(String data) { + JSONObject object = data == null ? new JSONObject() : new JSONObject(data); + if(!object.has("history")) object.put("history", new JSONArray()); + if(!object.has("roles")) object.put("roles", new JSONArray()); + if(!object.has("status")) object.put("status", new JSONObject().put("type","None").put("until", 0L).put("reason","")); + return object; + } + +} diff --git a/src/main/java/net/tylermurphy/ken/image/GifFactory.java b/src/main/java/net/tylermurphy/ken/image/GifFactory.java deleted file mode 100644 index 193dc41..0000000 --- a/src/main/java/net/tylermurphy/ken/image/GifFactory.java +++ /dev/null @@ -1,131 +0,0 @@ -package net.tylermurphy.ken.image; - -import java.awt.image.BufferedImage; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Iterator; - -import javax.imageio.IIOException; -import javax.imageio.IIOImage; -import javax.imageio.ImageIO; -import javax.imageio.ImageTypeSpecifier; -import javax.imageio.ImageWriter; -import javax.imageio.metadata.IIOInvalidTreeException; -import javax.imageio.metadata.IIOMetadata; -import javax.imageio.metadata.IIOMetadataNode; -import javax.imageio.stream.ImageOutputStream; - -import net.dv8tion.jda.api.entities.User; - -public class GifFactory { - - public static byte[] generateEjectGif(User u) { - String message; - if(Math.random() > .5) - message = u.getName() + " was An Impostor"; - else - message = u.getName() + " was not An Impostor"; - - BufferedImage space1 = ImageFactory.getImageFromURL("https://cdn.tylermurphy.net/ken/space.jpg"); - BufferedImage avatar = ImageFactory.getImageFromURL(u.getAvatarUrl()); - - BufferedImage[] frames = new BufferedImage[30]; - for(int i = 0; i < 30; i++) { - frames[i] = ImageFactory.GenerateEjectFrame(message, Math.min(i, 23), 24, space1, avatar); - } - - try { - return generateFromBI(frames); - } catch(Exception e) { - e.printStackTrace(); - return null; - } - - } - - private static byte[] generateFromBI(BufferedImage[] images) - throws IIOException, IOException - { - System.out.println('e'); - ImageWriter gifWriter = getWriter(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ImageOutputStream ios = ImageIO.createImageOutputStream(baos); - IIOMetadata metadata = getMetadata(gifWriter); - - gifWriter.setOutput(ios); - gifWriter.prepareWriteSequence(null); - for (BufferedImage img: images) - { - IIOImage temp = new IIOImage(img, null, metadata); - gifWriter.writeToSequence(temp, null); - } - - gifWriter.endWriteSequence(); - ios.close(); - System.out.println('e'); - return baos.toByteArray(); - - } - - private static ImageWriter getWriter() throws IIOException - { - Iterator itr = ImageIO.getImageWritersByFormatName("gif"); - if(itr.hasNext()) - return itr.next(); - - throw new IIOException("GIF writer doesn't exist on this JVM!"); - } - - private static IIOMetadata getMetadata(ImageWriter writer) - throws IIOInvalidTreeException - { - ImageTypeSpecifier img_type = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB); - IIOMetadata metadata = writer.getDefaultImageMetadata(img_type, null); - String native_format = metadata.getNativeMetadataFormatName(); - IIOMetadataNode node_tree = (IIOMetadataNode)metadata.getAsTree(native_format); - - IIOMetadataNode graphics_node = getNode("GraphicControlExtension", node_tree); - graphics_node.setAttribute("delayTime", String.valueOf(8)); - graphics_node.setAttribute("disposalMethod", "none"); - graphics_node.setAttribute("userInputFlag", "FALSE"); - - makeLoopy(node_tree); - - metadata.setFromTree(native_format, node_tree); - - return metadata; - } - - private static void makeLoopy(IIOMetadataNode root) - { - IIOMetadataNode app_extensions = getNode("ApplicationExtensions", root); - IIOMetadataNode app_node = getNode("ApplicationExtension", app_extensions); - - app_node.setAttribute("applicationID", "NETSCAPE"); - app_node.setAttribute("authenticationCode", "2.0"); - app_node.setUserObject(new byte[]{ 0x1, (byte) (0), (byte) ((0) & 0xFF)}); - - app_extensions.appendChild(app_node); - root.appendChild(app_extensions); - } - - private static IIOMetadataNode getNode(String node_name, IIOMetadataNode root) - { - IIOMetadataNode node; - - for (int i = 0; i < root.getLength(); i++) - { - if(root.item(i).getNodeName().compareToIgnoreCase(node_name) == 0) - { - node = (IIOMetadataNode) root.item(i); - return node; - } - } - - node = new IIOMetadataNode(node_name); - root.appendChild(node); - - return node; - } - -} \ No newline at end of file diff --git a/src/main/java/net/tylermurphy/ken/image/ImageFactory.java b/src/main/java/net/tylermurphy/ken/image/ImageFactory.java deleted file mode 100644 index e70156c..0000000 --- a/src/main/java/net/tylermurphy/ken/image/ImageFactory.java +++ /dev/null @@ -1,75 +0,0 @@ -package net.tylermurphy.ken.image; - -import java.awt.AlphaComposite; - -import java.awt.Color; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.geom.RoundRectangle2D; -import java.awt.image.BufferedImage; -import java.net.HttpURLConnection; -import java.net.URL; - -import javax.imageio.ImageIO; - -public class ImageFactory { - - public static BufferedImage GenerateEjectFrame(String message, int frame, float totalFrames, BufferedImage space1, BufferedImage avatar) { - try { - int w = 600; - int h = 400; - BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); - - Graphics2D g2d = img.createGraphics(); - g2d.drawImage(space1, (int) (-100+100/totalFrames*frame), 0, (int)(w*1.5), (int)(h*1.5), null); - - BufferedImage ravater = rotate(avatar, 180/24*frame); - g2d.drawImage(ravater, (w+2*avatar.getWidth()+100)/24*frame-avatar.getWidth()-50, h/2-avatar.getHeight()/2, 150, 150, null); - - if(frame > 12) { - int length = (message.length() * (frame-11)/12); - message = message.substring(0, length); - - g2d.setFont(new Font("Dialog", Font.BOLD, 25)); - FontMetrics fm = g2d.getFontMetrics(); - int x = w/2 - fm.stringWidth(message)/2; - int y = h/2; - g2d.drawString(message, x, y); - } - - return img; - - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - public static BufferedImage rotate(BufferedImage bimg, double angle) { - - int w = bimg.getWidth()+50; - int h = bimg.getHeight()+50; - - BufferedImage rotated = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); - Graphics2D graphic = rotated.createGraphics(); - graphic.rotate(Math.toRadians(angle), w/2, h/2); - graphic.drawImage(bimg, null, w/2-bimg.getWidth()/2, h/2-bimg.getHeight()/2); - graphic.dispose(); - return rotated; - } - - public static BufferedImage getImageFromURL(String link) { - try { - final URL url = new URL(link); - final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0"); - return ImageIO.read(connection.getInputStream()); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - -} \ No newline at end of file diff --git a/src/main/java/net/tylermurphy/ken/util/Checks.java b/src/main/java/net/tylermurphy/ken/util/Checks.java new file mode 100644 index 0000000..7c3daa1 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/util/Checks.java @@ -0,0 +1,33 @@ +package net.tylermurphy.ken.util; + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Role; + +import java.util.List; + +public class Checks { + + public static Role getHighestRole(Member member) { + if(member == null) { + return null; + } + List roles = member.getRoles(); + if (roles.isEmpty()) { + return null; + } + return roles.stream().min((first, second) -> { + if (first.getPosition() == second.getPosition()) { + return 0; + } + return first.getPosition() > second.getPosition() ? -1 : 1; + }).orElse(null); + } + + public static boolean getRolePermission(Role first, Role second){ + if(first == null) return false; + if(second == null) return true; + if(!first.getGuild().equals(second.getGuild())) return false; + return first.getPosition() > second.getPosition(); + } + +} diff --git a/src/main/java/net/tylermurphy/ken/util/GifSequenceWriter.java b/src/main/java/net/tylermurphy/ken/util/GifSequenceWriter.java new file mode 100644 index 0000000..f5860dc --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/util/GifSequenceWriter.java @@ -0,0 +1,75 @@ +package net.tylermurphy.ken.util; + +import javax.imageio.*; +import javax.imageio.metadata.IIOInvalidTreeException; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataNode; +import javax.imageio.stream.ImageOutputStream; +import java.awt.image.RenderedImage; +import java.io.IOException; + +public class GifSequenceWriter { + + protected ImageWriter writer; + protected ImageWriteParam params; + protected IIOMetadata metadata; + + public GifSequenceWriter(ImageOutputStream out, int imageType, int delay, boolean loop) throws IOException { + writer = ImageIO.getImageWritersBySuffix("gif").next(); + params = writer.getDefaultWriteParam(); + + ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imageType); + metadata = writer.getDefaultImageMetadata(imageTypeSpecifier, params); + + configureRootMetadata(delay, loop); + + writer.setOutput(out); + writer.prepareWriteSequence(null); + } + + private void configureRootMetadata(int delay, boolean loop) throws IIOInvalidTreeException { + String metaFormatName = metadata.getNativeMetadataFormatName(); + IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(metaFormatName); + + IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension"); + graphicsControlExtensionNode.setAttribute("disposalMethod", "restoreToBackgroundColor"); + graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE"); + graphicsControlExtensionNode.setAttribute("transparentColorFlag", "TRUE"); + graphicsControlExtensionNode.setAttribute("delayTime", Integer.toString(delay / 10)); + graphicsControlExtensionNode.setAttribute("transparentColorIndex", "3"); + + IIOMetadataNode commentsNode = getNode(root, "CommentExtensions"); + commentsNode.setAttribute("CommentExtension", "Created by: https://memorynotfound.com"); + + IIOMetadataNode appExtensionsNode = getNode(root, "ApplicationExtensions"); + IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension"); + child.setAttribute("applicationID", "NETSCAPE"); + child.setAttribute("authenticationCode", "2.0"); + + int loopContinuously = loop ? 0 : 1; + child.setUserObject(new byte[]{ 0x1, (byte) (loopContinuously & 0xFF), (byte) ((loopContinuously >> 8) & 0xFF)}); + appExtensionsNode.appendChild(child); + metadata.setFromTree(metaFormatName, root); + } + + private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName){ + int nNodes = rootNode.getLength(); + for (int i = 0; i < nNodes; i++){ + if (rootNode.item(i).getNodeName().equalsIgnoreCase(nodeName)){ + return (IIOMetadataNode) rootNode.item(i); + } + } + IIOMetadataNode node = new IIOMetadataNode(nodeName); + rootNode.appendChild(node); + return(node); + } + + public void writeToSequence(RenderedImage img) throws IOException { + writer.writeToSequence(new IIOImage(img, null, metadata), params); + } + + public void close() throws IOException { + writer.endWriteSequence(); + } + +} \ No newline at end of file diff --git a/src/main/java/net/tylermurphy/ken/util/ImageFetcher.java b/src/main/java/net/tylermurphy/ken/util/ImageFetcher.java new file mode 100644 index 0000000..875475b --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/util/ImageFetcher.java @@ -0,0 +1,30 @@ +package net.tylermurphy.ken.util; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +public class ImageFetcher { + + private final Map CACHE = new HashMap<>(); + + public BufferedImage getImage(String url, boolean cache) throws IOException { + if(CACHE.containsKey(url)) return CACHE.get(url); + HttpURLConnection connection = getConnection(url); + BufferedImage image = ImageIO.read(connection.getInputStream()); + if(cache && image != null) CACHE.put(url, image); + return image; + } + + private HttpURLConnection getConnection(String link) throws IOException { + final URL url = new URL(link); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0"); + return connection; + } + +}