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

@ -1,9 +1,10 @@
# Project Structure # Project Structure
- **Commons**: Commons is common libraries and/or utilities that are shared across the network. - **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. - **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. - **ServerController**: This will dynamically start and stop servers on demand.
- **Proxy**: The proxy will handle server balancing and player caching. - **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. - **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 - **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. - **Hub**: This is pretty self-explanatory. Any Hub related things will go here.

@ -11,8 +11,8 @@ import zone.themcgamer.api.model.ModelSerializer;
import zone.themcgamer.api.model.impl.*; import zone.themcgamer.api.model.impl.*;
import zone.themcgamer.api.repository.AccountRepository; import zone.themcgamer.api.repository.AccountRepository;
import zone.themcgamer.api.route.AccountRoute; import zone.themcgamer.api.route.AccountRoute;
import zone.themcgamer.api.route.PlayerStatusRoute;
import zone.themcgamer.api.route.ServersRoute; import zone.themcgamer.api.route.ServersRoute;
import zone.themcgamer.api.route.StatusRoute;
import zone.themcgamer.data.APIAccessLevel; import zone.themcgamer.data.APIAccessLevel;
import zone.themcgamer.data.jedis.JedisController; import zone.themcgamer.data.jedis.JedisController;
import zone.themcgamer.data.jedis.data.APIKey; import zone.themcgamer.data.jedis.data.APIKey;
@ -57,12 +57,12 @@ public class API {
addModel(NodeModel.class); addModel(NodeModel.class);
addModel(ServerGroupModel.class); addModel(ServerGroupModel.class);
addModel(AccountModel.class); addModel(AccountModel.class);
addModel(StatusModel.class); addModel(PlayerStatusModel.class);
// Adding the routes // Adding the routes
addRoute(new ServersRoute()); addRoute(new ServersRoute());
addRoute(new AccountRoute(accountRepository)); addRoute(new AccountRoute(accountRepository));
addRoute(new StatusRoute()); addRoute(new PlayerStatusRoute());
// 404 Handling // 404 Handling
Spark.notFound((request, response) -> { Spark.notFound((request, response) -> {
@ -110,6 +110,8 @@ public class API {
System.out.println("Handling incoming request from \"" + request.ip() + "\" using path \"" + request.pathInfo() + "\""); System.out.println("Handling incoming request from \"" + request.ip() + "\" using path \"" + request.pathInfo() + "\"");
APIKey key = new APIKey(UUID.randomUUID().toString(), APIAccessLevel.STANDARD); 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) { if (requiresAuthentication) {
String apiKey = request.headers("key"); String apiKey = request.headers("key");
if (apiKey == null) if (apiKey == null)
@ -133,7 +135,9 @@ public class API {
if (method.getParameterTypes().length != 3) if (method.getParameterTypes().length != 3)
throw new APIException("Invalid route defined"); throw new APIException("Invalid route defined");
Object object = method.invoke(entry.getKey(), request, response, key); 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 (object instanceof IModel) {
if (models.contains(object.getClass())) if (models.contains(object.getClass()))
jsonObject.add("value", gson.toJsonTree(((IModel) object).toMap(), HashMap.class)); 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)); jsonObject.add("value", gson.toJsonTree(object, HashMap.class));
else jsonObject.addProperty("value", object.toString()); else jsonObject.addProperty("value", object.toString());
} catch (Throwable ex) { } 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) if (ex instanceof InvocationTargetException)
ex = ex.getCause(); ex = ex.getCause();
String message = ex.getLocalizedMessage(); 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())) if (message == null || (message.trim().isEmpty()))
message = ex.getClass().getSimpleName(); message = ex.getClass().getSimpleName();
jsonObject.addProperty("success", "false"); jsonObject.addProperty("success", "false");
jsonObject.addProperty("error", message); jsonObject.addProperty("error", message);
// If the caught exception is not an API exception, print the stacktrace
if (!(ex instanceof APIException)) { if (!(ex instanceof APIException)) {
System.err.println("The route \"" + entry.getKey().getClass().getSimpleName() + "\" raised an exception:"); System.err.println("The route \"" + entry.getKey().getClass().getSimpleName() + "\" raised an exception:");
ex.printStackTrace(); 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) { private static void addModel(Class<? extends IModel> modelClass) {
models.add(modelClass); models.add(modelClass);
} }
/**
* Adding a route
*
* @param object the instance of the route to add
*/
private static void addRoute(Object object) { private static void addRoute(Object object) {
List<Method> methods = routes.getOrDefault(object, new ArrayList<>()); List<Method> methods = routes.getOrDefault(object, new ArrayList<>());
for (Method method : object.getClass().getMethods()) { for (Method method : object.getClass().getMethods()) {

@ -1,16 +1,14 @@
package zone.themcgamer.api; package zone.themcgamer.api;
import lombok.NoArgsConstructor;
/** /**
* This {@link RuntimeException} gets thrown when there is a problem handling a {@link RestPath}
*
* @author Braydon * @author Braydon
*/ */
@NoArgsConstructor
public class APIException extends RuntimeException { 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. * Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a * The cause is not initialized, and may subsequently be initialized by a

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

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

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

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

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

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

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

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

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

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

@ -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.
}

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

@ -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);
}

@ -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!");
});
}
}

@ -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();
}
}

@ -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();
}
}

@ -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();
});
}
}

@ -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());
}
}
}

@ -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
}
}

@ -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();
}
}

@ -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();
}
}

@ -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();
}
}

@ -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();
});
}
}
}

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

@ -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());
}
}

@ -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;
}
}

@ -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();
}
}

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