From 1d54a2a6c0e81ec82c333aac595548a128967a33 Mon Sep 17 00:00:00 2001 From: cmastudios Date: Mon, 27 Oct 2014 16:43:13 -0500 Subject: [PATCH] War 2.0 for SpongeAPI started! Just started rewriting a bit, in case this API really does come through eventually. Sponge is scheduled for release in November. Whadya think @taoneill ? Pouvez-vous nous aider @kugick ? --- sponge/.gitignore | 5 + sponge/pom.xml | 181 ++++++++++++++++++ .../java/com/tommytony/war/WarConfig.java | 133 +++++++++++++ .../java/com/tommytony/war/WarPlugin.java | 51 +++++ .../war/command/WarConfigCommand.java | 134 +++++++++++++ .../java/com/tommytony/war/struct/Region.java | 103 ++++++++++ 6 files changed, 607 insertions(+) create mode 100644 sponge/.gitignore create mode 100644 sponge/pom.xml create mode 100644 sponge/src/main/java/com/tommytony/war/WarConfig.java create mode 100644 sponge/src/main/java/com/tommytony/war/WarPlugin.java create mode 100644 sponge/src/main/java/com/tommytony/war/command/WarConfigCommand.java create mode 100644 sponge/src/main/java/com/tommytony/war/struct/Region.java diff --git a/sponge/.gitignore b/sponge/.gitignore new file mode 100644 index 0000000..a3bb0d7 --- /dev/null +++ b/sponge/.gitignore @@ -0,0 +1,5 @@ +target/ +war.iml +.project +.classpath +.workspace/ diff --git a/sponge/pom.xml b/sponge/pom.xml new file mode 100644 index 0000000..8627a4a --- /dev/null +++ b/sponge/pom.xml @@ -0,0 +1,181 @@ + + 4.0.0 + + com.tommytony + war + 2.0-SNAPSHOT + jar + + War + http://war.tommytony.com + The original TDM/CTF plugin for Minecraft + 2010 + + + + MIT License + http://opensource.org/licenses/MIT + repo + + + + + TeamWar + http://community.tommytony.com + + + + + cmastudios + Connor Monahan + cma@tommytony.com + https://cmastudios.me + TeamWar + http://community.tommytony.com + + maintainer + + America/Chicago + + + tommytony + Thomas-Antoine O'Neill + taoneill@tommytony.com + http://tommytony.com + TeamWar + http://community.tommytony.com + + dictator + + America/Montreal + + + + + GitHub + https://github.com/taoneill/war/issues + + + + Jenkins + http://ci.tommytony.com + + + + + Google Groups + minecraft-war+subscribe@googlegroups.com + minecraft-war+unsubscribe@googlegroups.com + minecraft-war@googlegroups.com + https://groups.google.com/forum/#!forum/minecraft-war + + + + + scm:git:https://github.com/taoneill/war.git + scm:git:https://github.com/taoneill/war.git + HEAD + https://github.com/taoneill/war + + + + http://war.tommytony.com + + war-repo + War Jenkins Maven Builds + http://ci.tommytony.com/plugin/repository/everything/ + + + + + UTF-8 + + + + + war-repo + http://ci.tommytony.com/plugin/repository/everything/ + + + + + + junit + junit + 3.8.1 + test + + + org.spongepowered + spongeapi + 1.0.0-SNAPSHOT + + + org.xerial + sqlite-jdbc + 3.7.2 + + + org.yaml + snakeyaml + 1.14 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.0.2 + + 7 + 7 + + + + org.apache.maven.plugins + maven-shade-plugin + 1.7.1 + + + package + + shade + + + + + org.xerial:sqlite-jdbc + org.yaml:snakeyaml + + + false + + + org.sqlite + com.tommytony.war.sqlite + + + org.ibex + com.tommytony.war.ibex + + + org.yaml.snakeyaml + com.tommytony.war.yaml + + + + + + + + + + true + ${basedir}/src/main/resources/ + + + + diff --git a/sponge/src/main/java/com/tommytony/war/WarConfig.java b/sponge/src/main/java/com/tommytony/war/WarConfig.java new file mode 100644 index 0000000..7a6177b --- /dev/null +++ b/sponge/src/main/java/com/tommytony/war/WarConfig.java @@ -0,0 +1,133 @@ +package com.tommytony.war; + +import com.google.common.collect.ImmutableList; +import org.spongepowered.api.entity.Player; + +import java.io.Closeable; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.sql.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.UUID; + +/** + * The main war configuration database. + */ +public class WarConfig implements Closeable { + private final WarPlugin plugin; + /** + * Database configuration descriptor. + */ + private Connection conn; + + /** + * Load the war config database for future use. + * + * @param file War configuration database location. + * @throws FileNotFoundException + * @throws SQLException + */ + public WarConfig(WarPlugin plugin, File file) throws FileNotFoundException, SQLException { + this.plugin = plugin; + if (!file.exists()) + throw new FileNotFoundException("Can't find war main database"); + conn = DriverManager.getConnection("jdbc:sqlite:" + file.getPath()); + try (Statement stmt = conn.createStatement()) { + stmt.executeUpdate("CREATE TABLE IF NOT EXISTS settings (option TEXT, value BLOB)"); + stmt.executeUpdate("CREATE TABLE IF NOT EXISTS zones (name TEXT)"); + stmt.executeUpdate("CREATE TABLE IF NOT EXISTS zonemakers (uuid TEXT)"); + } + } + + /** + * Get the value of an integer setting. + * + * @param setting The type of setting to look up. + * @return the value of the setting or the default if not found. + * @throws SQLException + */ + public int getInt(WarSetting setting) throws SQLException { + try (PreparedStatement stmt = conn.prepareStatement("SELECT value FROM settings WHERE option = ?")) { + stmt.setString(1, setting.name()); + try (ResultSet result = stmt.executeQuery()) { + if (result.next()) { + return result.getInt(1); + } else { + return (int) setting.defaultValue; + } + } + } + } + + /** + * Load all the enabled war zones on the server. + * + * @return list of war zones. + * @throws SQLException + */ + public Collection getZones() throws SQLException { + ArrayList zones = new ArrayList<>(); + try (Statement stmt = conn.createStatement(); + ResultSet result = stmt.executeQuery("SELECT name FROM zones")) { + while (result.next()) { + zones.add(result.getString(1)); + } + } + return ImmutableList.copyOf(zones); + } + + /** + * Get server zone makers. These people have permission to create zones. + * + * @return list of zone makers. + * @throws SQLException + */ + public Collection getZoneMakers() throws SQLException { + ArrayList makers = new ArrayList<>(); + try (Statement stmt = conn.createStatement(); + ResultSet result = stmt.executeQuery("SELECT uuid FROM zonemakers")) { + while (result.next()) { + UUID playerId = UUID.fromString(result.getString(1)); + if (playerId == null) + continue; + Player player = plugin.getGame().getPlayer(playerId); + if (player == null) + continue; + makers.add(player); + } + } + return ImmutableList.copyOf(makers); + } + + /** + * Closes this stream and releases any system resources associated + * with it. If the stream is already closed then invoking this + * method has no effect. + * + * @throws java.io.IOException if an I/O error occurs + */ + @Override + public void close() throws IOException { + try { + conn.close(); + } catch (SQLException e) { + throw new IOException(e); + } + } + + /** + * Possible types of settings stored in the war server config database. + */ + public enum WarSetting { + MAXZONES(Integer.class, 20); + private final Class dataType; + private final Object defaultValue; + + private WarSetting(Class dataType, Object defaultValue) { + this.dataType = dataType; + this.defaultValue = defaultValue; + } + } +} diff --git a/sponge/src/main/java/com/tommytony/war/WarPlugin.java b/sponge/src/main/java/com/tommytony/war/WarPlugin.java new file mode 100644 index 0000000..12c8370 --- /dev/null +++ b/sponge/src/main/java/com/tommytony/war/WarPlugin.java @@ -0,0 +1,51 @@ +package com.tommytony.war; + +import org.apache.logging.log4j.Logger; +import org.spongepowered.api.Game; +import org.spongepowered.api.event.SpongeEventHandler; +import org.spongepowered.api.event.state.PreInitializationEvent; +import org.spongepowered.api.event.state.ServerStartingEvent; +import org.spongepowered.api.plugin.Plugin; + +import java.io.File; +import java.io.FileNotFoundException; +import java.sql.SQLException; + +@Plugin(id = "war", name = "War", version = "2.0-SNAPSHOT") +public class WarPlugin { + private Game game; + private Logger logger; + private File dataDir; + private WarConfig config; + + @SpongeEventHandler + public void onConstruction(PreInitializationEvent event) throws InstantiationException { + game = event.getGame(); + logger = event.getPluginLog(); + dataDir = event.getConfigurationDirectory(); + try { + Class.forName("com.tommytony.war.sqlite.JDBC").newInstance(); + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + throw new InstantiationException("Failed to load SQLite database"); + } + } + + @SpongeEventHandler + public void onStartUp(ServerStartingEvent event) throws FileNotFoundException, SQLException { + if (!dataDir.exists() && !dataDir.mkdirs()) + throw new FileNotFoundException("Failed to make War data folder at " + dataDir.getPath()); + config = new WarConfig(this, new File(dataDir, "war.sl3")); + } + + public Game getGame() { + return game; + } + + public Logger getLogger() { + return logger; + } + + public WarConfig getConfig() { + return config; + } +} diff --git a/sponge/src/main/java/com/tommytony/war/command/WarConfigCommand.java b/sponge/src/main/java/com/tommytony/war/command/WarConfigCommand.java new file mode 100644 index 0000000..239a13d --- /dev/null +++ b/sponge/src/main/java/com/tommytony/war/command/WarConfigCommand.java @@ -0,0 +1,134 @@ +package com.tommytony.war.command; + +import com.google.common.collect.ImmutableList; +import com.tommytony.war.WarConfig; +import com.tommytony.war.WarPlugin; +import org.spongepowered.api.entity.Player; +import org.spongepowered.api.service.permission.Subject; +import org.spongepowered.api.util.command.CommandCallable; +import org.spongepowered.api.util.command.CommandException; +import org.spongepowered.api.util.command.CommandSource; +import org.spongepowered.api.util.command.Description; + +import javax.annotation.Nullable; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class WarConfigCommand implements CommandCallable { + private final WarPlugin plugin; + + public WarConfigCommand(WarPlugin plugin) { + this.plugin = plugin; + } + + /** + * Execute the command based on input arguments. + *

+ *

The implementing class must perform the necessary permission + * checks.

+ * + * @param source The caller of the command + * @param arguments The raw arguments for this command + * @param parents A stack of parent commands, where the first entry is + * the root command + * @return Whether a command was processed + * @throws org.spongepowered.api.util.command.CommandException Thrown on a command error + */ + @Override + public boolean call(CommandSource source, String arguments, List parents) throws CommandException { + if (!testPermission(source)) { + source.sendMessage("You do not have permission for this command."); + return true; + } + source.sendMessage("you do have permission"); + return false; + } + + /** + * Get a description of the command, detailing usage information. + * + * @return The command description + */ + @Override + public Description getDescription() { + return new Description() { + @Nullable + @Override + public String getShortDescription() { + return "View/modify war config"; + } + + @Nullable + @Override + public String getHelp() { + return "Allows viewing of the war server config or changing various settings."; + } + + @Override + public String getUsage() { + return "[-p] setting:value..."; + } + + @Override + public List getPermissions() { + return ImmutableList.of("war.admin", "war.admin.config"); + } + }; + } + + /** + * Test whether this command can probably be executed by the given source. + *

+ *

If implementations are unsure if the command can be executed by + * the source, {@code true} should be returned. Return values of this method + * may be used to determine whether this command is listed in command + * listings.

+ * + * @param source The caller of the command + * @return Whether permission is (probably) granted + */ + @Override + public boolean testPermission(CommandSource source) { + if (source instanceof Player) { + try { + if (plugin.getConfig().getZoneMakers().contains(source)) { + source.sendMessage("You are a zone maker."); + return true; + } + } catch (SQLException e) { + plugin.getLogger().error("Loading zone makers for testing permission", e); + } + } + if (source instanceof Subject && ((Subject) source).isPermitted("war.admin.config")) { + source.sendMessage("You are a war admin."); + return true; + } + if (!(source instanceof Player) && !(source instanceof Subject)) { + source.sendMessage("You are console or something."); + return true; + } + return false; + } + + /** + * Get a list of suggestions based on input. + *

+ *

If a suggestion is chosen by the user, it will replace the last + * word.

+ * + * @param source The command source + * @param arguments The arguments entered up to this point + * @return A list of suggestions + * @throws org.spongepowered.api.util.command.CommandException Thrown if there was a parsing error + */ + @Override + public List getSuggestions(CommandSource source, String arguments) throws CommandException { + ArrayList suggestions = new ArrayList<>(); + for (WarConfig.WarSetting setting : WarConfig.WarSetting.values()) { + if (setting.name().toLowerCase().startsWith(arguments.toLowerCase())) + suggestions.add(setting.name().toLowerCase() + ":"); + } + return suggestions; + } +} diff --git a/sponge/src/main/java/com/tommytony/war/struct/Region.java b/sponge/src/main/java/com/tommytony/war/struct/Region.java new file mode 100644 index 0000000..3575d65 --- /dev/null +++ b/sponge/src/main/java/com/tommytony/war/struct/Region.java @@ -0,0 +1,103 @@ +package com.tommytony.war.struct; + +import org.spongepowered.api.block.Block; +import org.spongepowered.api.math.Vector3d; +import org.spongepowered.api.world.Location; +import org.spongepowered.api.world.extent.BlockVolume; + +/** + * A selection of blocks in the world. Identified by two corners. + */ +public class Region implements BlockVolume { + /** + * One corner of the selection. + */ + private Location first; + /** + * The second corner of the selection. + */ + private Location second; + + public Region(Location first, Location second) { + this.first = first; + this.second = second; + } + + /** + * Calculate the minimum value of the selection. + * + * @return the minimum value. + */ + public Location getMin() { + return new Location(first.getExtent(), first.getPosition().min(second.getPosition())); + } + + /** + * Calculate the maximum value of the selection. + * + * @return the maximum value. + */ + public Location getMax() { + return new Location(first.getExtent(), first.getPosition().max(second.getPosition())); + } + + /** + * Get the size of the region in the X dimension. + * + * @return X dimension length. + */ + public int getSizeX() { + return getMax().getBlock().getX() - getMin().getBlock().getX(); + } + + /** + * Get the size of the region in the Y dimension. + * + * @return Y dimension length. + */ + public int getSizeY() { + return getMax().getBlock().getY() - getMin().getBlock().getY(); + } + + /** + * Get the size of the region in the Z dimension. + * + * @return Z dimension length. + */ + public int getSizeZ() { + return getMax().getBlock().getZ() - getMin().getBlock().getZ(); + } + + /** + * Get the total area of the region. + * + * @return region total area. + */ + public int getSize() { + return getSizeX() * getSizeY() * getSizeZ(); + } + + /** + * Get a representation of the block at the given position. + * + * @param position The position + * @return The block + */ + @Override + public Block getBlock(Vector3d position) { + return first.getExtent().getBlock(position); + } + + /** + * Get a representation of the block at the given position. + * + * @param x The X position + * @param y The Y position + * @param z The Z position + * @return The block + */ + @Override + public Block getBlock(int x, int y, int z) { + return first.getExtent().getBlock(x, y, z); + } +}