diff --git a/.classpath b/.classpath index 58ad8b1..720c4f0 100644 --- a/.classpath +++ b/.classpath @@ -12,6 +12,12 @@ + + + + + + diff --git a/.gitignore b/.gitignore index 5cede7c..9108392 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ test_server/ .gradle build/ server/ +bin/ diff --git a/.project b/.project index 765ab9b..28c5951 100644 --- a/.project +++ b/.project @@ -1,6 +1,6 @@ - civil-core-civilcore + CivilCore Project civilcore created by Buildship. diff --git a/bin/main/paper-plugin.yml b/bin/main/paper-plugin.yml index 3f63ddd..5db0a58 100644 --- a/bin/main/paper-plugin.yml +++ b/bin/main/paper-plugin.yml @@ -1,5 +1,5 @@ api-version: "1.21" -name: civil-core +name: CivilCore version: 0.1.0 main: rip.iwakura.civil.Core authors: diff --git a/bin/main/rip/iwakura/civil/Core.class b/bin/main/rip/iwakura/civil/Core.class index 98b6222..4c18cb3 100644 Binary files a/bin/main/rip/iwakura/civil/Core.class and b/bin/main/rip/iwakura/civil/Core.class differ diff --git a/build.gradle.kts b/build.gradle.kts index 59ec723..e1607bc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,7 +3,7 @@ version = "0.1.0" plugins { java - id("com.github.johnrengelman.shadow") version "7.1.2" + id("com.gradleup.shadow") version "8.3.6" id("de.eldoria.plugin-yml.paper") version "0.7.1" } @@ -21,15 +21,20 @@ paper { apiVersion = "1.21" } -tasks.withType { - val isDebug = providers.gradleProperty("isDebug") - if (isDebug.isPresent()) { - destinationDirectory.set(file(isDebug)) +tasks { + register("copyToServer") { + from(shadowJar) + destinationDir = File("server/plugins") + } + build { + dependsOn(shadowJar) } } dependencies { compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT") + implementation("com.j256.ormlite", "ormlite-jdbc", "6.1") + implementation("org.postgresql", "postgresql", "42.7.5") library("com.google.code.gson", "gson", "2.10.1") // All platform plugins } diff --git a/build.sh b/build.sh index 5e2b430..1404b4f 100644 --- a/build.sh +++ b/build.sh @@ -5,6 +5,6 @@ catch () { exit 1 } -./gradlew build -PisDebug=./server/plugins || catch +./gradlew clean build copyToServer || catch cd server && java -jar server.jar -nogui && cd .. diff --git a/settings.gradle.kts b/settings.gradle.kts index b790ed4..82d9ae2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,4 +10,4 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" } -rootProject.name = "civil-core" +rootProject.name = "CivilCore" diff --git a/src/main/java/rip/iwakura/civil/Core.java b/src/main/java/rip/iwakura/civil/Core.java index b5cdd84..c04addb 100644 --- a/src/main/java/rip/iwakura/civil/Core.java +++ b/src/main/java/rip/iwakura/civil/Core.java @@ -1,10 +1,41 @@ package rip.iwakura.civil; +import java.sql.SQLException; +import java.util.logging.Level; + +import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; +import rip.iwakura.civil.events.ChatHandler; +import rip.iwakura.civil.commands.Team; +import rip.iwakura.civil.events.JoinHandler; + public class Core extends JavaPlugin { + public Database database; + @Override public void onEnable() { getLogger().info("Hello world! We are booting up..."); + + saveDefaultConfig(); + + try { + this.database = new Database(getConfig().getString("database.url")); + } catch (SQLException e) { + getLogger().log(Level.SEVERE, e.getMessage()); + Bukkit.getPluginManager().disablePlugin(this); + + return; + } + + Team teamCommand = new Team(database); + + this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> { + commands.registrar().register(teamCommand.getCommand()); + }); + + getServer().getPluginManager().registerEvents(new JoinHandler(database), this); + getServer().getPluginManager().registerEvents(new ChatHandler(this), this); } } diff --git a/src/main/java/rip/iwakura/civil/Database.java b/src/main/java/rip/iwakura/civil/Database.java new file mode 100644 index 0000000..6cabcb0 --- /dev/null +++ b/src/main/java/rip/iwakura/civil/Database.java @@ -0,0 +1,83 @@ +package rip.iwakura.civil; + +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + +import org.apache.logging.log4j.LogManager; +import org.bukkit.entity.Player; + +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.jdbc.JdbcConnectionSource; +import com.j256.ormlite.logger.LoggerFactory; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.TableUtils; + +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import rip.iwakura.civil.types.CivilPlayer; +import rip.iwakura.civil.types.CivilTeam; + +public class Database { + private final Dao playerDao; + private final Dao teamDao; + private ConnectionSource connectionSource; + + public Database(String uri) throws SQLException { + connectionSource = new JdbcConnectionSource(uri); + + + TableUtils.createTableIfNotExists(connectionSource, CivilPlayer.class); + TableUtils.createTableIfNotExists(connectionSource, CivilTeam.class); + + playerDao = DaoManager.createDao(connectionSource, CivilPlayer.class); + teamDao = DaoManager.createDao(connectionSource, CivilTeam.class); + } + + public void createPlayer(Player p) throws SQLException { + playerDao.create( + new CivilPlayer(p.getUniqueId(), p.getName()) + ); + } + + public void createTeam(String name, String prefix) throws SQLException { + teamDao.create( + new CivilTeam(name, prefix) + ); + } + + public void joinTeam(Player p, CivilTeam team) throws SQLException { + CivilPlayer civilPlayer = playerDao.queryForId(p.getUniqueId()); + civilPlayer.setTeam(team); + playerDao.update(civilPlayer); + } + + public void joinTeam(CivilPlayer p, CivilTeam team) throws SQLException { + p.setTeam(team); + playerDao.update(p); + } + + public CivilTeam getTeam(String team) throws SQLException { + return teamDao.queryForId(team); + } + + public List getAllTeams() throws SQLException { + return teamDao.queryForAll(); + } + + public CivilPlayer getPlayer(String name) throws SQLException { + return playerDao.queryBuilder().where().eq("name", name).queryForFirst(); + } + + public CivilPlayer getPlayer(UUID uuid) throws SQLException { + return playerDao.queryForId(uuid); + } + + public CivilPlayer getPlayer(Player p) throws SQLException { + return playerDao.queryForId(p.getUniqueId()); + } + + public List getAllPlayers() throws SQLException { + return playerDao.queryForAll(); + } +} diff --git a/src/main/java/rip/iwakura/civil/commands/PlayerArgument.java b/src/main/java/rip/iwakura/civil/commands/PlayerArgument.java new file mode 100644 index 0000000..0979be7 --- /dev/null +++ b/src/main/java/rip/iwakura/civil/commands/PlayerArgument.java @@ -0,0 +1,77 @@ +package rip.iwakura.civil.commands; + +import java.sql.SQLException; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.bukkit.entity.Player; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import io.papermc.paper.command.brigadier.MessageComponentSerializer; +import io.papermc.paper.command.brigadier.argument.CustomArgumentType; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import rip.iwakura.civil.types.CivilPlayer; +import rip.iwakura.civil.Database; + +/** + * PlayerArgument + */ +public class PlayerArgument implements CustomArgumentType.Converted { + private Database database; + + public PlayerArgument(Database database) { + this.database = database; + } + + @Override + public CivilPlayer convert(String playerName) throws CommandSyntaxException { + try { + CivilPlayer civilPlayer = database.getPlayer(playerName); + + if (civilPlayer == null) { + final Message message = MessageComponentSerializer.message() + .serialize(Component.text(playerName + " doesn't exist!", NamedTextColor.RED)); + throw new CommandSyntaxException(new SimpleCommandExceptionType(message), message); + } + + return civilPlayer; + + } catch (SQLException e) { + final Message message = MessageComponentSerializer.message() + .serialize(Component.text("Uh oh, an error occured!", NamedTextColor.RED)); + throw new CommandSyntaxException(new SimpleCommandExceptionType(message), message); + } + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + try { + List players = database.getAllPlayers(); + + for (CivilPlayer player : players) { + String name = player.getName(); + + if (name.toLowerCase().startsWith(builder.getRemainingLowerCase())) { + builder.suggest(name); + } + } + } catch (SQLException e) { + } + + return builder.buildFuture(); + } + + @Override + public ArgumentType getNativeType() { + return StringArgumentType.word(); + } +} diff --git a/src/main/java/rip/iwakura/civil/commands/Team.java b/src/main/java/rip/iwakura/civil/commands/Team.java new file mode 100644 index 0000000..3bfb7c8 --- /dev/null +++ b/src/main/java/rip/iwakura/civil/commands/Team.java @@ -0,0 +1,79 @@ +package rip.iwakura.civil.commands; + +import java.sql.SQLException; + +import javax.xml.crypto.Data; + +import org.bukkit.entity.Player; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.tree.LiteralCommandNode; + +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import rip.iwakura.civil.Database; +import rip.iwakura.civil.types.*; + +public class Team { + private Database database; + + public Team(Database database) { + this.database = database; + } + + private LiteralArgumentBuilder createTeam() { + return Commands.literal("create") + .then( + Commands.argument("name", StringArgumentType.string()) + .then( + Commands.argument("prefix", StringArgumentType.string()) + .executes(ctx -> { + String name = StringArgumentType.getString(ctx, "name"); + String prefix = StringArgumentType.getString(ctx, "prefix"); + + try { + database.createTeam(name, prefix); + return Command.SINGLE_SUCCESS; + } catch (SQLException e) { + ctx.getSource().getSender().sendMessage( + Component.text(e.getMessage(), NamedTextColor.RED)); + return 0; + } + }))); + } + + // Add a player to a team. + private LiteralArgumentBuilder joinTeam() { + return Commands.literal("add") + .then( + Commands.argument("player", new PlayerArgument(database)) + .then( + Commands.argument("team", new TeamArgument(database)) + .executes(ctx -> { + CivilTeam civilTeam = ctx.getArgument("team", CivilTeam.class); + CivilPlayer civilPlayer = ctx.getArgument("player", + CivilPlayer.class); + + try { + database.joinTeam(civilPlayer, civilTeam); + return Command.SINGLE_SUCCESS; + } catch (SQLException e) { + ctx.getSource().getSender().sendMessage( + Component.text(e.getMessage(), NamedTextColor.RED)); + return 0; + } + }))); + }; + + public LiteralCommandNode getCommand() { + return Commands.literal("team") + .then(createTeam()) + .then(joinTeam()).build(); + } + +} diff --git a/src/main/java/rip/iwakura/civil/commands/TeamArgument.java b/src/main/java/rip/iwakura/civil/commands/TeamArgument.java new file mode 100644 index 0000000..3a9988a --- /dev/null +++ b/src/main/java/rip/iwakura/civil/commands/TeamArgument.java @@ -0,0 +1,75 @@ +package rip.iwakura.civil.commands; + +import java.sql.SQLException; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import com.mojang.brigadier.Message; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import io.papermc.paper.command.brigadier.MessageComponentSerializer; +import io.papermc.paper.command.brigadier.argument.CustomArgumentType; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import rip.iwakura.civil.types.CivilTeam; +import rip.iwakura.civil.Database; + +/** + * TeamArgument + */ +public class TeamArgument implements CustomArgumentType.Converted { + private Database database; + + public TeamArgument(Database database) { + this.database = database; + } + + @Override + public CivilTeam convert(String teamName) throws CommandSyntaxException { + try { + CivilTeam civilTeam = database.getTeam(teamName); + + if (civilTeam == null) { + final Message message = MessageComponentSerializer.message() + .serialize(Component.text(teamName + " doesn't exist!", NamedTextColor.RED)); + throw new CommandSyntaxException(new SimpleCommandExceptionType(message), message); + } + + return civilTeam; + + } catch (SQLException e) { + final Message message = MessageComponentSerializer.message() + .serialize(Component.text("Uh oh, an error occured!", NamedTextColor.RED)); + throw new CommandSyntaxException(new SimpleCommandExceptionType(message), message); + } + } + + @Override + public CompletableFuture listSuggestions(CommandContext ctx, SuggestionsBuilder builder) { + try { + List teams = database.getAllTeams(); + + for (CivilTeam team : teams) { + String name = team.getName(); + + if (name.toLowerCase().startsWith(builder.getRemainingLowerCase())) { + builder.suggest(name); + } + } + } catch (SQLException e) { + } + + return builder.buildFuture(); + } + + @Override + public ArgumentType getNativeType() { + return StringArgumentType.string(); + } +} diff --git a/src/main/java/rip/iwakura/civil/events/ChatHandler.java b/src/main/java/rip/iwakura/civil/events/ChatHandler.java new file mode 100644 index 0000000..2a6bda1 --- /dev/null +++ b/src/main/java/rip/iwakura/civil/events/ChatHandler.java @@ -0,0 +1,51 @@ +package rip.iwakura.civil.events; + +import java.sql.SQLException; +import java.util.logging.Level; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import io.papermc.paper.chat.ChatRenderer; +import io.papermc.paper.event.player.AsyncChatEvent; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import rip.iwakura.civil.Core; +import rip.iwakura.civil.Database; + +public class ChatHandler implements Listener, ChatRenderer { + private Core core; + private Database database; + + public ChatHandler(Core core) { + this.core = core; + this.database = core.database; + } + + @EventHandler + public void chatHandler(AsyncChatEvent event) { + event.renderer(this); + } + + @Override + public Component render(Player source, Component sourceDisplayName, Component message, Audience viewer) { + String prefix = null; + + try { + prefix = database.getPlayer(source).getTeam().getPrefix(); + } catch (SQLException e) { + core.getLogger().log(Level.WARNING, e.getMessage());; + } catch (NullPointerException e) { + } + + if (prefix == null) prefix = ""; + + return MiniMessage.miniMessage() + .deserialize(prefix) + .append(sourceDisplayName) + .append(Component.text(": ")) + .append(message); + } +} diff --git a/src/main/java/rip/iwakura/civil/events/JoinHandler.java b/src/main/java/rip/iwakura/civil/events/JoinHandler.java new file mode 100644 index 0000000..77f8082 --- /dev/null +++ b/src/main/java/rip/iwakura/civil/events/JoinHandler.java @@ -0,0 +1,25 @@ +package rip.iwakura.civil.events; + +import java.sql.SQLException; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +import rip.iwakura.civil.Database; + +public class JoinHandler implements Listener { + private Database database; + + public JoinHandler(Database database) { + this.database = database; + } + + @EventHandler + public void chatHandler(PlayerJoinEvent event) throws SQLException { + Player p = event.getPlayer(); + + if (database.getPlayer(p) == null) database.createPlayer(p); + } +} diff --git a/src/main/java/rip/iwakura/civil/types/CivilPlayer.java b/src/main/java/rip/iwakura/civil/types/CivilPlayer.java new file mode 100644 index 0000000..2ca4014 --- /dev/null +++ b/src/main/java/rip/iwakura/civil/types/CivilPlayer.java @@ -0,0 +1,38 @@ +package rip.iwakura.civil.types; + +import java.util.UUID; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; + +@DatabaseTable(tableName = "players") +public class CivilPlayer { + @DatabaseField(id = true, canBeNull = false, generatedId = false, columnName = "uuid") + private UUID uuid; + + @DatabaseField(canBeNull = false, columnName = "name") + private String name; + + @DatabaseField(canBeNull = true, foreign = true, foreignAutoRefresh = true) + private CivilTeam team; + + public CivilPlayer() { + } + + public CivilPlayer(UUID uuid, String name) { + this.uuid = uuid; + this.name = name; + } + + public void setTeam(CivilTeam team) { + this.team = team; + } + + public CivilTeam getTeam() { + return team; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/rip/iwakura/civil/types/CivilTeam.java b/src/main/java/rip/iwakura/civil/types/CivilTeam.java new file mode 100644 index 0000000..c6fb73e --- /dev/null +++ b/src/main/java/rip/iwakura/civil/types/CivilTeam.java @@ -0,0 +1,43 @@ +package rip.iwakura.civil.types; + +import org.bukkit.Location; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; + +@DatabaseTable(tableName = "teams") +public class CivilTeam { + @DatabaseField(id = true) + private String name; + + @DatabaseField(canBeNull = false) + private String prefix; + + /*@DatabaseField(canBeNull = true) + private Location home;*/ + + public CivilTeam() { + } + + public CivilTeam(String name, String prefix) { + this.name = name; + this.prefix = prefix; + } + + public String getName() { + return name; + } + + public String getPrefix() { + return prefix; + } +/* + public void setHome(Location home) { + this.home = home; + } + + public Location getHome() { + return home; + } + */ +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..40ac02b --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,2 @@ +database: + url: "" diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties new file mode 100644 index 0000000..ccf1f99 --- /dev/null +++ b/src/main/resources/log4j.properties @@ -0,0 +1,16 @@ +log4j.rootLogger=INFO, stdout + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout + +# print the date in ISO 8601 format +log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} [%p] %c{1} %m%n + +# be more verbose with our code +log4j.logger.com.j256.ormlite=DEBUG + +# to enable logging of arguments to all of the SQL calls +# uncomment the following lines +log4j.logger.com.j256.ormlite.stmt.mapped.BaseMappedStatement=TRACE +log4j.logger.com.j256.ormlite.stmt.mapped.MappedCreate=TRACE +log4j.logger.com.j256.ormlite.stmt.StatementExecutor=TRACE