I have a problem while creating a Java bot for Discord. I decided to make a command for it to kick players from the server. But I ran into difficulties.
Here's a code :
package com.company;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import java.util.List;
import java.util.Objects;
public class KickComm extends ListenerAdapter {
public void onGuildMessageReceived(GuildMessageReceivedEvent event) {
String[] args = event.getMessage().getContentRaw().split("\\s+");
List<Member> mentionedMembers = event.getMessage().getMentionedMembers();
Member target = mentionedMembers.get(0);
if(args[0].equalsIgnoreCase(Main.prefix + "kick"))
{
if (args.length < 2) { //TODO NOT WORK
EmbedBuilder NoUser = new EmbedBuilder();
NoUser.setColor(0xff3923);
NoUser.setTitle("\uD83D\uDD34You need to add a <#username> and <reason>");
NoUser.setFooter("Usage: " + Main.prefix + "kick <#username> <reason>.",
Objects.requireNonNull(event.getMember()).getUser().getAvatarUrl());
event.getChannel().sendMessage(NoUser.build()).queue();
NoUser.clear();
}
else if (args.length < 3) { //WORK
EmbedBuilder NoReason = new EmbedBuilder();
NoReason.setColor(0xff3923);
NoReason.setTitle("\uD83D\uDD34You need to add a <reason>.");
NoReason.setFooter("Usage: " + Main.prefix + "kick <#username> <reason>.",
Objects.requireNonNull(event.getMember()).getUser().getAvatarUrl());
event.getChannel().sendMessage(NoReason.build()).queue();
NoReason.clear();
}
else if(!Objects.requireNonNull(event.getMember()).hasPermission(Permission.KICK_MEMBERS) //WORK
&&
!event.getMember().canInteract(target)) {
EmbedBuilder NoPermission = new EmbedBuilder();
NoPermission.setColor(0xff3923);
NoPermission.setTitle("\uD83D\uDD34You don't have permission to use this command.");
NoPermission.setFooter("Usage: " + Main.prefix + "kick <#username> <reason>.",
Objects.requireNonNull(event.getMember()).getUser().getAvatarUrl());
event.getChannel().sendMessage(NoPermission.build()).queue();
NoPermission.clear();
}
else if(mentionedMembers.isEmpty()) { //TODO NOT WORK
EmbedBuilder NoMember = new EmbedBuilder();
NoMember.setColor(0xff3923);
NoMember.setTitle("\uD83D\uDD34I don't see member with this nickname.");
NoMember.setFooter("Usage: " + Main.prefix + "kick <#username> <reason>.",
Objects.requireNonNull(event.getMember()).getUser().getAvatarUrl());
event.getChannel().sendMessage(NoMember.build()).queue();
NoMember.clear();
}
}
}
}
Promlem in two lines :
if (args.length < 2) {
And
else if(mentionedMembers.isEmpty()) {
Most of all, I can't understand why line 1 does not work. When I write the !kick command in the discord, the console displays an error :
java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
I don't know why args length is 0, it's very strange.I tried to "if-else-if" to "if", but it doesn't work.I really wanna to continue creating that command, but i don't know what to do.
P.S.:it's not all of code, because i can't progress further due to this error.Sorry for my Google translater english and many thanks
The exception is caused by this line:
Member target = mentionedMembers.get(0);
Your problem here is that not every message may mention a member. Keep in mind you also receive your own messages. If the bot only sends an embed, the content will be empty.
If the content is only whitespace your split("\\s+") will return an empty array. This will cause an ArrayIndexOutOfBoundsException on this line:
if(args[0].equalsIgnoreCase(Main.prefix + "kick"))
I would recommend checking for the length of mentionedMembers and checking for the length of args before trying to access their respective elements.
Related
I've written a rather simple method for my paper/spigot Minecraft server plugin that detects potential lag machines under construction.
The issue I have is that I want to send a single chat message that, when clicked once, will first run a /vanish command on behalf of the clicker.
Then if (and only if) the vanish was successful, I want to run a teleport command to a location included along with the specific instance of the ClickEvent.
Both of those commands need to be completed from the single user click event.
For reference here is the method that calls notifyOps() and includes the TextComponent in question, msg
if (LagMats.contains(blockType) || mat.contains("MINECART") || mat.contains("DOOR")) {
int counter = 0;
for (Material thisMat: LagMats) {
if (thisMat != Material.GRAVEL) {
counter += Utilities.blockCounter(block.getChunk(), thisMat);
}
}
TextComponent warn = new TextComponent("WARN "); warn.setBold(true);
warn.setColor(ChatColor.RED);
TextComponent msg = new TextComponent("Potential lag-machine at " +
block.getX() + ", " + block.getY() + ", " + block.getZ() + " in " + dimension +
" by " + placer_name + " with UUID: " + placer.getUniqueId());
String cmd = "/execute in " + env + " run tp #s " +
block.getX() + " " + block.getY() + " " + block.getZ();
msg.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, cmd));
if (counter > 256) {
Utilities.notifyOps(new TextComponent(warn, msg));
}
}
Oh and the actual little code of notifyOps where the TextComponent is used in a message:
// send a message to all online ops and console
public static boolean notifyOps(TextComponent msg) {
if (msg == null) return false;
for (Player thisPlayer: Bukkit.getOnlinePlayers()) {
try {
if (thisPlayer.isOp()) thisPlayer.spigot().sendMessage(msg);
} catch (Exception e) {return false;}
}
System.out.println(msg.getText());
return true;
}
So I want to have the user click just once, run two commands, the second only if the first succeeds, and would be best if it could be done within the try block the message is sent from.
I could write a custom command for this purpose, and then just run that command, but I rather avoid adding classes for such a small addition if it's actually possible and I just have no idea.
Thanks for any advice or help!
There is no way of doing that without writing a custom command...
This is impossible because the ClickEvent and HoverEvent are entirely client-side. That means that there are no packets sent from the Player to the server. Therefore, it is impossible to callback the click of the Player and call a method to perform what you are trying to do.
You may notice that all the ClickEvent.Actions do not affect the server. OPEN_URL, OPEN_FILE, RUN_COMMAND, SUGGEST_COMMAND, CHANGE_PAGE and COPY_TO_CLIPBOARD are all actions taken on the client-side.
The only way here is to make the client send a command to the server which will trigger a method.
So I'm making a simple code redemption plugin for a Minecraft server. What's weird is when I type /redeem (the valid code), nothing happens, although it's supposed to... The valid code is the a code entered into the plugins configuration by the user.
Here's my code...
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args)
{
//Assigns the commands chosen in config to strings
String commandChosen1 = this.getConfig().getString("Command for code 1");
String commandChosen2 = this.getConfig().getString("Command for code 2");
String commandChosen3 = this.getConfig().getString("Command for code 3");
//Assigns the codes to strings
String validCode1 = this.getConfig().getString("Valid Code 1");
String validCode2 = this.getConfig().getString("Valid Code 2");
String validCode3 = this.getConfig().getString("Valid Code 3");
//If the redeem command is sent from a player
if(cmd.getName().equalsIgnoreCase("redeem") && sender instanceof Player)
{
//Casts the sender to a new player.
Player player = (Player) sender;
//Creates object hasUSed to store whether or not the player has already redeemed a code
Object hasUsed = this.getConfig().get(player.getName());
//Gives an error message of the arguments don't equal 1.
if(args.length != 1)
{
player.sendMessage(ChatColor.DARK_RED + "Please enter a valid promo code. Find them on our twitter!");
}
if(args.length == 1)
{
//If the player hasn't used the code yet and the arguments given are equal to a code then give them the reward...
if(args[0] == validCode1 && hasUsed == null)
{
this.getConfig().set(player.getName(), 1);
player.sendMessage(ChatColor.GREEN + "Promo code successfully entered!");
if(commandChosen1 == "xp")
{
Bukkit.dispatchCommand(player, commandChosen1 + getConfig().getString("XP Given") + "L" + " " + player.getName());
}
}
}
return true;
}
return false;
}
The problem occurs on "if (args[0] == validCode1 && hasUsed == null)". The code that's supposed to happen if both those things check out, doesn't happen and I have no clue why.
Make sure to use equals() when comparing Strings. Using commandChosen1 == "xp" compares string references not values; use commandChosen1.equals("xp") or if you prefer "xp".equals(commandChosen1).
Also,
While it is possible to use a this.getConfig().getString()with a key value that contains spaces, it can make configuration files hard to read and cluttered. Whenever I design plugins I'll design my config.yml as such
VoteGUI:
message: 'hello'
and then run a this.getConfig().getString("VoteGUI.message");
For yours I'd suggest something like this
Promo-Codes:
validCode1: 'insert code here'
validCode2: 'insert code here'
validCode3: 'insert code here'
and then put this in your onCommand method:
String validCode1 = this.getConfig().getString("Promo-Codes.validCode1");
String validCode2 = this.getConfig().getString("Promo-Codes.validCode2");
String validCode3 = this.getConfig().getString("Promo-Codes.validCode3");
If this does not resolve the issue, copy and paste the exception being thrown from the console and I may be of further assistance
I'm trying to get a specific user's tweets into Processing and then have them spoken out using the TTS Library. So far I've managed to get the tweets into Processing, with them printed as I want them. BUT, adding the TTS stuff is where it's proving problematic, considering my novice-level-skills.
What happens at the moment is that I receive the error message:
The method speak(String) in the type TTS is not applicable for the arguments (String[])
Anyone have any ideas? Help would be greatly appreciated. Thanks.
import twitter4j.util.*;
import twitter4j.*;
import twitter4j.management.*;
import twitter4j.api.*;
import twitter4j.conf.*;
import twitter4j.json.*;
import twitter4j.auth.*;
import guru.ttslib.*;
import java.util.*;
TTS tts;
tts = new TTS();
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setOAuthConsumerKey("XXXX");
cb.setOAuthConsumerSecret("XXXX");
cb.setOAuthAccessToken("XXXX");
cb.setOAuthAccessTokenSecret("XXXX");
java.util.List statuses = null;
Twitter twitter = new TwitterFactory(cb.build()).getInstance();
String userName ="#BBC";
int numTweets = 19;
String[] twArray = new String[numTweets];
try {
statuses = twitter.getUserTimeline(userName);
}
catch(TwitterException e) {
}
for (int i=0; i<statuses.size(); i++) {
Status status = (Status)statuses.get(i);
//println(status.getUser().getName() + ": " + status.getText());
twArray[i] = status.getUser().getName() + ": " + status.getText();
}
println(twArray);
tts.speak(twArray);
The error says it all: the tts.speak() function take a single String value, but you're giving it a String[] array.
In other words, you should only be passing in a single tweet at a time. Instead, you're passing in every tweet at once. The function doesn't know how to handle that, so you get the error.
You need to only pass in a single String value. How you do that depends on what exactly your goal is. You might just pass in the first tweet:
tts.speak(twArray[0]);
Or you might pass in each tweet one at a time:
for(String tweet : twArray){
tts.speak(tweet);
}
It seems like the Play Framework used(?) to have a since() function to get relative time (like "4 minutes ago") in views for Play 1.x. This is mentioned as a Date Extension here
However in Play 2.1 this doesn't appear to work anymore. I get value since is not a member of java.util.Date ... Additionally I can't find any other references to since() (in the context of Play 2.1) online.
Is there a proper/default way of handling this common case? I feel like I must be missing something important since this seems to no longer be supported?
Thanks!
The since() method is unavailable since beginning of the 2.0 branch.
Not a direct answer, but if it's possible I'd suggest to use JavaScript plugin for this task for an example: timeago jQuery plugin reasons:
It doesn't require calculating it in the controller
You can cache your site (for an example in the memory) for long time, and since time will be still displayed correctly as it's updated on the client-side.
It auto updates even without page refresh (like here, on the Stack Overflow)
#Jack suggested a pretty good answer.
Here is a version of his code that might be useful because it'll enable some composition if needed (the check function is not composing but could be easily changed to compose and show a more detailed since value)
package object pimps {
import java.util.Date
import org.joda.time.DateTime;
import org.joda.time.Period;
def step(f:Period => Int)(fi:String):Period => Option[String] = {
def g(i:Int = 1) = i + " " + fi + (if (i==1) "" else "s") + " ago"
(p:Period) => {
f(p) match {
case 0 => None
case 1 => Some(g())
case x => Some(g(x))
}
}
}
val yearsStep = step(_.getYears)("year")
val monthsStep = step(_.getMonths)("month")
val daysStep = step(_.getDays)("day")
val hoursStep = step(_.getHours)("hour")
val minutesStep = step(_.getMinutes)("minute")
val secondsStep = step(_.getSeconds)("second")
val steps = Seq(yearsStep, monthsStep, daysStep, hoursStep, minutesStep, secondsStep)
val check =
(p:Period) =>
steps.collectFirst {
case f if f(p).isDefined => f(p).get
}
implicit class PimpedDate(col: Date) {
def since() = {
val period: Period = new Period(new DateTime(col), DateTime.now);
check(period)
}
}
}
As you can see, for now we stop at the first matching level, and also we repeat the getter (getYears if matching will be called twice).
Nevertheless, another thing to note is the usage of implicit class which has been introduced in Scala 2.10 to ease the pimping
As far as I can tell this isn't possible to do any more (by default in Play2.1). Please correct me if I am wrong. Here's how I recreated it. As mentioned here I "pimped" the "Date" class:
// File app/views/pimps.scala
package views
package object pimps {
import java.util.Date
import org.joda.time.DateTime;
import org.joda.time.Period;
class PimpedDate(col: Date) {
def since() = {
def addS(b: Int) = if (b == 1) "" else "s"
val now: DateTime = new DateTime();
val period: Period = new Period(new DateTime(col), now);
var r: String = "";
if (period.getYears() > 0) {
r = period.getYears() + " year" + addS(period.getYears()) + " ago";
} else if (period.getWeeks() > 0) {
r = period.getWeeks() + " week" + addS(period.getWeeks()) + " ago";
} else if (period.getMonths() > 0) {
r = period.getMonths() + " month" + addS(period.getMonths()) + " ago";
} else if (period.getDays() > 0) {
r = period.getDays() + " day" + addS(period.getDays()) + " ago";
} else if (period.getHours() > 0) {
r = period.getHours() + " hour" + addS(period.getHours()) + " ago";
} else if (period.getMinutes() > 0) {
r = period.getMinutes() + " minute" + addS(period.getMinutes()) + " ago";
} else {
r = period.getSeconds() + " second" + addS(period.getSeconds()) + " ago";
}
r
}
}
implicit def pimpDate(col: Date) = new PimpedDate(col)
}
Then in my view I can just import the above:
#import views.pimps._
and then use since() just as you could in Play1
<td>#record.created_on.since()</td>
Please comment/answer if there's a better way to do this or write the scala code...
Hi I'm trying to make a game in java that gives users the option to a joystick or gamepad to control movement. So I found something called "JInput" that is suppose to make it easy to detect all connected game controllers. The problem is that when I run it in Eclipse I get the following error: "java.lang.UnsatisfiedLinkError: no jinput-dx8 in java.library.path".
My code is the following:
import net.java.games.input.*;
public class ListControllers
{
public static void main(String[] args)
{
System.out.println("JInput version: " + Version.getVersion());
ControllerEnvironment ce =
ControllerEnvironment.getDefaultEnvironment();
Controller[] cs = ce.getControllers();
if (cs.length == 0) {
System.out.println("No controllers found");
System.exit(0);
}
// print the name and type for each controller
for (int i = 0; i < cs.length; i++)
System.out.println(i + ". " +
cs[i].getName() + ", " + cs[i].getType() );
} // end of main()
} // end of ListControllers class
I'm currently developing in Windows 7 environment. Any help would be really appreciated.
You should set java.library.path property to point to the directory containing native dlls of JInput.
You can do it by adding -Djava.library.path=x (where x is your path) to the command line or to the "VM arguments" field of "Run configurations" dialog in Eclipse.