This commit is contained in:
nickreesdev 2021-02-19 19:24:03 -06:00
commit 202fdafe81
31 changed files with 548 additions and 247 deletions

View File

@ -1,9 +1,10 @@
# Project Structure
- **Commons**: Commons is common libraries and/or utilities that are shared across the network.
g
- **ServerData**: This branch of the project controls the database backend for both Redis and MySQL. All modules that use Redis or MySQL must have this as a dependency.
- **ServerController**: This will dynamically start and stop servers on demand.
- **Proxy**: The proxy will handle server balancing and player caching.
- **API**: This is the frontend of the project if you will. All developers will be given access to this branch of the project where they can access multiple parts of the server.
- **API**: This is the Restful API. The API has api keys which have access levels. Players will be able to generate an api key in-game with the /api command and they will have the standard access level. The standard access level has access to things such as stats, leaderboards, etc. The dev access level is granted to Jr.Developers and above. The dev access level has access to things such as server groups, Minecraft servers, etc.
- **Core**: The core is a shared module between all Spigot plugins. Everything used between multiple Spigot servers will be created here.
- **Build Server**: The core for the build server - This handles map creating, parsing, etc
- **Hub**: This is pretty self-explanatory. Any Hub related things will go here.

View File

@ -11,8 +11,8 @@ import zone.themcgamer.api.model.ModelSerializer;
import zone.themcgamer.api.model.impl.*;
import zone.themcgamer.api.repository.AccountRepository;
import zone.themcgamer.api.route.AccountRoute;
import zone.themcgamer.api.route.PlayerStatusRoute;
import zone.themcgamer.api.route.ServersRoute;
import zone.themcgamer.api.route.StatusRoute;
import zone.themcgamer.data.APIAccessLevel;
import zone.themcgamer.data.jedis.JedisController;
import zone.themcgamer.data.jedis.data.APIKey;
@ -57,12 +57,12 @@ public class API {
addModel(NodeModel.class);
addModel(ServerGroupModel.class);
addModel(AccountModel.class);
addModel(StatusModel.class);
addModel(PlayerStatusModel.class);
// Adding the routes
addRoute(new ServersRoute());
addRoute(new AccountRoute(accountRepository));
addRoute(new StatusRoute());
addRoute(new PlayerStatusRoute());
// 404 Handling
Spark.notFound((request, response) -> {
@ -110,6 +110,8 @@ public class API {
System.out.println("Handling incoming request from \"" + request.ip() + "\" using path \"" + request.pathInfo() + "\"");
APIKey key = new APIKey(UUID.randomUUID().toString(), APIAccessLevel.STANDARD);
// If authentication is enabled, handle the api key checking and display a Unauthorized error
// if there is a problem checking the key or the key is invalid
if (requiresAuthentication) {
String apiKey = request.headers("key");
if (apiKey == null)
@ -133,7 +135,9 @@ public class API {
if (method.getParameterTypes().length != 3)
throw new APIException("Invalid route defined");
Object object = method.invoke(entry.getKey(), request, response, key);
jsonObject.addProperty("success", "true");
jsonObject.addProperty("success", "true"); // Marking the request as successful in the JsonObject
// Format the Object returned from the route accordingly
if (object instanceof IModel) {
if (models.contains(object.getClass()))
jsonObject.add("value", gson.toJsonTree(((IModel) object).toMap(), HashMap.class));
@ -144,13 +148,17 @@ public class API {
jsonObject.add("value", gson.toJsonTree(object, HashMap.class));
else jsonObject.addProperty("value", object.toString());
} catch (Throwable ex) {
// If there is an error thrown from a route, we wanna fetch the error from the invoke method
// and get the cause of the exception
if (ex instanceof InvocationTargetException)
ex = ex.getCause();
String message = ex.getLocalizedMessage();
// If the exception has no message associated with it, display the type of exception instead
if (message == null || (message.trim().isEmpty()))
message = ex.getClass().getSimpleName();
jsonObject.addProperty("success", "false");
jsonObject.addProperty("error", message);
// If the caught exception is not an API exception, print the stacktrace
if (!(ex instanceof APIException)) {
System.err.println("The route \"" + entry.getKey().getClass().getSimpleName() + "\" raised an exception:");
ex.printStackTrace();
@ -162,10 +170,20 @@ public class API {
}
}
/**
* Adding a {@link IModel}
*
* @param modelClass the class of the model to add
*/
private static void addModel(Class<? extends IModel> modelClass) {
models.add(modelClass);
}
/**
* Adding a route
*
* @param object the instance of the route to add
*/
private static void addRoute(Object object) {
List<Method> methods = routes.getOrDefault(object, new ArrayList<>());
for (Method method : object.getClass().getMethods()) {

View File

@ -1,16 +1,14 @@
package zone.themcgamer.api;
import lombok.NoArgsConstructor;
/**
* This {@link RuntimeException} gets thrown when there is a problem handling a {@link RestPath}
*
* @author Braydon
*/
@NoArgsConstructor
public class APIException extends RuntimeException {
/**
* Constructs a new runtime exception with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
public APIException() {}
/**
* Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a

View File

@ -4,6 +4,8 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* The API version is used in {@link RestPath}. It represents the version the path is using
*
* @author Braydon
*/
@AllArgsConstructor @Getter

View File

@ -8,6 +8,8 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation represents information for a specific Rest path
*
* @author Braydon
*/
@Retention(RetentionPolicy.RUNTIME)

View File

@ -3,6 +3,8 @@ package zone.themcgamer.api.model;
import java.util.HashMap;
/**
* This interface represents a custom Object that will displayed as json when handling requests
*
* @author Braydon
*/
public interface IModel {

View File

@ -9,6 +9,8 @@ import java.lang.reflect.Type;
import java.util.Map;
/**
* This class handles serializing of {@link IModel}'s
*
* @author Braydon
*/
public class ModelSerializer implements JsonSerializer<IModel> {

View File

@ -13,7 +13,7 @@ import java.util.UUID;
* @author Braydon
*/
@AllArgsConstructor @Setter @Getter @ToString
public class StatusModel implements IModel {
public class PlayerStatusModel implements IModel {
private final UUID uuid;
private final String playerName;
private String server;

View File

@ -14,6 +14,8 @@ import java.util.Objects;
import java.util.UUID;
/**
* This repository handles fetching of {@link AccountModel}'s from MySQL
*
* @author Braydon
*/
public class AccountRepository extends MySQLRepository {
@ -23,6 +25,12 @@ public class AccountRepository extends MySQLRepository {
super(dataSource);
}
/**
* Fetch the {@link AccountModel} with the provided {@link UUID}
*
* @param uuid the uuid of the account
* @return the account, null if it doesn't exist
*/
public AccountModel getAccount(UUID uuid) {
AccountModel[] model = new AccountModel[] { null };
executeQuery(SELECT_ACCOUNT, new Column[] {
@ -40,13 +48,9 @@ public class AccountRepository extends MySQLRepository {
/**
* Construct a {@link AccountModel} from the given parameters
* @param accountId the account id
*
* @param uuid the uuid
* @param name the name
* @param resultSet the result set
* @param ipAddress the ip address
* @param encryptedIpAddress the encrypted ip address
* @param lastLogin the last login
* @return the account
*/
private AccountModel constructAccount(UUID uuid, ResultSet resultSet) {

View File

@ -18,6 +18,8 @@ import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* This route handles everything associated with {@link AccountModel}
*
* @author Braydon
*/
@AllArgsConstructor
@ -29,6 +31,9 @@ public class AccountRoute {
private final AccountRepository accountRepository;
/**
* This path handles displaying the {@link AccountModel} with the given {@link UUID}
*/
@RestPath(path = "/account/:uuid", version = APIVersion.V1)
public AccountModel get(Request request, Response response, APIKey apiKey) throws APIException {
UUID uuid = MiscUtils.getUuid(request.params(":uuid"));

View File

@ -5,7 +5,7 @@ import spark.Response;
import zone.themcgamer.api.APIException;
import zone.themcgamer.api.APIVersion;
import zone.themcgamer.api.RestPath;
import zone.themcgamer.api.model.impl.StatusModel;
import zone.themcgamer.api.model.impl.PlayerStatusModel;
import zone.themcgamer.data.APIAccessLevel;
import zone.themcgamer.data.jedis.cache.CacheRepository;
import zone.themcgamer.data.jedis.cache.ICacheItem;
@ -19,15 +19,20 @@ import java.util.List;
import java.util.Map;
/**
* This route handles everything associated with {@link PlayerStatusModel}
*
* @author Braydon
*/
public class StatusRoute {
public class PlayerStatusRoute {
private final CacheRepository repository;
public StatusRoute() {
public PlayerStatusRoute() {
repository = RedisRepository.getRepository(CacheRepository.class).orElse(null);
}
/**
* This path handles displaying of all of the {@link PlayerStatusModel}'s
*/
@RestPath(path = "/status", version = APIVersion.V1)
public Map<String, Object> getStatuses(Request request, Response response, APIKey apiKey) throws APIException {
List<ICacheItem<?>> statuses = repository.filter(cacheItem -> cacheItem.getType() == ItemCacheType.PLAYER_STATUS);
@ -44,8 +49,11 @@ public class StatusRoute {
}};
}
/**
* This path handles displaying the {@link PlayerStatusModel} with the given name
*/
@RestPath(path = "/status/:name", version = APIVersion.V1)
public StatusModel getStatus(Request request, Response response, APIKey apiKey) throws APIException {
public PlayerStatusModel getStatus(Request request, Response response, APIKey apiKey) throws APIException {
String name = request.params(":name");
if (name == null || (name.trim().isEmpty() || name.length() > 16))
throw new APIException("Invalid username");
@ -54,7 +62,7 @@ public class StatusRoute {
.stream().findFirst().orElse(null);
if (statusCache == null)
throw new APIException("Player not found");
StatusModel model = new StatusModel(statusCache.getUuid(), statusCache.getPlayerName(), statusCache.getServer(), statusCache.getTimeJoined());
PlayerStatusModel model = new PlayerStatusModel(statusCache.getUuid(), statusCache.getPlayerName(), statusCache.getServer(), statusCache.getTimeJoined());
if (apiKey.getAccessLevel() == APIAccessLevel.STANDARD)
model.setServer("Unauthorized");
return model;

View File

@ -20,6 +20,8 @@ import java.util.List;
import java.util.Optional;
/**
* This route handles everything associated with {@link ServerGroupModel} and {@link MinecraftServerModel}
*
* @author Braydon
*/
public class ServersRoute {
@ -31,10 +33,9 @@ public class ServersRoute {
minecraftServerRepository = RedisRepository.getRepository(MinecraftServerRepository.class).orElse(null);
}
/*
Server Groups
/**
* This path handles displaying of all of the {@link ServerGroupModel}'s
*/
@RestPath(path = "/serverGroups", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV)
public List<ServerGroupModel> getGroups(Request request, Response response, APIKey apiKey) throws APIException {
List<ServerGroupModel> models = new ArrayList<>();
@ -43,6 +44,9 @@ public class ServersRoute {
return models;
}
/**
* This path handles displaying the {@link ServerGroupModel} with the given name
*/
@RestPath(path = "/serverGroup/:name", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV)
public ServerGroupModel getServerGroup(Request request, Response response, APIKey apiKey) throws APIException {
String name = request.params(":name");
@ -54,10 +58,9 @@ public class ServersRoute {
return ServerGroupModel.fromServerGroup(optionalServerGroup.get());
}
/*
Minecraft Servers
/**
* This path handles displaying of all of the {@link MinecraftServerModel}'s
*/
@RestPath(path = "/minecraftServers", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV)
public List<MinecraftServerModel> getMinecraftServers(Request request, Response response, APIKey apiKey) throws APIException {
List<MinecraftServerModel> models = new ArrayList<>();
@ -66,6 +69,9 @@ public class ServersRoute {
return models;
}
/**
* This path handles displaying the {@link MinecraftServerModel} with the given id
*/
@RestPath(path = "/minecraftServer/:id", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV)
public MinecraftServerModel getMinecraftServer(Request request, Response response, APIKey apiKey) throws APIException {
String id = request.params(":id");

View File

@ -1,7 +1,7 @@
dependencies {
implementation(project(":core"))
implementation("com.jagrosh:jda-utilities:3.0.5")
implementation("net.dv8tion:JDA:4.2.0_228")
implementation("com.jagrosh:jda-utilities:3.0.5")
}
val jar by tasks.getting(Jar::class) {

View File

@ -0,0 +1,28 @@
package zone.themcgamer.discordbot;
import java.util.Calendar;
/**
* @author Nicholas
*/
public class BotConstants {
public static final String TOKEN = "NzY1NTI5MTM2NzgxMDY2MjQ2.X4WIkQ.L7pszAdOq1cbqwyhxtr_-qBULpA";
public static final String PREFIX = ".";
public static final String OWNER_ID = "504069946528104471"; // Joel
public static final String[] BOT_ADMINS = new String[] {
"758733013579595836", // Nicholas
"504147739131641857" // Braydon
};
// Guilds
public static final String MAIN_GUILD_ID = "764609803459756093";
public static final String TEAM_GUILD_ID = "796582717956423760";
public static final String TEST_GUILD_ID = "811044415211700234";
// Default Lines
public static final String COPYRIGHT = "© McGamerZone - " + Calendar.getInstance().get(Calendar.YEAR);
// Channels
public static final String SUGGESTIONS = "802304706701426730"; // TODO: 2/15/2021 Change this to the main guild's suggestions channel when the bot is on the main guild.
}

View File

@ -1,60 +1,62 @@
package zone.themcgamer.discordbot;
import com.jagrosh.jdautilities.command.CommandClientBuilder;
import com.jagrosh.jdautilities.commons.waiter.EventWaiter;
import lombok.Getter;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.OnlineStatus;
import net.dv8tion.jda.api.entities.Activity;
import net.dv8tion.jda.api.requests.GatewayIntent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import zone.themcgamer.discordbot.commands.BotStatusCommand;
import zone.themcgamer.discordbot.command.impl.*;
import zone.themcgamer.discordbot.events.GuildMemberJoinQuitListener;
import javax.security.auth.login.LoginException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@Getter
public class MGZBot {
@Getter private static MGZBot instance;
private static final Logger LOG = LoggerFactory.getLogger(MGZBot.class);
private JDA jda;
@Getter private static JDA jda;
@Getter private static CommandClientBuilder commandClientBuilder;
@Getter private static EventWaiter eventWaiter;
@Getter private static ScheduledExecutorService executorService;
public static void main(String[] args) {
public MGZBot() {
instance = this;
long time = System.currentTimeMillis();
eventWaiter = new EventWaiter();
commandClientBuilder = new CommandClientBuilder();
commandClientBuilder.setPrefix(".");
CommandClientBuilder commandClientBuilder = new CommandClientBuilder();
commandClientBuilder.setPrefix(BotConstants.PREFIX);
commandClientBuilder.setActivity(Activity.playing("McGamerZone"));
commandClientBuilder.setStatus(OnlineStatus.DO_NOT_DISTURB);
commandClientBuilder.setOwnerId("504069946528104471");
commandClientBuilder.setCoOwnerIds("504147739131641857");
commandClientBuilder.setEmojis("<:success:789354594651209738>", "<:warning:789354594877964324>", "<:error:789354595003793408>");
commandClientBuilder.setAlternativePrefix("/");
commandClientBuilder.setStatus(OnlineStatus.ONLINE);
commandClientBuilder.setOwnerId(BotConstants.OWNER_ID);
for (String botAdmin : BotConstants.BOT_ADMINS)
commandClientBuilder.setCoOwnerIds(botAdmin);
commandClientBuilder.useHelpBuilder(false);
commandClientBuilder.addCommand(new BotStatusCommand(eventWaiter));
executorService = Executors.newScheduledThreadPool(10);
commandClientBuilder.addCommand(new SuggestCommand());
commandClientBuilder.addCommand(new SetActivityCommand());
commandClientBuilder.addCommand(new ToggleNewsRoleCommand());
commandClientBuilder.addCommand(new InviteCommand());
commandClientBuilder.addCommand(new SayCommand());
try {
jda = JDABuilder.createDefault("ODA5NjMxMzcxNzg1Nzk3NjMz.YCX5-Q.t4S8qOmhAc98DKKw9rBsPNv82xM")
.setCallbackPool(getExecutorService())
.setActivity(Activity.playing("loading..."))
jda = JDABuilder.createDefault(BotConstants.TOKEN)
.setCallbackPool(Executors.newScheduledThreadPool(10))
.setActivity(Activity.playing("Booting up..."))
.setStatus(OnlineStatus.IDLE)
.enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_EMOJIS)
.addEventListeners(eventWaiter,
commandClientBuilder.build())
.addEventListeners(
commandClientBuilder.build(),
new GuildMemberJoinQuitListener(this))
.build();
} catch (LoginException e) {
e.printStackTrace();
jda.awaitReady();
} catch (LoginException | InterruptedException ex) {
ex.printStackTrace();
}
System.out.println("Done (" + (System.currentTimeMillis() - time) + ")! For help, type \"help\" or \"?\"\n");
System.out.println("Done (" + (System.currentTimeMillis() - time) + "ms)!");
}
}
public static void main(String[] args) {
new MGZBot();
}
}

View File

@ -0,0 +1,35 @@
package zone.themcgamer.discordbot.command;
import com.jagrosh.jdautilities.command.Command;
import com.jagrosh.jdautilities.command.CommandEvent;
import zone.themcgamer.discordbot.BotConstants;
import zone.themcgamer.discordbot.guild.Guild;
import zone.themcgamer.discordbot.utilities.GuildUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
/**
* @author Nicholas
*/
public abstract class BaseCommand extends Command {
protected List<Guild> guilds; // The guilds the command can be executed in
@Override
protected void execute(CommandEvent event) {
if (!guilds.contains(GuildUtils.getGuildFromId(event.getGuild().getId())))
return;
List<String> args = new ArrayList<>();
if (event.getArgs() != null && event.getArgs().length() > 0) {
String[] split = event.getMessage().getContentRaw()
.replaceFirst("(?i)" + Pattern.quote(BotConstants.PREFIX), "")
.split("\\s+");
args = Arrays.asList(split);
}
execute(event, args);
}
protected abstract void execute(CommandEvent event, List<String> args);
}

View File

@ -0,0 +1,43 @@
package zone.themcgamer.discordbot.command.impl;
import com.jagrosh.jdautilities.command.CommandEvent;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.TextChannel;
import zone.themcgamer.discordbot.command.BaseCommand;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class InviteCommand extends BaseCommand {
public InviteCommand() {
name = "invite";
aliases = new String[]{"createinvite"};
help = "Create invite link via the bot";
guildOnly = true;
guilds = Collections.singletonList(zone.themcgamer.discordbot.guild.Guild.MAIN);
}
@Override
protected void execute(CommandEvent event, List<String> args) {
Guild guild = event.getGuild();
TextChannel textChannelById = guild.getTextChannelById(791015530001596456L);
if (textChannelById == null)
return;
textChannelById.createInvite()
.timeout(1, TimeUnit.DAYS)
.setTemporary(true).queue(inviteLink -> {
event.getMember().getUser().openPrivateChannel().queue(privateChannel -> {
privateChannel.sendMessage("I have generated an invite link for you! This invite link will work for 24 hours! " + inviteLink.getUrl()).queue();
event.reply("Check your dm's!");
}, error -> {
event.replyError("Could not sent you a dm!");
}); }, error -> {
event.replyError("Coulnd't create an invite link due an error!");
});
}
}

View File

@ -0,0 +1,41 @@
package zone.themcgamer.discordbot.command.impl;
import com.jagrosh.jdautilities.command.CommandEvent;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.Permission;
import zone.themcgamer.discordbot.command.BaseCommand;
import zone.themcgamer.discordbot.guild.Guild;
import zone.themcgamer.discordbot.utilities.EmbedUtils;
import zone.themcgamer.discordbot.utilities.MessageUtils;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class SayCommand extends BaseCommand {
public SayCommand() {
name = "say";
aliases = new String[]{"announce"};
help = "Announce something in an embed format.";
arguments = "<title> <description>";
userPermissions = new Permission[] { Permission.ADMINISTRATOR };
guildOnly = true;
guilds = Arrays.asList(Guild.MAIN, Guild.TEAM, Guild.TEST);
}
@Override
protected void execute(CommandEvent event, List<String> args) {
if (args.size() < 1) {
MessageUtils.sendUsageMessage(event.getTextChannel(),this);
return;
}
//TODO a way to add images, and such to the embeds.
String description = args.stream().skip(2).collect(Collectors.joining(" "));
EmbedBuilder embedBuilder = EmbedUtils.defaultEmbed();
embedBuilder.setTitle(args.get(1).replace("_", " "));
embedBuilder.setDescription(description);
event.getChannel().sendMessage(embedBuilder.build()).queue();
}
}

View File

@ -0,0 +1,45 @@
package zone.themcgamer.discordbot.command.impl;
import com.jagrosh.jdautilities.command.CommandEvent;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Activity;
import zone.themcgamer.discordbot.BotConstants;
import zone.themcgamer.discordbot.MGZBot;
import zone.themcgamer.discordbot.command.BaseCommand;
import zone.themcgamer.discordbot.guild.Guild;
import zone.themcgamer.discordbot.utilities.EmbedUtils;
import zone.themcgamer.discordbot.utilities.MessageUtils;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Nicholas
*/
public class SetActivityCommand extends BaseCommand {
public SetActivityCommand() {
name = "setactivity";
help = "Set the bot activity.";
arguments = "<message>";
userPermissions = new Permission[] { Permission.ADMINISTRATOR };
guildOnly = true;
guilds = Arrays.asList(Guild.MAIN, Guild.TEAM, Guild.TEST);
}
@Override
protected void execute(CommandEvent event, List<String> args) {
if (args.size() < 1) {
MessageUtils.sendUsageMessage(event.getTextChannel(),this);
return;
}
String activity = args.stream().skip(1).collect(Collectors.joining(" "));
MGZBot.getInstance().getJda().getPresence().setActivity(Activity.playing(activity));
event.getChannel().sendMessage(EmbedUtils.successEmbed()
.setThumbnail(event.getAuthor().getAvatarUrl())
.setTitle("Activity updated!")
.appendDescription(event.getAuthor().getAsTag() + " updated the bot activity to \"" + activity + "\".")
.build()
).queue();
}
}

View File

@ -0,0 +1,56 @@
package zone.themcgamer.discordbot.command.impl;
import com.jagrosh.jdautilities.command.CommandEvent;
import net.dv8tion.jda.api.entities.TextChannel;
import zone.themcgamer.discordbot.BotConstants;
import zone.themcgamer.discordbot.MGZBot;
import zone.themcgamer.discordbot.command.BaseCommand;
import zone.themcgamer.discordbot.guild.Guild;
import zone.themcgamer.discordbot.utilities.EmbedUtils;
import zone.themcgamer.discordbot.utilities.MessageUtils;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Nicholas
*/
public class SuggestCommand extends BaseCommand {
public SuggestCommand() {
name = "suggest";
aliases = new String[]{"suggestion"};
help = "Share a suggestion!";
arguments = "<suggestion>";
guildOnly = true;
guilds = Collections.singletonList(Guild.MAIN);
}
@Override
protected void execute(CommandEvent event, List<String> args) {
if (args.size() < 1) {
MessageUtils.sendUsageMessage(event.getTextChannel(),this);
return;
}
TextChannel channel = MGZBot.getInstance().getJda().getTextChannelById(BotConstants.SUGGESTIONS);
if (channel == null)
return;
String suggestion = args.stream().skip(1).collect(Collectors.joining(" "));
if (suggestion.length() < 120) {
event.getChannel().sendMessage(EmbedUtils.errorEmbed()
.appendDescription("Your suggestion is too short. Suggestions must be at least 120 characters.")
.build()
).queue();
return;
}
channel.sendMessage(EmbedUtils.defaultEmbed()
.setThumbnail(event.getAuthor().getAvatarUrl())
.setTitle(event.getAuthor().getAsTag() + " has a suggestion!")
.appendDescription(suggestion)
.build()
).queue(message -> {
message.addReaction("").queue();
message.addReaction("").queue();
});
}
}

View File

@ -0,0 +1,47 @@
package zone.themcgamer.discordbot.command.impl;
import com.jagrosh.jdautilities.command.CommandEvent;
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.entities.Role;
import zone.themcgamer.discordbot.command.BaseCommand;
import zone.themcgamer.discordbot.utilities.EmbedUtils;
import java.util.Collections;
import java.util.List;
public class ToggleNewsRoleCommand extends BaseCommand {
public ToggleNewsRoleCommand() {
name = "togglenews";
aliases = new String[]{"news"};
help = "Turn on or off news role.";
guildOnly = true;
guilds = Collections.singletonList(zone.themcgamer.discordbot.guild.Guild.MAIN);
}
@Override
protected void execute(CommandEvent event, List<String> args) {
Member member = event.getMember();
Guild guild = event.getGuild();
if (member == null)
return;
Role newsRole = guild.getRoleById(812440883898875914L);
if (newsRole == null)
return;
if (member.getRoles().contains(newsRole)) {
guild.removeRoleFromMember(member.getIdLong(), newsRole).queue();
EmbedBuilder embedBuilder = EmbedUtils.successEmbed();
embedBuilder.setDescription("You have successfully removed the " + newsRole.getAsMention() + " role from your account!");
event.reply(embedBuilder.build());
} else {
guild.addRoleToMember(member.getIdLong(), newsRole).queue();
EmbedBuilder embedBuilder = EmbedUtils.successEmbed();
embedBuilder.setDescription("You have successfully added the " + newsRole.getAsMention() + " role to your account!");
event.reply(embedBuilder.build());
}
}
}

View File

@ -1,45 +0,0 @@
package zone.themcgamer.discordbot.commands;
import com.jagrosh.jdautilities.command.Command;
import com.jagrosh.jdautilities.command.CommandEvent;
import com.jagrosh.jdautilities.doc.standard.CommandInfo;
import com.jagrosh.jdautilities.doc.standard.Error;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import java.util.List;
import java.util.UUID;
@CommandInfo(
name = {"account", "profile"},
usage = "<name>",
description = "View your own account")
@Error(prefix = "Account » ",
value = "An error occured in this command, please contact an administrator.")
public class AccountCommand extends Command {
@Override
protected void execute(CommandEvent commandEvent) {
Message message = commandEvent.getMessage();
String[] args = message.getContentDisplay().split(" ");
UUID player;
List<Member> mentioned = message.getMentionedMembers();
if (args.length > 1) {
Member target = mentioned.get(0);
//(!mentioned.isEmpty()) ? mentioned.get(0) : args[0];
//TODO check if account is linked
player = UUID.randomUUID(); //"SET THE UUID";
} else {
//TODO your own account if you did not have more than 1 args.
player = UUID.randomUUID(); //"YOUR OWN UUID";
}
//TODO sent the message with player information
}
}

View File

@ -1,53 +0,0 @@
package zone.themcgamer.discordbot.commands;
import com.jagrosh.jdautilities.command.Command;
import com.jagrosh.jdautilities.command.CommandEvent;
import com.jagrosh.jdautilities.commons.waiter.EventWaiter;
import com.sun.management.OperatingSystemMXBean;
import net.dv8tion.jda.api.EmbedBuilder;
import java.awt.*;
import java.lang.management.ManagementFactory;
import java.text.DecimalFormat;
import java.time.Instant;
import java.util.Date;
public class BotStatusCommand extends Command {
public BotStatusCommand(EventWaiter waiter) {
this.name = "botstatus";
//this.aliases = new String[]{"bot"};
this.help = "view status of thee bot.";
this.ownerCommand = true;
this.guildOnly = false;
this.category = new Category("Administration");
}
@Override
protected void execute(CommandEvent commandEvent) {
String title = ":information_source: Stats of **"+ commandEvent.getJDA().getSelfUser().getName()+"**:";
String os = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class).getName();
String arch = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class).getArch();
String version = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class).getVersion();
os = os+" "+arch+" "+version;
int cpus = Runtime.getRuntime().availableProcessors();
String processCpuLoad = new DecimalFormat("###.###%").format(ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class).getProcessCpuLoad());
String systemCpuLoad = new DecimalFormat("###.###%").format(ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class).getSystemCpuLoad());
long ramUsed = ((Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()) / (1024 * 1024));
EmbedBuilder builder = new EmbedBuilder();
builder.setTitle(title);
builder.addField(":desktop: OS:", os, true);
builder.addField(":computer: RAM usage:", ramUsed+"MB", true);
builder.addField(":gear: CPU usage:", processCpuLoad + "/" + systemCpuLoad + " (" + cpus + " Cores)", true);
builder.addField(":map: Guilds:", "" + commandEvent.getJDA().getGuilds().size() , true);
builder.addField(":speech_balloon: Text Channels:", "" + commandEvent.getJDA().getTextChannels().size(), true);
builder.addField(":speaker: Voice Channels:", "" + commandEvent.getJDA().getVoiceChannels().size(), true);
builder.addField(":bust_in_silhouette: Users:", "" + commandEvent.getJDA().getUsers().size(), true);
builder.setColor(Color.RED);
builder.setFooter("© McGamerZone - " + Date.from(Instant.now()).getYear(), commandEvent.getJDA().getSelfUser().getEffectiveAvatarUrl());
commandEvent.getChannel().sendMessage(builder.build()).queue();
}
}

View File

@ -1,53 +0,0 @@
package zone.themcgamer.discordbot.commands;
import com.jagrosh.jdautilities.command.Command;
import com.jagrosh.jdautilities.command.CommandEvent;
import com.jagrosh.jdautilities.commons.waiter.EventWaiter;
import com.sun.management.OperatingSystemMXBean;
import net.dv8tion.jda.api.EmbedBuilder;
import java.awt.*;
import java.lang.management.ManagementFactory;
import java.text.DecimalFormat;
import java.time.Instant;
import java.util.Date;
public class StatusCommand extends Command {
public StatusCommand(EventWaiter waiter) {
this.name = "setstatus";
//this.aliases = new String[]{"bot"};
this.help = "view status of thee bot.";
this.ownerCommand = true;
this.guildOnly = false;
this.category = new Category("Administration");
}
@Override
protected void execute(CommandEvent commandEvent) {
String title = ":information_source: Stats of **"+ commandEvent.getJDA().getSelfUser().getName()+"**:";
String os = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class).getName();
String arch = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class).getArch();
String version = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class).getVersion();
os = os+" "+arch+" "+version;
int cpus = Runtime.getRuntime().availableProcessors();
String processCpuLoad = new DecimalFormat("###.###%").format(ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class).getProcessCpuLoad());
String systemCpuLoad = new DecimalFormat("###.###%").format(ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class).getSystemCpuLoad());
long ramUsed = ((Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()) / (1024 * 1024));
EmbedBuilder builder = new EmbedBuilder();
builder.setTitle(title);
builder.addField(":desktop: OS:", os, true);
builder.addField(":computer: RAM usage:", ramUsed+"MB", true);
builder.addField(":gear: CPU usage:", processCpuLoad + "/" + systemCpuLoad + " (" + cpus + " Cores)", true);
builder.addField(":map: Guilds:", "" + commandEvent.getJDA().getGuilds().size() , true);
builder.addField(":speech_balloon: Text Channels:", "" + commandEvent.getJDA().getTextChannels().size(), true);
builder.addField(":speaker: Voice Channels:", "" + commandEvent.getJDA().getVoiceChannels().size(), true);
builder.addField(":bust_in_silhouette: Users:", "" + commandEvent.getJDA().getUsers().size(), true);
builder.setColor(Color.RED);
builder.setFooter("© McGamerZone - " + Date.from(Instant.now()).getYear(), commandEvent.getJDA().getSelfUser().getEffectiveAvatarUrl());
commandEvent.getChannel().sendMessage(builder.build()).queue();
}
}

View File

@ -1,35 +0,0 @@
package zone.themcgamer.discordbot.commands;
import com.jagrosh.jdautilities.command.Command;
import com.jagrosh.jdautilities.command.CommandEvent;
import com.jagrosh.jdautilities.doc.standard.CommandInfo;
import com.jagrosh.jdautilities.doc.standard.Error;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
@CommandInfo(
name = {"mycommand", "coolcommand"},
description = "Use this command if you are cool! B)",
requirements = {"The bot has all necessary permissions."})
@Error(
prefix = "Test »",
value = "Rip this command had an error.",
response = "Invalid page number")
public class Test extends Command {
@Override
protected void execute(CommandEvent commandEvent) {
}
private OkHttpClient clientWithApiKey(String apiKey) {
return new OkHttpClient.Builder()
.addInterceptor(chain -> {
Request originalRequest = chain.request();
HttpUrl newUrl = originalRequest.url().newBuilder()
.addQueryParameter("key", apiKey).build();
Request request = originalRequest.newBuilder().url(newUrl).build();
return chain.proceed(request);
}).build();
}
}

View File

@ -0,0 +1,66 @@
package zone.themcgamer.discordbot.events;
import lombok.RequiredArgsConstructor;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import zone.themcgamer.discordbot.BotConstants;
import zone.themcgamer.discordbot.MGZBot;
import zone.themcgamer.discordbot.utilities.EmbedUtils;
import javax.annotation.Nonnull;
@RequiredArgsConstructor
public class GuildMemberJoinQuitListener extends ListenerAdapter {
private final MGZBot mgzBot;
@Override
public void onGuildMemberJoin(@Nonnull GuildMemberJoinEvent event) {
User user = event.getUser();
Guild guild = event.getGuild();
if (user.isBot())
return;
if (guild.getId().equals(BotConstants.MAIN_GUILD_ID)) {
Role memberRole = guild.getRoleById(793672609395900446L);
if (memberRole != null)
guild.addRoleToMember(user.getId(), memberRole).queue();
Role newsRole = guild.getRoleById(812440883898875914L);
if (newsRole != null)
guild.addRoleToMember(user.getId(), newsRole).queue();
user.openPrivateChannel().queue(privateChannel -> {
EmbedBuilder embedBuilder = EmbedUtils.defaultEmbed();
embedBuilder.setThumbnail(mgzBot.getJda().getSelfUser().getAvatarUrl());
embedBuilder.setDescription("Welcome to **McGamerZone** you have received News & Member role.");
privateChannel.sendMessage(embedBuilder.build()).queue();
}, error -> {
TextChannel textChannelById = guild.getTextChannelById(767396615299923998L);
if (textChannelById != null)
textChannelById.sendMessage(user.getAsMention() + ", I could not sent a message to you due you have private messages disabled!").queue();
});
TextChannel textChannelById = guild.getTextChannelById(812453030405996564L);
if (textChannelById == null)
return;
EmbedBuilder embedBuilder = EmbedUtils.defaultEmbed();
embedBuilder.setTitle("Welcome to McGamerZone, " + user.getAsTag());
embedBuilder.setThumbnail(user.getAvatarUrl());
embedBuilder.setDescription("This is the official Discord server for McGamerZone Minecraft server." +
"We are a fun Server that is focused on creativity, community-building, and keeping to the" +
"core of the game itself. Our goal here; is to maintain a friendly, fun, " +
"and equal community for anyone and everyone that joins in and " +
"give the og players of MGZ the nostalgia feeling back!");
embedBuilder.setTimestamp(event.getMember().getTimeJoined());
embedBuilder.setFooter("Joined at » ");
textChannelById.sendMessage(user.getAsMention()).queue(message -> message.delete().queue());
textChannelById.sendMessage(embedBuilder.build()).queue(message -> {
message.addReaction(":MGZ_Icon_M:791020631042162729").queue();
});
}
}
}

View File

@ -0,0 +1,8 @@
package zone.themcgamer.discordbot.guild;
/**
* @author Nicholas
*/
public enum Guild {
MAIN, TEAM, TEST
}

View File

@ -0,0 +1,30 @@
package zone.themcgamer.discordbot.utilities;
import net.dv8tion.jda.api.EmbedBuilder;
import zone.themcgamer.discordbot.BotConstants;
import zone.themcgamer.discordbot.MGZBot;
import java.awt.*;
import java.time.LocalDateTime;
public class EmbedUtils {
public static EmbedBuilder successEmbed() {
return defaultEmbed().setColor(Color.decode("#41bc7f"));
}
public static EmbedBuilder errorEmbed() {
return defaultEmbed().setTitle("Oops!")
.setColor(Color.decode("#d74742"));
}
public static EmbedBuilder warnEmbed() {
return defaultEmbed().setColor(Color.decode("#f85b2e"));
}
public static EmbedBuilder defaultEmbed() {
return new EmbedBuilder()
.setColor(Color.decode("#1DD0D5"))
.setTimestamp(LocalDateTime.now())
.setFooter(BotConstants.COPYRIGHT, MGZBot.getInstance().getJda().getSelfUser().getEffectiveAvatarUrl());
}
}

View File

@ -0,0 +1,21 @@
package zone.themcgamer.discordbot.utilities;
import zone.themcgamer.discordbot.BotConstants;
import zone.themcgamer.discordbot.guild.Guild;
/**
* @author Nicholas
*/
public class GuildUtils {
public static Guild getGuildFromId(String id) {
switch (id) {
case BotConstants.MAIN_GUILD_ID:
return Guild.MAIN;
case BotConstants.TEAM_GUILD_ID:
return Guild.TEAM;
case BotConstants.TEST_GUILD_ID:
return Guild.TEST;
}
return null;
}
}

View File

@ -0,0 +1,15 @@
package zone.themcgamer.discordbot.utilities;
import net.dv8tion.jda.api.entities.TextChannel;
import zone.themcgamer.discordbot.BotConstants;
import zone.themcgamer.discordbot.command.BaseCommand;
public class MessageUtils {
public static void sendUsageMessage(TextChannel textChannel, BaseCommand command) {
textChannel.sendMessage(EmbedUtils.errorEmbed()
.appendDescription("Usage: " + BotConstants.PREFIX + command.getName() + " " + command.getArguments())
.build()
).queue();
}
}

View File

@ -169,6 +169,8 @@ public class PlayerListener implements Listener {
@EventHandler
private void onBlockInteract(PlayerInteractEvent event) {
if (event.getPlayer().getGameMode() == GameMode.CREATIVE)
return;
Block block = event.getClickedBlock();
if (block == null)
return;