diff --git a/.circleci/config.yml b/.circleci/config.yml index 034ef2b569..1d4ba67277 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -61,7 +61,13 @@ jobs: - ~/.m2 key: glowstone-{{ checksum "pom.xml" }} - - run: mvn -T 2 -B -s .circleci/maven.xml source:jar javadoc:jar deploy + # Ensure we are on the right repo before attempting a deploy + - run: | + if [ "${CIRCLE_PROJECT_USERNAME}" == "GlowstoneMC" ]; then + mvn -T 2 -B -s .circleci/maven.xml source:jar javadoc:jar deploy + else + mvn -T 2 -B package + fi - store_test_results: path: target/surefire-reports @@ -92,4 +98,4 @@ workflows: - build: filters: branches: - ignore: dev \ No newline at end of file + ignore: dev diff --git a/.gitignore b/.gitignore index e8efa22d01..e18fc028c5 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ dependency-reduced-pom.xml .settings .db .DS_Store +.vscode diff --git a/docs/CHEATING_AND_ILLEGAL_BEHAVIOR_POLICY.md b/docs/CHEATING_AND_ILLEGAL_BEHAVIOR_POLICY.md new file mode 100644 index 0000000000..9cd854941a --- /dev/null +++ b/docs/CHEATING_AND_ILLEGAL_BEHAVIOR_POLICY.md @@ -0,0 +1,23 @@ +# Cheating and Illegal Behavior Policy + +## Purpose + +The purpose of this Policy is to define guidelines as to the usage of software or services deemed unreasonable in the context of the Glowstone Project. +This Policy affirms the Project's position against cheating and unauthorized use of products and services. + + +## Extent + +This Policy extends to the following actions, deemed unreasonable in the context of the Project: + * The usage of illegally distributed, obtained and/or pirated copies of the *Minecraft* client (commonly known as "*cracked clients*"); + * The usage of pirated or stolen *Minecraft* or *Mojang AB* accounts; + * The usage of illegally distributed and/or obtained software, plugins and libraries with the Glowstone server; + * The usage of *Minecraft* clients modified with the foremost purpose of using game exploits and cheating. + + +## Enforcement + +The enforcement of this Policy is under the discretion of the Project's administration, which may include but is not limited to: +* The refusal to provide support to an end-user utilizing software or services deemed unreasonable to the extent of this Policy; + * Support may still be provided if the user accepts to stop utilizing unreasonable software or services in the context of the support request. +* The refusal to provide support to an end-user seeking help to use software or services unreasonably to the extent of this Policy. diff --git a/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md similarity index 100% rename from CODE_OF_CONDUCT.md rename to docs/CODE_OF_CONDUCT.md diff --git a/.github/CONTRIBUTING.md b/docs/CONTRIBUTING.md similarity index 100% rename from .github/CONTRIBUTING.md rename to docs/CONTRIBUTING.md diff --git a/.github/ISSUE_TEMPLATE.md b/docs/ISSUE_TEMPLATE.md similarity index 100% rename from .github/ISSUE_TEMPLATE.md rename to docs/ISSUE_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE.md rename to docs/PULL_REQUEST_TEMPLATE.md diff --git a/README.md b/docs/README.md similarity index 91% rename from README.md rename to docs/README.md index 91199be369..701958c890 100644 --- a/README.md +++ b/docs/README.md @@ -1,8 +1,8 @@ ![Built with Love](http://forthebadge.com/images/badges/built-with-love.svg) -[![Join the Discord chat](https://img.shields.io/badge/discord-glowstone-738bd7.svg?style=flat-square)](https://discord.gg/TFJqhsC) +[![Join the Discord chat](https://img.shields.io/badge/discord-glowstone-7289da.svg?style=flat-square&logo=discord)](https://discord.gg/TFJqhsC) [![Build Status](https://circleci.com/gh/GlowstoneMC/Glowstone/tree/dev.svg?style=shield)](https://circleci.com/gh/GlowstoneMC/Glowstone/tree/dev) -Glowstone logo +Glowstone logo # Glowstone @@ -51,9 +51,10 @@ However, there are several drawbacks: For a current list of features, [check the wiki](https://github.com/GlowstoneMC/Glowstone/wiki/Current-Features). ## Downloads -[![Build Status](https://circleci.com/gh/GlowstoneMC/Glowstone.svg?style=svg)](https://circleci.com/gh/GlowstoneMC/Glowstone) -If you don't want to build from source, pre-built jar files are available to download from [**CircleCI**](https://circleci.com/gh/GlowstoneMC/Glowstone) - click the latest build and then open the "Artifacts" tab **(you must be logged in for this to show)**. The `glowstone.jar` artifact will be under `tmp/circle-artifacts.#######/`. +The latest LTS and monthly releases, as well as a direct link to our latest build can be found on [our website](https://glowstone.net/#downloads). + +Older releases can be found on [GitHub](https://github.com/GlowstoneMC/Glowstone/releases). ## Building diff --git a/pom.xml b/pom.xml index 902de4b2ff..9f33e2d7cd 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.glowstone glowstone jar - 2018.0.1-SNAPSHOT + 2018.0.1 Glowstone https://www.glowstone.net A fast, customizable and compatible open source Minecraft server. @@ -18,6 +18,7 @@ yyyyMMdd-HHmm 1.8 1.8 + 1.2.10 @@ -45,7 +46,7 @@ org.slf4j - slf4j-log4j12 + slf4j-jdk14 1.7.25 runtime @@ -73,7 +74,7 @@ org.projectlombok lombok - 1.14.8 + 1.16.20 provided @@ -85,12 +86,12 @@ org.jetbrains.kotlin kotlin-runtime - 1.2.0 + ${kotlin.version} org.jetbrains.kotlin kotlin-reflect - 1.2.0 + ${kotlin.version} diff --git a/src/main/java/net/glowstone/ConsoleManager.java b/src/main/java/net/glowstone/ConsoleManager.java index d608f0c6d8..20d8e516b7 100644 --- a/src/main/java/net/glowstone/ConsoleManager.java +++ b/src/main/java/net/glowstone/ConsoleManager.java @@ -22,6 +22,7 @@ import java.util.logging.StreamHandler; import jline.console.ConsoleReader; import jline.console.completer.Completer; +import lombok.Getter; import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.ChatColor; import org.bukkit.command.CommandException; @@ -54,6 +55,12 @@ public final class ConsoleManager { private final ChatColor[] colors = ChatColor.values(); private ConsoleReader reader; + /** + * Returns this ConsoleManager's console as a ConsoleCommandSender. + * + * @return the ConsoleCommandSender instance for this ConsoleManager's console + */ + @Getter private ConsoleCommandSender sender; private boolean running = true; @@ -135,19 +142,10 @@ public ConsoleManager(GlowServer server) { replacements.put(ChatColor.RESET, Ansi.ansi().a(Attribute.RESET).toString()); } - /** - * Returns this ConsoleManager's console as a ConsoleCommandSender. - * - * @return the ConsoleCommandSender instance for this ConsoleManager's console - */ - public ConsoleCommandSender getSender() { - return sender; - } - /** * Starts the console. * - * @param jline TODO: document this parameter + * @param jline whether the console should use JLine */ public void startConsole(boolean jline) { this.jline = jline; diff --git a/src/main/java/net/glowstone/GlowOfflinePlayer.java b/src/main/java/net/glowstone/GlowOfflinePlayer.java index df739c15bb..69b80bc80d 100644 --- a/src/main/java/net/glowstone/GlowOfflinePlayer.java +++ b/src/main/java/net/glowstone/GlowOfflinePlayer.java @@ -6,6 +6,7 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import lombok.Getter; import net.glowstone.entity.meta.profile.PlayerProfile; import net.glowstone.entity.meta.profile.ProfileCache; import net.glowstone.io.PlayerDataService.PlayerReader; @@ -23,16 +24,21 @@ public final class GlowOfflinePlayer implements OfflinePlayer { private final GlowServer server; + @Getter private final PlayerProfile profile; private boolean hasPlayed; + @Getter private long firstPlayed; + @Getter private long lastPlayed; private String lastName; - private Location bedSpawn; + @Getter + private Location bedSpawnLocation; /** - * Create a new offline player for the given name. If possible, the player's data will be loaded. + * Create a new offline player for the given name. If possible, the player's data will be + * loaded. * * @param server The server of the offline player. Must not be null. * @param profile The profile associated with the player. Must not be null. @@ -46,18 +52,28 @@ public GlowOfflinePlayer(GlowServer server, PlayerProfile profile) { } /** - * Returns a Future for a GlowOfflinePlayer by UUID. If possible, the player's data (including name) will be loaded based on the UUID. + * Returns a Future for a GlowOfflinePlayer by UUID. If possible, the player's data (including + * name) will be loaded based on the UUID. * * @param server The server of the offline player. Must not be null. * @param uuid The UUID of the player. Must not be null. * @return A {@link GlowOfflinePlayer} future. */ - public static CompletableFuture getOfflinePlayer(GlowServer server, UUID uuid) { + public static CompletableFuture getOfflinePlayer(GlowServer server, + UUID uuid) { checkNotNull(server, "server must not be null"); checkNotNull(uuid, "UUID must not be null"); - return ProfileCache.getProfile(uuid).thenApplyAsync((profile) -> new GlowOfflinePlayer(server, profile)); + return ProfileCache.getProfile(uuid) + .thenApplyAsync((profile) -> new GlowOfflinePlayer(server, profile)); } + /** + * Required method for configuration serialization. + * + * @param val map to deserialize + * @return deserialized player record + * @see org.bukkit.configuration.serialization.ConfigurationSerializable + */ @SuppressWarnings("UnusedDeclaration") public static OfflinePlayer deserialize(Map val) { if (val.get("name") != null) { @@ -78,7 +94,7 @@ private void loadData() { if (hasPlayed) { firstPlayed = reader.getFirstPlayed(); lastPlayed = reader.getLastPlayed(); - bedSpawn = reader.getBedSpawnLocation(); + bedSpawnLocation = reader.getBedSpawnLocation(); String lastName = reader.getLastKnownName(); if (lastName != null) { @@ -126,28 +142,9 @@ public boolean hasPlayedBefore() { return hasPlayed; } - @Override - public long getFirstPlayed() { - return firstPlayed; - } - - @Override - public long getLastPlayed() { - return lastPlayed; - } - - public PlayerProfile getProfile() { - return profile; - } - //////////////////////////////////////////////////////////////////////////// // Ban, op, whitelist - @Override - public Location getBedSpawnLocation() { - return bedSpawn; - } - @Override public boolean isBanned() { return server.getBanList(Type.NAME).isBanned(getName()); @@ -169,7 +166,7 @@ public void setWhitelisted(boolean value) { @Override public boolean isOp() { - return server.getOpsList().containsUUID(getUniqueId()); + return server.getOpsList().containsUuid(getUniqueId()); } //////////////////////////////////////////////////////////////////////////// @@ -191,6 +188,7 @@ public Map serialize() { return ret; } + @Override public boolean equals(Object o) { if (this == o) { return true; diff --git a/src/main/java/net/glowstone/GlowPluginTypeDetector.java b/src/main/java/net/glowstone/GlowPluginTypeDetector.java index e65b388223..f7fe91181b 100644 --- a/src/main/java/net/glowstone/GlowPluginTypeDetector.java +++ b/src/main/java/net/glowstone/GlowPluginTypeDetector.java @@ -31,6 +31,9 @@ public GlowPluginTypeDetector(File directory) { this.directory = directory; } + /** + * Scans all jars in the plugin directory for their types. + */ public void scan() { GlowServer.logger.info("Scanning plugins..."); File[] files = directory.listFiles(new PatternFilenameFilter(".+\\.jar")); @@ -42,7 +45,15 @@ public void scan() { scanFile(file); } - GlowServer.logger.info("PluginTypeDetector: found " + bukkitPlugins.size() + " Bukkit, " + spongePlugins.size() + " Sponge, " + (forgefPlugins.size() + forgenPlugins.size()) + " Forge, " + canaryPlugins.size() + " Canary, " + unrecognizedPlugins.size() + " unknown plugins (total " + files.length + ")"); + GlowServer.logger.info(String.format( + "PluginTypeDetector: found %d Bukkit, %d Sponge, %d Forge, %d Canary, " + + "%d unknown plugins (total %d)", + bukkitPlugins.size(), + spongePlugins.size(), + forgefPlugins.size() + forgenPlugins.size(), + canaryPlugins.size(), + unrecognizedPlugins.size(), + files.length)); if (!unrecognizedPlugins.isEmpty()) { for (File file : unrecognizedPlugins) { @@ -84,7 +95,8 @@ private void scanFile(File file) { // Analyze class file ClassReader classReader = new ClassReader(zip.getInputStream(entryIn)); GlowVisitor visitor = new GlowVisitor(); - classReader.accept(visitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + classReader.accept(visitor, ClassReader.SKIP_CODE + | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); if (visitor.isSponge) { isSponge = true; @@ -146,6 +158,8 @@ public AnnotationVisitor visitAnnotation(String name, boolean visible) { case "Lnet/minecraftforge/fml/common/Mod;": // newer isForgeN = true; break; + default: + // do nothing } return null; diff --git a/src/main/java/net/glowstone/GlowServer.java b/src/main/java/net/glowstone/GlowServer.java index f09bbfe3bd..a9aa9c872b 100644 --- a/src/main/java/net/glowstone/GlowServer.java +++ b/src/main/java/net/glowstone/GlowServer.java @@ -82,6 +82,7 @@ import net.glowstone.command.minecraft.TellCommand; import net.glowstone.command.minecraft.TellrawCommand; import net.glowstone.command.minecraft.TestForBlockCommand; +import net.glowstone.command.minecraft.TestForBlocksCommand; import net.glowstone.command.minecraft.TestForCommand; import net.glowstone.command.minecraft.TimeCommand; import net.glowstone.command.minecraft.TitleCommand; @@ -121,7 +122,6 @@ import net.glowstone.util.GlowHelpMap; import net.glowstone.util.GlowServerIcon; import net.glowstone.util.GlowUnsafeValues; -import net.glowstone.util.LibraryManager; import net.glowstone.util.OpenCompute; import net.glowstone.util.SecurityUtils; import net.glowstone.util.ShutdownMonitorThread; @@ -131,6 +131,8 @@ import net.glowstone.util.config.ServerConfig; import net.glowstone.util.config.ServerConfig.Key; import net.glowstone.util.config.WorldConfig; +import net.glowstone.util.library.Library; +import net.glowstone.util.library.LibraryManager; import net.glowstone.util.loot.LootingManager; import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.BanEntry; @@ -383,6 +385,16 @@ public org.bukkit.configuration.file.YamlConfiguration getConfig() { * The storage provider for the world. */ private WorldStorageProviderFactory storageProviderFactory = null; + /** + * Whether the server should just generate and load configuration files, then exit. + * + *

This can be enabled by using the --generate-config launch argument. + */ + private static boolean generateConfigOnly; + /** + * The file name for the server icon. + */ + private static final String SERVER_ICON_FILE = "server-icon.png"; /** * Creates a new server. @@ -395,7 +407,11 @@ public GlowServer(ServerConfig config) { // test advancement GlowAdvancement advancement = new GlowAdvancement(NamespacedKey.minecraft("test"), null); advancement.addCriterion("minecraft:test/criterion"); - advancement.setDisplay(new GlowAdvancementDisplay(new TextMessage("Advancements in Glowstone"), new TextMessage("=)"), new ItemStack(Material.GLOWSTONE), GlowAdvancementDisplay.FrameType.GOAL, -10F, 0)); + advancement.setDisplay(new GlowAdvancementDisplay( + new TextMessage("Advancements in Glowstone"), new TextMessage("=)"), + new ItemStack(Material.GLOWSTONE), + GlowAdvancementDisplay.FrameType.GOAL, + -10F, 0)); addAdvancement(advancement); this.config = config; @@ -418,10 +434,14 @@ public static void main(String... args) { try { GlowServer server = createFromArguments(args); - // we don't want to run a server when called with --version + // we don't want to run a server when called with --version, --help or --generate-config if (server == null) { return; } + if (generateConfigOnly) { + GlowServer.logger.info("Configuration files have been loaded, exiting..."); + return; + } server.run(); } catch (SecurityException e) { @@ -433,6 +453,12 @@ public static void main(String... args) { } } + /** + * Initialize a server using the command-line arguments. + * + * @param args the command-line arguments + * @return the new server, or null if the command-line arguments include e.g. {@code --version} + */ public static GlowServer createFromArguments(String... args) { ServerConfig config = parseArguments(args); @@ -466,30 +492,61 @@ private static ServerConfig parseArguments(String... args) { // Help and version if ("--help".equals(opt) || "-h".equals(opt) || "-?".equals(opt)) { System.out.println("Available command-line options:"); - System.out.println(" --help, -h, -? Shows this help message and exits."); - System.out.println(" --version, -v Shows version information and exits."); - System.out.println(" --configdir Sets the configuration directory."); + System.out + .println(" --help, -h, -? Shows this help message and " + + "exits."); + System.out + .println(" --version, -v Shows version information and " + + "exits."); + System.out + .println(" --generate-config Generates and loads " + + "configuration files, then exits."); + System.out + .println(" --configdir Sets the configuration " + + "directory."); System.out.println(" --configfile Sets the configuration file."); - System.out.println(" --port, -p Sets the server listening port."); - System.out.println(" --host, -H Sets the server listening address."); - System.out.println(" --onlinemode, -o Sets the server's online-mode."); - System.out.println(" --jline Enables or disables JLine console."); - System.out.println(" --plugins-dir, -P Sets the plugin directory to use."); - System.out.println(" --worlds-dir, -W Sets the world directory to use."); - System.out.println(" --update-dir, -U Sets the plugin update folder to use."); - System.out.println(" --max-players, -M Sets the maximum amount of players."); + System.out + .println(" --port, -p Sets the server listening port" + + "."); + System.out + .println(" --host, -H Sets the server listening " + + "address."); + System.out + .println(" --onlinemode, -o Sets the server's online-mode."); + System.out + .println(" --jline Enables or disables JLine " + + "console."); + System.out + .println(" --plugins-dir, -P Sets the plugin directory to " + + "use."); + System.out + .println(" --worlds-dir, -W Sets the world directory to " + + "use."); + System.out + .println(" --update-dir, -U Sets the plugin update folder " + + "to use."); + System.out + .println(" --max-players, -M Sets the maximum amount of " + + "players."); System.out.println(" --world-name, -N Sets the main world name."); - System.out.println(" --log-pattern, -L Sets the log file pattern (%D for date)."); + System.out + .println(" --log-pattern, -L Sets the log file pattern (%D " + + "for date)."); return null; } else if ("--version".equals(opt) || "-v".equals(opt)) { - System.out.println("Glowstone version: " + GlowServer.class.getPackage().getImplementationVersion()); - System.out.println("Bukkit version: " + GlowServer.class.getPackage().getSpecificationVersion()); - System.out.println("Minecraft version: " + GAME_VERSION + " protocol " + PROTOCOL_VERSION); + System.out.println("Glowstone version: " + GlowServer.class.getPackage() + .getImplementationVersion()); + System.out.println("Bukkit version: " + GlowServer.class.getPackage() + .getSpecificationVersion()); + System.out.println( + "Minecraft version: " + GAME_VERSION + " protocol " + PROTOCOL_VERSION); return null; + } else if ("--generate-config".equals(opt)) { + generateConfigOnly = true; } // Below this point, options require parameters - if (i == args.length - 1) { + if (i == args.length - 1 && !"--generate-config".equals(opt)) { System.err.println("Ignored option specified without value: " + opt); continue; } @@ -540,6 +597,9 @@ private static ServerConfig parseArguments(String... args) { case "-L": parameters.put(Key.LOG_FILE, args[++i]); break; + case "--generate-config": + // previously handled + break; default: System.err.println("Ignored invalid option: " + opt); } @@ -576,7 +636,8 @@ public void start() { logger.info("Proxy support is enabled."); } } else if (!getOnlineMode()) { - logger.warning("The server is running in offline mode! Only do this if you know what you're doing."); + logger.warning("The server is running in offline mode! Only do this if you know what " + + "you're doing."); } int openClMajor = 1; @@ -591,7 +652,8 @@ public void start() { CLPlatform bestCpuPlatform = null; // gets the max flops device across platforms on the computer for (CLPlatform platform : CLPlatform.listCLPlatforms()) { - if (platform.isAtLeast(openClMajor, openClMinor) && platform.isExtensionAvailable("cl_khr_fp64")) { + if (platform.isAtLeast(openClMajor, openClMinor) && platform + .isExtensionAvailable("cl_khr_fp64")) { for (CLDevice device : platform.listCLDevices()) { if (device.getType() == CLDevice.Type.GPU) { int flops = device.getMaxComputeUnits() * device.getMaxClockFrequency(); @@ -602,9 +664,12 @@ public void start() { logger.info("Device is best platform so far, on " + platform); bestIntelPlatform = platform; } else if (flops == maxIntelFlops) { - if (bestIntelPlatform != null && bestIntelPlatform.getVersion().compareTo(platform.getVersion()) < 0) { + if (bestIntelPlatform != null && bestIntelPlatform.getVersion() + .compareTo(platform.getVersion()) < 0) { maxIntelFlops = flops; - logger.info("Device tied for flops, but had higher version on " + platform); + logger.info( + "Device tied for flops, but had higher version on " + + platform); bestIntelPlatform = platform; } } @@ -614,9 +679,12 @@ public void start() { logger.info("Device is best platform so far, on " + platform); bestPlatform = platform; } else if (flops == maxGpuFlops) { - if (bestPlatform != null && bestPlatform.getVersion().compareTo(platform.getVersion()) < 0) { + if (bestPlatform != null && bestPlatform.getVersion() + .compareTo(platform.getVersion()) < 0) { maxGpuFlops = flops; - logger.info("Device tied for flops, but had higher version on " + platform); + logger.info( + "Device tied for flops, but had higher version on " + + platform); bestPlatform = platform; } } @@ -629,9 +697,11 @@ public void start() { logger.info("Device is best platform so far, on " + platform); bestCpuPlatform = platform; } else if (flops == maxCpuFlops) { - if (bestCpuPlatform != null && bestCpuPlatform.getVersion().compareTo(platform.getVersion()) < 0) { + if (bestCpuPlatform != null && bestCpuPlatform.getVersion() + .compareTo(platform.getVersion()) < 0) { maxCpuFlops = flops; - logger.info("Device tied for flops, but had higher version on " + platform); + logger.info("Device tied for flops, but had higher version on " + + platform); bestCpuPlatform = platform; } } @@ -649,10 +719,12 @@ public void start() { } else { if (maxGpuFlops == 0) { if (maxIntelFlops == 0) { - logger.info("No Intel graphics found, best platform is the best CPU platform we could find..."); + logger.info("No Intel graphics found, best platform is the best CPU " + + "platform we could find..."); bestPlatform = bestCpuPlatform; } else { - logger.info("No dGPU found, best platform is the best Intel graphics we could find..."); + logger.info("No dGPU found, best platform is the best Intel graphics we " + + "could find..."); bestPlatform = bestIntelPlatform; } } @@ -660,7 +732,8 @@ public void start() { if (bestPlatform == null) { isGraphicsComputeAvailable = false; - logger.info("Your system does not meet the OpenCL requirements for Glowstone. See if driver updates are available."); + logger.info("Your system does not meet the OpenCL requirements for Glowstone. See" + + " if driver updates are available."); logger.info("Required version: " + openClMajor + '.' + openClMinor); logger.info("Required extensions: [ cl_khr_fp64 ]"); } else { @@ -684,14 +757,16 @@ public void start() { } // Start loading plugins - new LibraryManager().run(); + List libraries = aggregateLibraries(); + new LibraryManager(config.getString(Key.LIBRARY_REPOSITORY_URL), + config.getString(Key.LIBRARIES_FOLDER), + config.getBoolean(Key.LIBRARY_CHECKSUM_VALIDATION), + config.getInt(Key.LIBRARY_DOWNLOAD_ATTEMPTS), libraries).run(); loadPlugins(); enablePlugins(PluginLoadOrder.STARTUP); // Create worlds - String name = config.getString(Key.LEVEL_NAME); String seedString = config.getString(Key.LEVEL_SEED); - boolean structs = getGenerateStructures(); WorldType type = WorldType.getByName(getWorldType()); if (type == null) { type = WorldType.NORMAL; @@ -710,17 +785,23 @@ public void start() { } if (storageProviderFactory == null) { - storageProviderFactory = (worldName) -> new AnvilWorldStorageProvider(new File(getWorldContainer(), worldName)); + storageProviderFactory + = (worldName) -> new AnvilWorldStorageProvider(new File(getWorldContainer(), + worldName)); } - - createWorld(WorldCreator.name(name).environment(Environment.NORMAL).seed(seed).type(type).generateStructures(structs)); + String name = config.getString(Key.LEVEL_NAME); + boolean structs = getGenerateStructures(); + createWorld(WorldCreator.name(name).environment(Environment.NORMAL).seed(seed).type(type) + .generateStructures(structs)); if (getAllowNether()) { checkTransfer(name, "_nether", Environment.NETHER); - createWorld(WorldCreator.name(name + "_nether").environment(Environment.NETHER).seed(seed).type(type).generateStructures(structs)); + createWorld(WorldCreator.name(name + "_nether").environment(Environment.NETHER) + .seed(seed).type(type).generateStructures(structs)); } if (getAllowEnd()) { checkTransfer(name, "_the_end", Environment.THE_END); - createWorld(WorldCreator.name(name + "_the_end").environment(Environment.THE_END).seed(seed).type(type).generateStructures(structs)); + createWorld(WorldCreator.name(name + "_the_end").environment(Environment.THE_END) + .seed(seed).type(type).generateStructures(structs)); } // Finish loading plugins @@ -731,14 +812,16 @@ public void start() { private void checkTransfer(String name, String suffix, Environment environment) { // todo: import things like per-dimension villages.dat when those are implemented - Path srcPath = new File(new File(getWorldContainer(), name), "DIM" + environment.getId()).toPath(); + Path srcPath = new File(new File(getWorldContainer(), name), "DIM" + environment.getId()) + .toPath(); Path destPath = new File(getWorldContainer(), name + suffix).toPath(); if (Files.exists(srcPath) && !Files.exists(destPath)) { logger.info("Importing " + destPath + " from " + srcPath); try { Files.walkFileTree(srcPath, new FileVisitor() { @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes attrs) throws IOException { Path target = destPath.resolve(srcPath.relativize(dir)); if (!Files.exists(target)) { Files.createDirectory(target); @@ -747,19 +830,24 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th } @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Files.copy(file, destPath.resolve(srcPath.relativize(file)), StandardCopyOption.COPY_ATTRIBUTES); + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + Files.copy(file, destPath.resolve(srcPath + .relativize(file)), StandardCopyOption.COPY_ATTRIBUTES); return FileVisitResult.CONTINUE; } @Override - public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { - logger.warning("Importing file " + srcPath.relativize(file) + " + failed: " + exc); + public FileVisitResult visitFileFailed(Path file, + IOException exc) throws IOException { + logger.warning( + "Importing file " + srcPath.relativize(file) + " + failed: " + exc); return FileVisitResult.CONTINUE; } @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + public FileVisitResult postVisitDirectory(Path dir, + IOException exc) throws IOException { return FileVisitResult.CONTINUE; } }); @@ -888,15 +976,37 @@ private void loadConfig() { // server icon defaultIcon = new GlowServerIcon(); try { - File file = config.getFile("server-icon.png"); - if (file.isFile()) { - defaultIcon = new GlowServerIcon(file); + File serverIconFile = config.getFile(SERVER_ICON_FILE); + if (serverIconFile.isFile()) { + defaultIcon = new GlowServerIcon(serverIconFile); + } else { + try { + File vanillaServerIcon = new File(SERVER_ICON_FILE); + if (vanillaServerIcon.isFile()) { + // Import from Vanilla + logger.info("Importing '" + SERVER_ICON_FILE + "' from Vanilla."); + Files.copy(vanillaServerIcon.toPath(), serverIconFile.toPath()); + defaultIcon = new GlowServerIcon(serverIconFile); + } + } catch (Exception e) { + logger.log(Level.WARNING, + "Failed to import '" + SERVER_ICON_FILE + "' from Vanilla", e); + } } } catch (Exception e) { - logger.log(Level.WARNING, "Failed to load server-icon.png", e); + logger.log(Level.WARNING, "Failed to load '" + SERVER_ICON_FILE + "'", e); } } + /** + * Aggregates libraries from all relevant sources together. + */ + private List aggregateLibraries() { + return config.getMapList(Key.LIBRARIES).stream() + .map(Library::fromConfigMap) + .collect(Collectors.toList()); + } + /** * Loads all plugins, calling onLoad, &c. */ @@ -953,6 +1063,7 @@ private void loadPlugins() { commandMap.register("minecraft", new TestForBlockCommand()); commandMap.register("minecraft", new SetBlockCommand()); commandMap.register("minecraft", new CloneCommand()); + commandMap.register("minecraft", new TestForBlocksCommand()); File folder = new File(config.getString(Key.PLUGIN_FOLDER)); if (!folder.isDirectory() && !folder.mkdirs()) { @@ -966,14 +1077,17 @@ private void loadPlugins() { // clear plugins and prepare to load (Bukkit) pluginManager.clearPlugins(); pluginManager.registerInterface(JavaPluginLoader.class); - Plugin[] plugins = pluginManager.loadPlugins(folder.getPath(), pluginTypeDetector.bukkitPlugins.toArray(new File[pluginTypeDetector.bukkitPlugins.size()])); + Plugin[] plugins = pluginManager + .loadPlugins(folder.getPath(), pluginTypeDetector.bukkitPlugins + .toArray(new File[pluginTypeDetector.bukkitPlugins.size()])); // call onLoad methods for (Plugin plugin : plugins) { try { plugin.onLoad(); } catch (Exception ex) { - logger.log(Level.SEVERE, "Error loading " + plugin.getDescription().getFullName(), ex); + logger.log(Level.SEVERE, + "Error loading " + plugin.getDescription().getFullName(), ex); } } @@ -981,7 +1095,9 @@ private void loadPlugins() { boolean hasSponge = false; for (Plugin plugin : plugins) { if (plugin.getName().equals("Bukkit2Sponge")) { - hasSponge = true; // TODO: better detection method, plugin description file annotation APIs? + hasSponge + = true; // TODO: better detection method, plugin description file + // annotation APIs? break; } } @@ -994,15 +1110,19 @@ private void loadPlugins() { } if (!hasSponge && spongeOnlyPlugins) { - logger.log(Level.WARNING, "SpongeAPI plugins found, but no Sponge bridge present! They will be ignored."); + logger.log(Level.WARNING, "SpongeAPI plugins found, but no Sponge bridge present!" + + " They will be ignored."); for (File file : getSpongePlugins()) { logger.log(Level.WARNING, "Ignored SpongeAPI plugin: " + file.getPath()); } - logger.log(Level.WARNING, "Suggestion: install https://github.com/GlowstoneMC/Bukkit2Sponge to load these plugins"); + logger.log(Level.WARNING, "Suggestion: install https://github" + + ".com/GlowstoneMC/Bukkit2Sponge to load these plugins"); } } - if (!pluginTypeDetector.canaryPlugins.isEmpty() || !pluginTypeDetector.forgefPlugins.isEmpty() || !pluginTypeDetector.forgenPlugins.isEmpty() || !pluginTypeDetector.unrecognizedPlugins.isEmpty()) { + if (!pluginTypeDetector.canaryPlugins.isEmpty() || !pluginTypeDetector.forgefPlugins + .isEmpty() || !pluginTypeDetector.forgenPlugins.isEmpty() + || !pluginTypeDetector.unrecognizedPlugins.isEmpty()) { logger.log(Level.WARNING, "Unsupported plugin types found, will be ignored:"); for (File file : pluginTypeDetector.canaryPlugins) { @@ -1053,14 +1173,18 @@ private void enablePlugins(PluginLoadOrder type) { try { pluginManager.addPermission(perm); } catch (IllegalArgumentException ex) { - getLogger().log(Level.WARNING, "Plugin " + plugin.getDescription().getFullName() + " tried to register permission '" + perm.getName() + "' but it's already registered", ex); + getLogger().log(Level.WARNING, + "Plugin " + plugin.getDescription().getFullName() + + " tried to register permission '" + perm.getName() + + "' but it's already registered", ex); } } try { pluginManager.enablePlugin(plugin); } catch (Throwable ex) { - logger.log(Level.SEVERE, "Error loading " + plugin.getDescription().getFullName(), ex); + logger.log(Level.SEVERE, + "Error loading " + plugin.getDescription().getFullName(), ex); } } } @@ -1070,9 +1194,15 @@ private void enablePlugins(PluginLoadOrder type) { commandMap.registerServerAliases(); DefaultPermissions.registerCorePermissions(); // Default permissions - this.permissionRoot = DefaultPermissions.registerPermission("minecraft", "Gives the user the ability to use all Minecraft utilities and commands"); - this.permissionRootCommand = DefaultPermissions.registerPermission("minecraft.command", "Gives the user the ability to use all Minecraft commands", permissionRoot); - DefaultPermissions.registerPermission("minecraft.command.tell", "Allows the user to send a private message", PermissionDefault.TRUE, permissionRootCommand); + this.permissionRoot = DefaultPermissions + .registerPermission("minecraft", "Gives the user the ability to use all " + + "Minecraft utilities and commands"); + this.permissionRootCommand = DefaultPermissions + .registerPermission("minecraft.command", "Gives the user the ability to use " + + "all Minecraft commands", permissionRoot); + DefaultPermissions + .registerPermission("minecraft.command.tell", "Allows the user to send a " + + "private message", PermissionDefault.TRUE, permissionRootCommand); permissionRootCommand.recalculatePermissibles(); permissionRoot.recalculatePermissibles(); helpMap.initializeCommands(); @@ -1083,15 +1213,20 @@ private void enablePlugins(PluginLoadOrder type) { Map> data = new HashMap<>(); - permConfig.getValues(false).forEach((key, value) -> data.put(key, ((MemorySection) value).getValues(false))); + permConfig.getValues(false).forEach((key, value) -> data + .put(key, ((MemorySection) value).getValues(false))); - List perms = Permission.loadPermissions(data, "Permission node '%s' in permissions config is invalid", PermissionDefault.OP); + List perms = Permission + .loadPermissions(data, "Permission node '%s' in permissions config is " + + "invalid", PermissionDefault.OP); for (Permission perm : perms) { try { pluginManager.addPermission(perm); } catch (IllegalArgumentException ex) { - getLogger().log(Level.WARNING, "Permission config tried to register '" + perm.getName() + "' but it's already registered", ex); + getLogger().log(Level.WARNING, + "Permission config tried to register '" + perm.getName() + + "' but it's already registered", ex); } } } @@ -1129,7 +1264,8 @@ public void reloadData() { @Override public String toString() { - return "GlowServer{name=" + getName() + ",version=" + getVersion() + ",minecraftVersion=" + GAME_VERSION + "}"; + return "GlowServer{name=" + getName() + ",version=" + getVersion() + ",minecraftVersion=" + + GAME_VERSION + "}"; } //////////////////////////////////////////////////////////////////////////// @@ -1164,29 +1300,36 @@ public void addAdvancement(Advancement advancement) { } /** - * Creates an {@link AdvancementsMessage} containing a list of advancements the server has, along with some extra actions. + * Creates an {@link AdvancementsMessage} containing a list of advancements the server has, + * along with some extra actions. * *

This does not affect the server's advancement registry. * - * @param clear whether to clear the advancements on the player's perspective. - * @param remove a list of advancement {@link NamespacedKey NamespacedKeys} to remove from the player's perspective. + * @param clear whether to clear the advancements on the player's perspective. + * @param remove a list of advancement {@link NamespacedKey NamespacedKeys} to remove + * from the player's perspective. * @return a resulting {@link AdvancementsMessage} packet */ - public AdvancementsMessage createAdvancementsMessage(boolean clear, List remove, Player player) { + public AdvancementsMessage createAdvancementsMessage(boolean clear, List remove, + Player player) { return createAdvancementsMessage(advancements, clear, remove, player); } /** - * Creates an {@link AdvancementsMessage} containing a given list of advancements, along with some extra actions. + * Creates an {@link AdvancementsMessage} containing a given list of advancements, along with + * some extra actions. * *

This does not affect the server's advancement registry. * * @param advancements the advancements to add to the player's perspective. - * @param clear whether to clear the advancements on the player's perspective. - * @param remove a list of advancement {@link NamespacedKey NamespacedKeys} to remove from the player's perspective. + * @param clear whether to clear the advancements on the player's perspective. + * @param remove a list of advancement {@link NamespacedKey NamespacedKeys} to remove + * from the player's perspective. * @return a resulting {@link AdvancementsMessage} packet */ - public AdvancementsMessage createAdvancementsMessage(Map advancements, boolean clear, List remove, Player player) { + public AdvancementsMessage createAdvancementsMessage( + Map advancements, boolean clear, List remove, + Player player) { return new AdvancementsMessage(clear, advancements, remove); } @@ -1419,7 +1562,8 @@ public String getName() { @Override public String getVersion() { - return GlowServer.class.getPackage().getImplementationVersion() + " (MC: " + GAME_VERSION + ")"; + return GlowServer.class.getPackage().getImplementationVersion() + " (MC: " + GAME_VERSION + + ")"; } @Override @@ -1511,8 +1655,7 @@ public boolean reloadCommandAliases() { @Override public boolean suggestPlayerNamesWhenNullTabCompletions() { - // TODO: Implementation (1.12.1) - return false; + return config.getBoolean(Key.SUGGEST_PLAYER_NAMES_WHEN_NULL_TAB_COMPLETIONS); } @Override @@ -1548,7 +1691,8 @@ public PluginCommand getPluginCommand(String name) { @Override public Map getCommandAliases() { Map aliases = new HashMap<>(); - ConfigurationSection section = config.getConfigFile(Key.COMMANDS_FILE).getConfigurationSection("aliases"); + ConfigurationSection section = config.getConfigFile(Key.COMMANDS_FILE) + .getConfigurationSection("aliases"); if (section == null) { return aliases; } @@ -1560,7 +1704,8 @@ public Map getCommandAliases() { } @Override - public boolean dispatchCommand(CommandSender sender, String commandLine) throws CommandException { + public boolean dispatchCommand(CommandSender sender, + String commandLine) throws CommandException { if (commandMap.dispatch(sender, commandLine)) { return true; } @@ -1576,7 +1721,8 @@ public boolean dispatchCommand(CommandSender sender, String commandLine) throws @Override public Set getOperators() { - return opsList.getProfiles().stream().map(this::getOfflinePlayer).collect(Collectors.toSet()); + return opsList.getProfiles().stream().map(this::getOfflinePlayer) + .collect(Collectors.toSet()); } //////////////////////////////////////////////////////////////////////////// @@ -1588,7 +1734,7 @@ public Collection getOnlinePlayers() { } /** - * Gets the modifiable set of the server's online players + * Gets the modifiable set of the server's online players. * * @return the server's modifiable set of players. */ @@ -1618,11 +1764,13 @@ public CompletableFuture getOfflinePlayersAsync() { } } - return getPlayerDataService().getOfflinePlayers().thenAcceptAsync(offlinePlayers -> offlinePlayers.stream() - .filter(offline -> !uuids.contains(offline.getUniqueId())).forEach(offline -> { - result.add(offline); - uuids.add(offline.getUniqueId()); - })).thenApply((v) -> result.toArray(new OfflinePlayer[result.size()])); + return getPlayerDataService().getOfflinePlayers() + .thenAcceptAsync(offlinePlayers -> offlinePlayers.stream() + .filter(offline -> !uuids.contains(offline.getUniqueId())) + .forEach(offline -> { + result.add(offline); + uuids.add(offline.getUniqueId()); + })).thenApply((v) -> result.toArray(new OfflinePlayer[result.size()])); } @Override @@ -1758,11 +1906,13 @@ public CompletableFuture getOfflinePlayerAsync(UUID uuid) { return CompletableFuture.completedFuture(onlinePlayer); } - return GlowOfflinePlayer.getOfflinePlayer(this, uuid).thenApply((player) -> (OfflinePlayer) player); + return GlowOfflinePlayer.getOfflinePlayer(this, uuid) + .thenApply((player) -> (OfflinePlayer) player); } private OfflinePlayer getOfflinePlayerFallback(String name) { - return getOfflinePlayer(new PlayerProfile(name, UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes()))); + return getOfflinePlayer(new PlayerProfile(name, UUID + .nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes()))); } @@ -1811,7 +1961,8 @@ public void broadcastPacket(Message message) { @Override public Set getWhitelistedPlayers() { - return whitelist.getProfiles().stream().map(this::getOfflinePlayer).collect(Collectors.toSet()); + return whitelist.getProfiles().stream().map(this::getOfflinePlayer) + .collect(Collectors.toSet()); } @Override @@ -1836,7 +1987,8 @@ public void unbanIP(String address) { @Override public Set getBannedPlayers() { - return nameBans.getBanEntries().stream().map(entry -> getOfflinePlayer(entry.getTarget())).collect(Collectors.toSet()); + return nameBans.getBanEntries().stream().map(entry -> getOfflinePlayer(entry.getTarget())) + .collect(Collectors.toSet()); } @Override @@ -1874,7 +2026,8 @@ private ChunkGenerator getGenerator(String name, Environment environment, WorldT ConfigurationSection worlds = config.getWorlds(); if (worlds != null) { String genName = worlds.getString(name + ".generator", null); - ChunkGenerator generator = WorldCreator.getGeneratorForName(name, genName, getConsoleSender()); + ChunkGenerator generator = WorldCreator + .getGeneratorForName(name, genName, getConsoleSender()); if (generator != null) { return generator; } @@ -1901,7 +2054,8 @@ public GlowWorld createWorld(WorldCreator creator) { return world; } if (isGenerationDisabled()) { - logger.warning("World generation is disabled! World '" + creator.name() + "' will be empty."); + logger.warning( + "World generation is disabled! World '" + creator.name() + "' will be empty."); } if (creator.generator() == null) { @@ -1909,7 +2063,8 @@ public GlowWorld createWorld(WorldCreator creator) { } // GlowWorld's constructor calls addWorld below. - return new GlowWorld(this, creator, storageProviderFactory.createWorldStorageProvider(creator.name())); + return new GlowWorld(this, creator, storageProviderFactory + .createWorldStorageProvider(creator.name())); } /** @@ -2351,7 +2506,8 @@ public boolean getAllowClientMods() { } /** - * Gets the maximum size of the player sample as shown on the client's server list when pinging the server. + * Gets the maximum size of the player sample as shown on the client's server list when pinging + * the server. * * @return the maximum size of the player sample as shown on the client's server list. */ @@ -2371,7 +2527,8 @@ public boolean isGenerationDisabled() { /** * Gets whether the server is OpenCL-capable and allowed to use graphics compute functionality. * - * @return true if the server is capable and allowed to use graphics compute functionality, false otherwise. + * @return true if the server is capable and allowed to use graphics compute functionality, + * false otherwise. */ public boolean doesUseGraphicsCompute() { return isGraphicsComputeAvailable && config.getBoolean(Key.GRAPHICS_COMPUTE); @@ -2387,8 +2544,9 @@ public boolean shouldPreventProxy() { } /** - * Gets the current storage provider factory, or null if none has been set by a plugin and the server has not - * started yet. The storage provider factory will be used to initialize storage for each world. + * Gets the current storage provider factory, or null if none has been set by a plugin and the + * server has not started yet. The storage provider factory will be used to initialize storage + * for each world. * * @return The current storage provider, or null. */ @@ -2397,14 +2555,17 @@ public WorldStorageProviderFactory getStorageProviderFactory() { } /** - * If a storage provider factory has not yet been set, and the server has not fully started yet, this allows plugins - * to set a storage provider factory, which will be used to create a storage provider for each world. Otherwise, - * this will throw an {@link IllegalStateException}. - * @param storageProviderFactory The world storage provider that is attempting to be set. + * If a storage provider factory has not yet been set, and the server has not fully started yet, + * this allows plugins to set a storage provider factory, which will be used to create a storage + * provider for each world. Otherwise, this will throw an {@link IllegalStateException}. + * + * @param storageProviderFactory The world storage provider that is attempting to be + * set. */ public void setStorageProvider(WorldStorageProviderFactory storageProviderFactory) { if (this.storageProviderFactory != null) { - throw new IllegalStateException("Duplicate storage provider attempting to be set. Only one custom storage provider may be provided."); + throw new IllegalStateException("Duplicate storage provider attempting to be set. " + + "Only one custom storage provider may be provided."); } this.storageProviderFactory = storageProviderFactory; } diff --git a/src/main/java/net/glowstone/GlowWorld.java b/src/main/java/net/glowstone/GlowWorld.java index c554abb678..f2159c1337 100644 --- a/src/main/java/net/glowstone/GlowWorld.java +++ b/src/main/java/net/glowstone/GlowWorld.java @@ -45,7 +45,7 @@ import net.glowstone.entity.GlowLightningStrike; import net.glowstone.entity.GlowLivingEntity; import net.glowstone.entity.GlowPlayer; -import net.glowstone.entity.GlowTNTPrimed; +import net.glowstone.entity.GlowTntPrimed; import net.glowstone.entity.objects.GlowFallingBlock; import net.glowstone.entity.objects.GlowItem; import net.glowstone.entity.physics.BoundingBox; @@ -140,29 +140,42 @@ public final class GlowWorld implements World { */ private static int seaLevel; /** - * The server of this world. + * Get the world's parent server. + * + * @return The GlowServer for the world. */ + @Getter private final GlowServer server; /** * The name of this world. */ + @Getter private final String name; /** * The chunk manager. + * + * @return The ChunkManager for the world. */ - private final ChunkManager chunks; + @Getter + private final ChunkManager chunkManager; /** - * The world metadata service used. + * The storage provider for the world. + * + * @return The {@link WorldStorageProvider}. */ - private final WorldStorageProvider storageProvider; + @Getter + private final WorldStorageProvider storage; /** * The world's UUID. */ private final UUID uid; /** * The entity manager. + * + * @return the entity manager */ - private final EntityManager entities = new EntityManager(); + @Getter + private final EntityManager entityManager = new EntityManager(); /** * The chunk generator for this world. */ @@ -174,10 +187,12 @@ public final class GlowWorld implements World { /** * The game rules used in this world. */ - private final GameRuleManager gameRules = new GameRuleManager(); + @Getter + private final GameRuleManager gameRuleMap = new GameRuleManager(); /** * The environment. */ + @Getter private final Environment environment; /** * Whether structure generation is enabled. @@ -186,6 +201,7 @@ public final class GlowWorld implements World { /** * The world seed. */ + @Getter private final long seed; /** * Contains how regular blocks should be pulsed. @@ -198,8 +214,10 @@ public void playEffect(Location location, Effect effect) { } @Override - public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) { - showParticle(location, effect, id, data, offsetX, offsetY, offsetZ, speed, particleCount, radius); + public void playEffect(Location location, Effect effect, int id, int data, float offsetX, + float offsetY, float offsetZ, float speed, int particleCount, int radius) { + showParticle(location, effect, id, data, offsetX, offsetY, offsetZ, speed, + particleCount, radius); } @Override @@ -219,13 +237,14 @@ public LightningStrike strikeLightningEffect(Location loc, boolean isSilent) { /** * The world border. */ + @Getter private final GlowWorldBorder worldBorder; /** * The functions for this world. */ private final Map functions; /** - * A lock kept on the spawn chunks. + * A lock kept on the spawn chunkManager. */ private ChunkLock spawnChunkLock; /** @@ -239,11 +258,11 @@ public LightningStrike strikeLightningEffect(Location loc, boolean isSilent) { */ private Location spawnLocation; /** - * Whether to keep the spawn chunks in memory (prevent them from being unloaded). + * Whether to keep the spawn chunkManager in memory (prevent them from being unloaded). */ private boolean keepSpawnLoaded = true; /** - * Whether to populate chunks when they are anchored. + * Whether to populate chunkManager when they are anchored. */ private boolean populateAnchoredChunks; /** @@ -265,30 +284,40 @@ public LightningStrike strikeLightningEffect(Location loc, boolean isSilent) { /** * How many ticks until the rain/snow status is expected to change. */ - private int rainingTicks; + @Getter + @Setter + private int weatherDuration; /** * Whether it is currently thundering on this world. */ - private boolean currentlyThundering = true; + @Getter + private boolean thundering = true; /** * How many ticks until the thundering status is expected to change. */ - private int thunderingTicks; + @Getter + @Setter + private int thunderDuration; /** * The rain density on the current world tick. */ - private float currentRainDensity; + @Getter + private float rainDensity; /** * The sky darkness on the current world tick. */ - private float currentSkyDarkness; + @Getter + private float skyDarkness; /** * The age of the world, in ticks. */ - private long worldAge; + @Getter + @Setter + private long fullTime; /** * The current world time. */ + @Getter private long time; /** * The time until the next full-save. @@ -297,40 +326,54 @@ public LightningStrike strikeLightningEffect(Location loc, boolean isSilent) { /** * The check to autosave. */ - private boolean autosave = true; + @Getter + @Setter + private boolean autoSave = true; /** * The world's gameplay difficulty. */ + @Getter private Difficulty difficulty; /** * Ticks between when passive mobs are spawned. */ - private long ticksPerAnimal; + @Setter + private int ticksPerAnimalSpawns; /** * Ticks between when hostile mobs are spawned. */ - private long ticksPerMonster; + @Setter + private int ticksPerMonsterSpawns; /** * Per-world spawn limits on hostile mobs. */ - private int monsterLimit; + @Getter + @Setter + private int monsterSpawnLimit; /** * Per-world spawn limits on passive mobs. */ - private int animalLimit; + @Getter + @Setter + private int animalSpawnLimit; /** * Per-world spawn limits on water mobs (squids). */ - private int waterAnimalLimit; + @Getter + @Setter + private int waterAnimalSpawnLimit; /** * Per-world spawn limits on ambient mobs (bats). */ - private int ambientLimit; + @Getter + @Setter + private int ambientSpawnLimit; private Map structures; /** * The maximum height at which players may place blocks. */ - private int maxBuildHeight; + @Getter + private int maxHeight; private Set activeChunksSet = new HashSet<>(); /** @@ -339,7 +382,8 @@ public LightningStrike strikeLightningEffect(Location loc, boolean isSilent) { * @param server The server for the world. * @param creator The WorldCreator to use. */ - public GlowWorld(GlowServer server, WorldCreator creator, WorldStorageProvider worldStorageProvider) { + public GlowWorld(GlowServer server, WorldCreator creator, + WorldStorageProvider worldStorageProvider) { this.server = server; // set up values from WorldCreator @@ -350,27 +394,27 @@ public GlowWorld(GlowServer server, WorldCreator creator, WorldStorageProvider w generator = creator.generator(); - storageProvider = worldStorageProvider; - storageProvider.setWorld(this); + storage = worldStorageProvider; + storage.setWorld(this); populators = generator.getDefaultPopulators(this); // set up values from server defaults - ticksPerAnimal = server.getTicksPerAnimalSpawns(); - ticksPerMonster = server.getTicksPerMonsterSpawns(); - monsterLimit = server.getMonsterSpawnLimit(); - animalLimit = server.getAnimalSpawnLimit(); - waterAnimalLimit = server.getWaterAnimalSpawnLimit(); - ambientLimit = server.getAmbientSpawnLimit(); + ticksPerAnimalSpawns = server.getTicksPerAnimalSpawns(); + ticksPerMonsterSpawns = server.getTicksPerMonsterSpawns(); + monsterSpawnLimit = server.getMonsterSpawnLimit(); + animalSpawnLimit = server.getAnimalSpawnLimit(); + waterAnimalSpawnLimit = server.getWaterAnimalSpawnLimit(); + ambientSpawnLimit = server.getAmbientSpawnLimit(); keepSpawnLoaded = server.keepSpawnLoaded(); populateAnchoredChunks = server.populateAnchoredChunks(); difficulty = server.getDifficulty(); - maxBuildHeight = server.getMaxBuildHeight(); + maxHeight = server.getMaxBuildHeight(); seaLevel = GlowServer.getWorldConfig().getInt(WorldConfig.Key.SEA_LEVEL); worldBorder = new GlowWorldBorder(this); // read in world data WorldFinalValues values; - values = storageProvider.getMetadataService().readWorldData(); + values = storage.getMetadataService().readWorldData(); if (values != null) { if (values.getSeed() == 0L) { seed = creator.seed(); @@ -383,9 +427,10 @@ public GlowWorld(GlowServer server, WorldCreator creator, WorldStorageProvider w uid = UUID.randomUUID(); } - chunks = new ChunkManager(this, storageProvider.getChunkIoService(), generator); - structures = storageProvider.getStructureDataService().readStructuresData(); - functions = storageProvider.getFunctionIoService().readFunctions().stream().collect(Collectors.toMap(CommandFunction::getFullName, function -> function)); + chunkManager = new ChunkManager(this, storage.getChunkIoService(), generator); + structures = storage.getStructureDataService().readStructuresData(); + functions = storage.getFunctionIoService().readFunctions().stream() + .collect(Collectors.toMap(CommandFunction::getFullName, function -> function)); server.addWorld(this); server.getLogger().info("Preparing spawn for " + name + "..."); EventFactory.callEvent(new WorldInitEvent(this)); @@ -405,38 +450,20 @@ public GlowWorld(GlowServer server, WorldCreator creator, WorldStorageProvider w // Various internal mechanisms /** - * Get the world chunk manager. - * - * @return The ChunkManager for the world. - */ - public ChunkManager getChunkManager() { - return chunks; - } - - /** - * Get the world's parent server. - * - * @return The GlowServer for the world. - */ - public GlowServer getServer() { - return server; - } - - /** - * Get a new chunk lock object a player or other party can use to keep chunks loaded. + * Get a new chunk lock object a player or other party can use to keep chunkManager loaded. * * @param desc A description for this chunk lock. * @return The ChunkLock. */ public ChunkLock newChunkLock(String desc) { - return new ChunkLock(chunks, name + ": " + desc); + return new ChunkLock(chunkManager, name + ": " + desc); } /** * Updates all the entities within this world. */ public void pulse() { - List allEntities = new ArrayList<>(entities.getAll()); + List allEntities = new ArrayList<>(entityManager.getAll()); List players = new LinkedList<>(); activeChunksSet.clear(); @@ -457,7 +484,8 @@ public void pulse() { } updateBlocksInActiveChunks(); - // why update blocks before Players or Entities? if there is a specific reason we should document it here. + // why update blocks before Players or Entities? if there is a specific reason we should + // document it here. pulsePlayers(players); resetEntities(allEntities); @@ -473,7 +501,7 @@ public void pulse() { } private void updateActiveChunkCollection(GlowEntity entity) { - // build a set of chunks around each player in this world, the + // build a set of chunkManager around each player in this world, the // server view distance is taken here int radius = server.getViewDistance(); Location playerLocation = entity.getLocation(); @@ -533,8 +561,8 @@ private void updateBlocksInSection(GlowChunk chunk, ChunkSection section, int i) private void saveWorld() { if (--saveTimer <= 0) { saveTimer = AUTOSAVE_TIME; - chunks.unloadOldChunks(); - if (autosave) { + chunkManager.unloadOldChunks(); + if (autoSave) { save(true); } } @@ -543,12 +571,12 @@ private void saveWorld() { private void updateOverworldWeather() { // only tick weather in a NORMAL world if (environment == Environment.NORMAL) { - if (--rainingTicks <= 0) { + if (--weatherDuration <= 0) { setStorm(!currentlyRaining); } - if (--thunderingTicks <= 0) { - setThundering(!currentlyThundering); + if (--thunderDuration <= 0) { + setThundering(!thundering); } updateWeather(); @@ -556,7 +584,7 @@ private void updateOverworldWeather() { } private void informPlayersOfTime() { - if (worldAge % (30 * TICKS_PER_SECOND) == 0) { + if (fullTime % (30 * TICKS_PER_SECOND) == 0) { // Only send the time every 30 seconds; clients are smart. getRawPlayers().forEach(GlowPlayer::sendTime); } @@ -564,12 +592,13 @@ private void informPlayersOfTime() { // Tick the world age and time of day private void updateWorldTime() { - worldAge++; - // worldAge is used to determine when to (periodically) update clients of server time (time of day - "time") + fullTime++; + // fullTime is used to determine when to (periodically) update clients of server time + // (time of day - "time") // also used to occasionally pulse some blocks (see "tickMap" and "requestPulse()") // Modulus by 24000, the tick length of a day - if (gameRules.getBoolean("doDaylightCycle")) { + if (gameRuleMap.getBoolean("doDaylightCycle")) { time = (time + 1) % DAY_LENGTH; } } @@ -591,7 +620,8 @@ private void handleSleepAndWake(List players) { wakeUpAllPlayers(players); // no need to send them the time - handle that normally } else { // otherwise check whether everyone is asleep - boolean skipNight = gameRules.getBoolean("doDaylightCycle") && areAllPlayersSleeping(players); + boolean skipNight = gameRuleMap.getBoolean("doDaylightCycle") + && areAllPlayersSleeping(players); // check gamerule before iterating players (micro-optimization) if (skipNight) { skipRestOfNight(players); @@ -601,7 +631,7 @@ private void handleSleepAndWake(List players) { } private void skipRestOfNight(List players) { - worldAge = (worldAge / DAY_LENGTH + 1) * DAY_LENGTH; + fullTime = (fullTime / DAY_LENGTH + 1) * DAY_LENGTH; time = 0; wakeUpAllPlayers(players, true); // true = send time to all players because we just changed it (to 0), above @@ -626,7 +656,8 @@ private void wakeUpAllPlayers(List players, boolean sendTime) { private boolean areAllPlayersSleeping(List players) { for (GlowPlayer player : players) { - if (!(player.isSleeping() && player.getSleepTicks() >= 100) && !player.isSleepingIgnored()) { + if (!(player.isSleeping() && player.getSleepTicks() >= 100) && !player + .isSleepingIgnored()) { return false; } } @@ -634,11 +665,12 @@ private boolean areAllPlayersSleeping(List players) { } public void broadcastBlockChangeInRange(GlowChunk.Key chunkKey, BlockChangeMessage message) { - getRawPlayers().stream().filter(player -> player.canSeeChunk(chunkKey)).forEach(player -> player.sendBlockChangeForce(message)); + getRawPlayers().stream().filter(player -> player.canSeeChunk(chunkKey)) + .forEach(player -> player.sendBlockChangeForce(message)); } private void maybeStrikeLightningInChunk(int cx, int cz) { - if (environment == Environment.NORMAL && currentlyRaining && currentlyThundering) { + if (environment == Environment.NORMAL && currentlyRaining && thundering) { if (ThreadLocalRandom.current().nextInt(100000) == 0) { strikeLightningInChunk(cx, cz); } @@ -652,27 +684,32 @@ private void strikeLightningInChunk(int cx, int cz) { int z = (cz << 4) + (n >> 8 & 0xF); int y = getHighestBlockYAt(x, z); - // search for living entities in a 6×6×h (there's an error in the wiki!) region from 3 below the + // search for living entities in a 6×6×h (there's an error in the wiki!) region from 3 + // below the // target block up to the world height - BoundingBox searchBox = BoundingBox.fromPositionAndSize(new Vector(x, y, z), new Vector(0, 0, 0)); + BoundingBox searchBox = BoundingBox + .fromPositionAndSize(new Vector(x, y, z), new Vector(0, 0, 0)); Vector vec = new Vector(3, 3, 3); Vector vec2 = new Vector(0, getMaxHeight(), 0); searchBox.minCorner.subtract(vec); searchBox.maxCorner.add(vec).add(vec2); List livingEntities = new LinkedList<>(); // make sure entity can see sky - getEntityManager().getEntitiesInside(searchBox, null).stream().filter(entity -> entity instanceof LivingEntity && !entity.isDead()).forEach(entity -> { - Vector pos = entity.getLocation().toVector(); - int minY = getHighestBlockYAt(pos.getBlockX(), pos.getBlockZ()); - if (pos.getBlockY() >= minY) { - livingEntities.add((LivingEntity) entity); - } - }); + getEntityManager().getEntitiesInside(searchBox, null).stream() + .filter(entity -> entity instanceof LivingEntity && !entity.isDead()) + .forEach(entity -> { + Vector pos = entity.getLocation().toVector(); + int minY = getHighestBlockYAt(pos.getBlockX(), pos.getBlockZ()); + if (pos.getBlockY() >= minY) { + livingEntities.add((LivingEntity) entity); + } + }); // re-target lightning if required if (!livingEntities.isEmpty()) { // randomly choose an entity - LivingEntity entity = livingEntities.get(ThreadLocalRandom.current().nextInt(livingEntities.size())); + LivingEntity entity = livingEntities + .get(ThreadLocalRandom.current().nextInt(livingEntities.size())); // re-target lightning on this living entity Vector newTarget = entity.getLocation().toVector(); x = newTarget.getBlockX(); @@ -694,9 +731,11 @@ private void strikeLightningInChunk(int cx, int cz) { * @return a value between 0 and 1, where 0 = all rays blocked and 1 = all rays unblocked */ public float rayTrace(Location location, GlowEntity entity) { - // TODO: calculate how much of the entity is visible (not blocked by blocks) from the location + // TODO: calculate how much of the entity is visible (not blocked by blocks) from the + // location /* - * To calculate this step through the entity's bounding box and check whether the ray to the point + * To calculate this step through the entity's bounding box and check whether the ray to + * the point * in the bounding box is blocked. * * Return (unblockedRays / allRays) @@ -704,17 +743,8 @@ public float rayTrace(Location location, GlowEntity entity) { return RayUtil.getExposure(location, entity.getLocation()); } - /** - * Gets the entity manager. - * - * @return The entity manager. - */ - public EntityManager getEntityManager() { - return entities; - } - public Collection getRawPlayers() { - return entities.getAll(GlowPlayer.class); + return entityManager.getAll(GlowPlayer.class); } //////////////////////////////////////////////////////////////////////////// @@ -722,13 +752,14 @@ public Collection getRawPlayers() { @Override public List getPlayers() { - return new ArrayList<>(entities.getAll(GlowPlayer.class)); + return new ArrayList<>(entityManager.getAll(GlowPlayer.class)); } /** * Returns a list of entities within a bounding box centered around a Location. * - *

Some implementations may impose artificial restrictions on the size of the search bounding box. + *

Some implementations may impose artificial restrictions on the size of the search bounding + * box. * * @param location The center of the bounding box * @param x 1/2 the size of the box along x axis @@ -738,21 +769,24 @@ public List getPlayers() { */ @Override public Collection getNearbyEntities(Location location, double x, double y, double z) { - Vector minCorner = new Vector(location.getX() - x, location.getY() - y, location.getZ() - z); - Vector maxCorner = new Vector(location.getX() + x, location.getY() + y, location.getZ() + z); + Vector minCorner = new Vector( + location.getX() - x, location.getY() - y, location.getZ() - z); + Vector maxCorner = new Vector( + location.getX() + x, location.getY() + y, location.getZ() + z); BoundingBox searchBox = BoundingBox.fromCorners(minCorner, maxCorner); // TODO: test GlowEntity except = null; - return entities.getEntitiesInside(searchBox, except); + return entityManager.getEntitiesInside(searchBox, except); } @Override public List getEntities() { - return new ArrayList<>(entities.getAll()); + return new ArrayList<>(entityManager.getAll()); } @Override public List getLivingEntities() { - return entities.getAll().stream().filter(e -> e instanceof GlowLivingEntity).map(e -> (GlowLivingEntity) e).collect(Collectors.toCollection(LinkedList::new)); + return entityManager.getAll().stream().filter(e -> e instanceof GlowLivingEntity) + .map(e -> (GlowLivingEntity) e).collect(Collectors.toCollection(LinkedList::new)); } @Override @@ -765,13 +799,14 @@ public Collection getEntitiesByClass(Class... classes) @Override @SuppressWarnings("unchecked") public Collection getEntitiesByClass(Class cls) { - return entities.getAll().stream().filter(e -> cls.isAssignableFrom(e.getClass())).map(e -> (T) e).collect(Collectors.toCollection(ArrayList::new)); + return entityManager.getAll().stream().filter(e -> cls.isAssignableFrom(e.getClass())) + .map(e -> (T) e).collect(Collectors.toCollection(ArrayList::new)); } @Override public Collection getEntitiesByClasses(Class... classes) { ArrayList result = new ArrayList<>(); - for (Entity e : entities.getAll()) { + for (Entity e : entityManager.getAll()) { for (Class cls : classes) { if (cls.isAssignableFrom(e.getClass())) { result.add(e); @@ -800,6 +835,13 @@ public boolean setSpawnLocation(int x, int y, int z) { return setSpawnLocation(new Location(this, x, y, z), true); } + /** + * Sets the spawn location of the world. + * + * @param newSpawn the new spawn location + * @param anchor if true, the spawn is never unloaded while the world is running + * @return true if the spawn location has changed + */ public boolean setSpawnLocation(Location newSpawn, boolean anchor) { Location oldSpawn = spawnLocation; if (newSpawn.equals(oldSpawn)) { @@ -845,9 +887,11 @@ public void setKeepSpawnInMemory(boolean keepLoaded) { // determine a location randomly int spawnX = ThreadLocalRandom.current().nextInt(256) - 128; int spawnZ = ThreadLocalRandom.current().nextInt(256) - 128; - getChunkAt(spawnX >> 4, spawnZ >> 4).load(true); // I'm not sure there's a sane way around this + getChunkAt(spawnX >> 4, spawnZ >> 4) + .load(true); // I'm not sure there's a sane way around this - for (int tries = 0; tries < 1000 && !generator.canSpawn(this, spawnX, spawnZ); ++tries) { + for (int tries = 0; tries < 1000 && !generator.canSpawn(this, spawnX, spawnZ); + ++tries) { spawnX += ThreadLocalRandom.current().nextInt(256) - 128; spawnZ += ThreadLocalRandom.current().nextInt(256) - 128; } @@ -870,13 +914,14 @@ public void setKeepSpawnInMemory(boolean keepLoaded) { prepareSpawn(); } else { // attempt to immediately unload the spawn - chunks.unloadOldChunks(); + chunkManager.unloadOldChunks(); spawnChunkLock = null; } } if (needSpawn) { - setSpawnLocation(spawnLocation.getBlockX(), getHighestBlockYAt(spawnLocation.getBlockX(), spawnLocation.getBlockZ()), spawnLocation.getBlockZ(), false); + setSpawnLocation(spawnLocation.getBlockX(), getHighestBlockYAt(spawnLocation + .getBlockX(), spawnLocation.getBlockZ()), spawnLocation.getBlockZ(), false); } } @@ -908,21 +953,6 @@ private void prepareSpawn() { } } - @Override - public boolean isAutoSave() { - return autosave; - } - - @Override - public void setAutoSave(boolean value) { - autosave = value; - } - - @Override - public Difficulty getDifficulty() { - return difficulty; - } - @Override public void setDifficulty(Difficulty difficulty) { this.difficulty = difficulty; @@ -951,94 +981,14 @@ public boolean getAllowMonsters() { return spawnMonsters; } - @Override - public long getTicksPerAnimalSpawns() { - return ticksPerAnimal; - } - - @Override - public void setTicksPerAnimalSpawns(int ticksPerAnimalSpawns) { - ticksPerAnimal = ticksPerAnimalSpawns; - } - - @Override - public long getTicksPerMonsterSpawns() { - return ticksPerMonster; - } - - @Override - public void setTicksPerMonsterSpawns(int ticksPerMonsterSpawns) { - ticksPerMonster = ticksPerMonsterSpawns; - } - - @Override - public int getMonsterSpawnLimit() { - return monsterLimit; - } - - @Override - public void setMonsterSpawnLimit(int limit) { - monsterLimit = limit; - } - - @Override - public int getAnimalSpawnLimit() { - return animalLimit; - } - - @Override - public void setAnimalSpawnLimit(int limit) { - animalLimit = limit; - } - - @Override - public int getWaterAnimalSpawnLimit() { - return waterAnimalLimit; - } - - @Override - public void setWaterAnimalSpawnLimit(int limit) { - waterAnimalLimit = limit; - } - - @Override - public int getAmbientSpawnLimit() { - return ambientLimit; - } - - @Override - public void setAmbientSpawnLimit(int limit) { - ambientLimit = limit; - } - //////////////////////////////////////////////////////////////////////////// // Various fixed world properties - @Override - public Environment getEnvironment() { - return environment; - } - - @Override - public long getSeed() { - return seed; - } - @Override public UUID getUID() { return uid; } - @Override - public String getName() { - return name; - } - - @Override - public int getMaxHeight() { - return maxBuildHeight; - } - @Override public int getSeaLevel() { if (worldType == WorldType.FLAT) { @@ -1055,6 +1005,18 @@ public boolean canGenerateStructures() { return generateStructures; } + @Override + public long getTicksPerAnimalSpawns() { + // Can't be lombokified because inherited return type is long, not int + return ticksPerAnimalSpawns; + } + + @Override + public long getTicksPerMonsterSpawns() { + // Can't be lombokified because inherited return type is long, not int + return ticksPerMonsterSpawns; + } + //////////////////////////////////////////////////////////////////////////// // force-save @@ -1063,16 +1025,21 @@ public void save() { save(false); } + /** + * Saves world to disk synchronously or asynchronously. + * + * @param async if true, save asynchronously + */ public void save(boolean async) { EventFactory.callEvent(new WorldSaveEvent(this)); // save metadata writeWorldData(async); - // save chunks + // save chunkManager maybeAsync(async, () -> { - for (GlowChunk chunk : chunks.getLoadedChunks()) { - chunks.performSave(chunk); + for (GlowChunk chunk : chunkManager.getLoadedChunks()) { + chunkManager.performSave(chunk); } }); @@ -1087,7 +1054,7 @@ public void save(boolean async) { @Override public ChunkGenerator getGenerator() { - return chunks.getGenerator(); + return chunkManager.getGenerator(); } @Override @@ -1103,15 +1070,18 @@ public boolean generateTree(Location location, TreeType type) { @Override public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) { BlockStateDelegate blockStateDelegate = new BlockStateDelegate(); - if (GlowTree.newInstance(type, ThreadLocalRandom.current(), loc, blockStateDelegate).generate()) { + if (GlowTree.newInstance(type, ThreadLocalRandom.current(), blockStateDelegate) + .generate(loc)) { List blockStates = new ArrayList<>(blockStateDelegate.getBlockStates()); - StructureGrowEvent growEvent = new StructureGrowEvent(loc, type, false, null, blockStates); + StructureGrowEvent growEvent + = new StructureGrowEvent(loc, type, false, null, blockStates); EventFactory.callEvent(growEvent); if (!growEvent.isCancelled()) { for (BlockState state : blockStates) { state.update(true); if (delegate != null) { - delegate.setTypeIdAndData(state.getX(), state.getY(), state.getZ(), state.getTypeId(), state.getRawData()); + delegate.setTypeIdAndData(state.getX(), state.getY(), state.getZ(), state + .getTypeId(), state.getRawData()); } } return true; @@ -1121,6 +1091,7 @@ public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate del } public Map getStructures() { + // TODO: Replace with a facade return structures; } @@ -1138,6 +1109,11 @@ public int getTileEntityCount() { return getBlockEntityCount(); } + /** + * Returns the number of block entities in loaded chunkManager. + * + * @return the number of block entities + */ public int getBlockEntityCount() { int length = 0; for (GlowChunk chunk : getChunkManager().getLoadedChunks()) { @@ -1152,6 +1128,11 @@ public int getTickableTileEntityCount() { return getTickableBlockEntityCount(); } + /** + * Returns the number of tickable block entities in loaded chunkManager. + * + * @return the number of tickable block entities + */ public int getTickableBlockEntityCount() { // TODO: distinguish between block entity types int length = 0; @@ -1214,7 +1195,15 @@ public Block getHighestBlockAt(Location location) { return getBlockAt(location.getBlockX(), getHighestBlockYAt(location), location.getBlockZ()); } - public Block getHighestBlockAt(Location location, Material[] except) { + /** + * Gets the lowest block at the given {@link Location} such that the block + * and all blocks above it are either air or one of the given materials. + * + * @param location Coordinates to get the highest block + * @param except Blocks to exclude in addition to air + * @return Highest non-empty block + */ + public Block getHighestBlockAt(Location location, Material... except) { Block block = getHighestBlockAt(location); List array = Arrays.asList(except); for (int i = 0; i < 6; i++) { @@ -1234,7 +1223,7 @@ public Chunk getChunkAt(Location location) { @Override public GlowChunk getChunkAt(int x, int z) { - return chunks.getChunk(x, z); + return chunkManager.getChunk(x, z); } @Override @@ -1244,7 +1233,8 @@ public Chunk getChunkAt(Block block) { @Override public void getChunkAtAsync(int x, int z, ChunkLoadCallback cb) { - Bukkit.getServer().getScheduler().runTaskAsynchronously(null, () -> cb.onLoad(chunks.getChunk(x, z))); + Bukkit.getServer().getScheduler() + .runTaskAsynchronously(null, () -> cb.onLoad(chunkManager.getChunk(x, z))); } @Override @@ -1267,17 +1257,17 @@ public boolean isChunkLoaded(Chunk chunk) { @Override public boolean isChunkLoaded(int x, int z) { - return chunks.isChunkLoaded(x, z); + return chunkManager.isChunkLoaded(x, z); } @Override public boolean isChunkInUse(int x, int z) { - return chunks.isChunkInUse(x, z); + return chunkManager.isChunkInUse(x, z); } @Override public Chunk[] getLoadedChunks() { - return chunks.getLoadedChunks(); + return chunkManager.getLoadedChunks(); } @Override @@ -1333,7 +1323,7 @@ public boolean unloadChunkRequest(int x, int z, boolean safe) { @Override public boolean regenerateChunk(int x, int z) { - if (!chunks.forceRegeneration(x, z)) { + if (!chunkManager.forceRegeneration(x, z)) { return false; } refreshChunk(x, z); @@ -1360,7 +1350,8 @@ public boolean refreshChunk(int x, int z) { } @Override - public ChunkSnapshot getEmptyChunkSnapshot(int x, int z, boolean includeBiome, boolean includeBiomeTempRain) { + public ChunkSnapshot getEmptyChunkSnapshot(int x, int z, boolean includeBiome, + boolean includeBiomeTempRain) { return new EmptySnapshot(x, z, this, includeBiome, includeBiomeTempRain); } @@ -1380,7 +1371,9 @@ public Biome getBiome(int x, int z) { @Override public void setBiome(int x, int z, Biome bio) { - getChunkAtAsync(x >> 4, z >> 4, chunk -> ((GlowChunk) chunk).setBiome(x & 0xF, z & 0xF, GlowBiome.getId(bio))); + getChunkAtAsync( + x >> 4, z >> 4, chunk -> ((GlowChunk) chunk) + .setBiome(x & 0xF, z & 0xF, GlowBiome.getId(bio))); } @Override @@ -1397,31 +1390,45 @@ public double getHumidity(int x, int z) { // Entity spawning @Override - public T spawn(Location location, Class clazz) throws IllegalArgumentException { + public T spawn(Location location, + Class clazz) throws IllegalArgumentException { return (T) spawn(location, EntityRegistry.getEntity(clazz), SpawnReason.CUSTOM); } @Override - public T spawn(Location location, Class clazz, Consumer function) throws IllegalArgumentException { + public T spawn(Location location, Class clazz, + Consumer function) throws IllegalArgumentException { return null; // TODO: work on type mismatches } - public GlowEntity spawn(Location location, Class clazz, SpawnReason reason) throws IllegalArgumentException { + /** + * Spawns an entity. + * + * @param location the {@link Location} to spawn the entity at + * @param clazz the class of the {@link Entity} to spawn + * @param reason the reason for the spawning of the entity + * @return an instance of the spawned {@link Entity} + * @throws IllegalArgumentException TODO: document the reason this can happen + */ + public GlowEntity spawn(Location location, Class clazz, + SpawnReason reason) throws IllegalArgumentException { GlowEntity entity = null; if (TNTPrimed.class.isAssignableFrom(clazz)) { - entity = new GlowTNTPrimed(location, null); + entity = new GlowTntPrimed(location, null); } if (entity == null) { try { - Constructor constructor = clazz.getConstructor(Location.class); + Constructor constructor = clazz + .getConstructor(Location.class); entity = constructor.newInstance(location); GlowEntity impl = entity; // function.accept(entity); TODO: work on type mismatches EntitySpawnEvent spawnEvent = null; if (entity instanceof LivingEntity) { - spawnEvent = EventFactory.callEvent(new CreatureSpawnEvent((LivingEntity) entity, reason)); + spawnEvent = EventFactory + .callEvent(new CreatureSpawnEvent((LivingEntity) entity, reason)); } else if (!(entity instanceof Item)) { // ItemSpawnEvent is called elsewhere spawnEvent = EventFactory.callEvent(new EntitySpawnEvent(entity)); } @@ -1430,11 +1437,14 @@ public GlowEntity spawn(Location location, Class clazz, Sp entity.remove(); } else { List spawnMessage = entity.createSpawnMessage(); - getRawPlayers().stream().filter(player -> player.canSeeEntity(impl)).forEach(player -> player.getSession().sendAll(spawnMessage.toArray(new Message[spawnMessage.size()]))); + getRawPlayers().stream().filter(player -> player.canSeeEntity(impl)) + .forEach(player -> player.getSession().sendAll(spawnMessage + .toArray(new Message[spawnMessage.size()]))); } } catch (NoSuchMethodException e) { GlowServer.logger.log(Level.WARNING, "Invalid entity spawn: ", e); - } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { + } catch (IllegalAccessException | InstantiationException | InvocationTargetException + e) { GlowServer.logger.log(Level.SEVERE, "Unable to spawn entity: ", e); } } @@ -1447,19 +1457,20 @@ public GlowEntity spawn(Location location, Class clazz, Sp } /** - * Spawn a custom entity at the given {@link Location} + * Spawn a custom entity at the given {@link Location}. * * @param location the {@link Location} to spawn the entity at * @param id the id of the custom entity * @param the class of the {@link Entity} to spawn * @return an instance of the spawned {@link Entity} */ - public T spawnCustomEntity(Location location, String id) throws IllegalArgumentException { + public T spawnCustomEntity(Location location, + String id) throws IllegalArgumentException { return spawnCustomEntity(location, id, SpawnReason.CUSTOM); } /** - * Spawn a custom entity at the given {@link Location}, with the given {@link SpawnReason} + * Spawn a custom entity at the given {@link Location}, with the given {@link SpawnReason}. * * @param location the {@link Location} to spawn the entity at * @param id the id of the custom entity @@ -1467,11 +1478,14 @@ public T spawnCustomEntity(Location location, String id) thro * @param the class of the {@link Entity} to spawn * @return an instance of the spawned {@link Entity} */ - public T spawnCustomEntity(Location location, String id, SpawnReason reason) throws IllegalArgumentException { + @SuppressWarnings("unchecked") + public T spawnCustomEntity(Location location, String id, + SpawnReason reason) throws IllegalArgumentException { Preconditions.checkNotNull(id); CustomEntityDescriptor descriptor = EntityRegistry.getCustomEntityDescriptor(id); if (descriptor == null) { - throw new IllegalArgumentException("Could not find a custom entity descriptor for the given id '" + id + "'"); + throw new IllegalArgumentException( + "Could not find a custom entity descriptor for the given id '" + id + "'"); } return (T) spawn(location, descriptor.getEntityClass(), reason); } @@ -1500,7 +1514,8 @@ public GlowItem dropItemNaturally(Location location, ItemStack item) { @Override public Arrow spawnArrow(Location location, Vector velocity, float speed, float spread) { // Transformative magic - Vector randVec = new Vector(ThreadLocalRandom.current().nextGaussian(), ThreadLocalRandom.current().nextGaussian(), ThreadLocalRandom.current().nextGaussian()); + Vector randVec = new Vector(ThreadLocalRandom.current().nextGaussian(), ThreadLocalRandom + .current().nextGaussian(), ThreadLocalRandom.current().nextGaussian()); randVec.multiply(0.0075 * spread); velocity.normalize(); @@ -1516,17 +1531,20 @@ public Arrow spawnArrow(Location location, Vector velocity, float speed, float s } @Override - public T spawnArrow(Location location, Vector direction, float speed, float spread, Class clazz) { + public T spawnArrow(Location location, Vector direction, float speed, + float spread, Class clazz) { return null; } @Override - public FallingBlock spawnFallingBlock(Location location, MaterialData data) throws IllegalArgumentException { + public FallingBlock spawnFallingBlock(Location location, + MaterialData data) throws IllegalArgumentException { return spawnFallingBlock(location, data.getItemType(), data.getData()); } @Override - public FallingBlock spawnFallingBlock(Location location, Material material, byte data) throws IllegalArgumentException { + public FallingBlock spawnFallingBlock(Location location, Material material, + byte data) throws IllegalArgumentException { if (location == null || material == null) { throw new IllegalArgumentException(); } @@ -1534,7 +1552,8 @@ public FallingBlock spawnFallingBlock(Location location, Material material, byte } @Override - public FallingBlock spawnFallingBlock(Location location, int blockId, byte blockData) throws IllegalArgumentException { + public FallingBlock spawnFallingBlock(Location location, int blockId, + byte blockData) throws IllegalArgumentException { Material material = Material.getMaterial(blockId); return spawnFallingBlock(location, material, blockData); } @@ -1544,7 +1563,8 @@ public Entity spawnEntity(Location loc, EntityType type) { return spawn(loc, type.getEntityClass()); } - private GlowLightningStrike strikeLightningFireEvent(Location loc, boolean effect, boolean isSilent) { + private GlowLightningStrike strikeLightningFireEvent(Location loc, boolean effect, + boolean isSilent) { GlowLightningStrike strike = new GlowLightningStrike(loc, effect, isSilent); LightningStrikeEvent event = new LightningStrikeEvent(this, strike); if (EventFactory.callEvent(event).isCancelled()) { @@ -1566,11 +1586,6 @@ public GlowLightningStrike strikeLightningEffect(Location loc) { //////////////////////////////////////////////////////////////////////////// // Time - @Override - public long getTime() { - return time; - } - @Override public void setTime(long time) { this.time = (time % DAY_LENGTH + DAY_LENGTH) % DAY_LENGTH; @@ -1578,16 +1593,6 @@ public void setTime(long time) { getRawPlayers().forEach(GlowPlayer::sendTime); } - @Override - public long getFullTime() { - return worldAge; - } - - @Override - public void setFullTime(long time) { - worldAge = time; - } - //////////////////////////////////////////////////////////////////////////// // Weather @@ -1610,9 +1615,11 @@ public void setStorm(boolean hasStorm) { // Numbers borrowed from CraftBukkit. if (currentlyRaining) { - setWeatherDuration(ThreadLocalRandom.current().nextInt(HALF_DAY_IN_TICKS) + HALF_DAY_IN_TICKS); + setWeatherDuration( + ThreadLocalRandom.current().nextInt(HALF_DAY_IN_TICKS) + HALF_DAY_IN_TICKS); } else { - setWeatherDuration(ThreadLocalRandom.current().nextInt(WEEK_IN_TICKS) + HALF_DAY_IN_TICKS); + setWeatherDuration( + ThreadLocalRandom.current().nextInt(WEEK_IN_TICKS) + HALF_DAY_IN_TICKS); } // update players @@ -1621,21 +1628,6 @@ public void setStorm(boolean hasStorm) { } } - @Override - public int getWeatherDuration() { - return rainingTicks; - } - - @Override - public void setWeatherDuration(int duration) { - rainingTicks = duration; - } - - @Override - public boolean isThundering() { - return currentlyThundering; - } - @Override public void setThundering(boolean thundering) { // call event @@ -1645,47 +1637,31 @@ public void setThundering(boolean thundering) { } // change weather - currentlyThundering = thundering; + this.thundering = thundering; // Numbers borrowed from CraftBukkit. - if (currentlyThundering) { - setThunderDuration(ThreadLocalRandom.current().nextInt(HALF_DAY_IN_TICKS) + 180 * TICKS_PER_SECOND); + if (this.thundering) { + setThunderDuration(ThreadLocalRandom.current().nextInt(HALF_DAY_IN_TICKS) + + 180 * TICKS_PER_SECOND); } else { - setThunderDuration(ThreadLocalRandom.current().nextInt(WEEK_IN_TICKS) + HALF_DAY_IN_TICKS); + setThunderDuration( + ThreadLocalRandom.current().nextInt(WEEK_IN_TICKS) + HALF_DAY_IN_TICKS); } } - @Override - public int getThunderDuration() { - return thunderingTicks; - } - - @Override - public void setThunderDuration(int duration) { - thunderingTicks = duration; - } - - public float getRainDensity() { - return currentRainDensity; - } - - public float getSkyDarkness() { - return currentSkyDarkness; - } - private void updateWeather() { - float previousRainDensity = currentRainDensity; - float previousSkyDarkness = currentSkyDarkness; + float previousRainDensity = rainDensity; + float previousSkyDarkness = skyDarkness; float rainDensityModifier = currentlyRaining ? .01F : -.01F; - float skyDarknessModifier = currentlyThundering ? .01F : -.01F; - currentRainDensity = Math.max(0, Math.min(1, previousRainDensity + rainDensityModifier)); - currentSkyDarkness = Math.max(0, Math.min(1, previousSkyDarkness + skyDarknessModifier)); + float skyDarknessModifier = thundering ? .01F : -.01F; + rainDensity = Math.max(0, Math.min(1, previousRainDensity + rainDensityModifier)); + skyDarkness = Math.max(0, Math.min(1, previousSkyDarkness + skyDarknessModifier)); - if (previousRainDensity != currentRainDensity) { + if (previousRainDensity != rainDensity) { getRawPlayers().forEach(GlowPlayer::sendRainDensity); } - if (previousSkyDarkness != currentSkyDarkness) { + if (previousSkyDarkness != skyDarkness) { getRawPlayers().forEach(GlowPlayer::sendSkyDarkness); } } @@ -1714,7 +1690,8 @@ public boolean createExplosion(double x, double y, double z, float power, boolea } @Override - public boolean createExplosion(double x, double y, double z, float power, boolean setFire, boolean breakBlocks) { + public boolean createExplosion(double x, double y, double z, float power, boolean setFire, + boolean breakBlocks) { return createExplosion(null, x, y, z, power, setFire, breakBlocks); } @@ -1730,7 +1707,8 @@ public boolean createExplosion(double x, double y, double z, float power, boolea * @param breakBlocks Whether or not to have blocks be destroyed * @return false if explosion was canceled, otherwise true */ - public boolean createExplosion(Entity source, double x, double y, double z, float power, boolean incendiary, boolean breakBlocks) { + public boolean createExplosion(Entity source, double x, double y, double z, float power, + boolean incendiary, boolean breakBlocks) { Explosion explosion = new Explosion(source, this, x, y, z, power, incendiary, breakBlocks); return explosion.explodeWithEvent(); } @@ -1746,7 +1724,9 @@ public void playEffect(Location location, Effect effect, int data) { @Override public void playEffect(Location location, Effect effect, int data, int radius) { int radiusSquared = radius * radius; - getRawPlayers().stream().filter(player -> player.getLocation().distanceSquared(location) <= radiusSquared).forEach(player -> player.playEffect(location, effect, data)); + getRawPlayers().stream() + .filter(player -> player.getLocation().distanceSquared(location) <= radiusSquared) + .forEach(player -> player.playEffect(location, effect, data)); } @Override @@ -1759,14 +1739,28 @@ public void playEffect(Location location, Effect effect, T data, int radius) playEffect(location, effect, GlowEffect.getDataValue(effect, data), radius); } - public void playEffectExceptTo(Location location, Effect effect, int data, int radius, Player exclude) { + /** + * Plays an effect to all but one player within a given radius around a location. + * + * @param location the {@link Location} around which players must be to + * hear the effect + * @param effect the {@link Effect} + * @param data a data bit needed for some effects + * @param radius the radius around the location + * @param exclude the player who won't see the effect + */ + public void playEffectExceptTo(Location location, Effect effect, int data, int radius, + Player exclude) { int radiusSquared = radius * radius; - getRawPlayers().stream().filter(player -> !player.equals(exclude) && player.getLocation().distanceSquared(location) <= radiusSquared).forEach(player -> player.playEffect(location, effect, data)); + getRawPlayers().stream().filter(player -> !player.equals(exclude) + && player.getLocation().distanceSquared(location) <= radiusSquared) + .forEach(player -> player.playEffect(location, effect, data)); } @Override public void playSound(Location location, Sound sound, float volume, float pitch) { - playSound(location, sound, GlowSound.getSoundCategory(GlowSound.getVanillaId(sound)), volume, pitch); + playSound(location, sound, GlowSound + .getSoundCategory(GlowSound.getVanillaId(sound)), volume, pitch); } @Override @@ -1775,17 +1769,21 @@ public void playSound(Location location, String sound, float volume, float pitch } @Override - public void playSound(Location location, Sound sound, SoundCategory category, float volume, float pitch) { + public void playSound(Location location, Sound sound, SoundCategory category, float volume, + float pitch) { if (location == null || sound == null) { return; } double radiusSquared = Math.pow(volume * 16, 2); - getRawPlayers().stream().filter(player -> player.getLocation().distanceSquared(location) <= radiusSquared).forEach(player -> player.playSound(location, sound, category, volume, pitch)); + getRawPlayers().stream() + .filter(player -> player.getLocation().distanceSquared(location) <= radiusSquared) + .forEach(player -> player.playSound(location, sound, category, volume, pitch)); } @Override - public void playSound(Location location, String sound, SoundCategory category, float volume, float pitch) { + public void playSound(Location location, String sound, SoundCategory category, float volume, + float pitch) { playSound(location, GlowSound.getVanillaSound(sound), category, volume, pitch); } @@ -1794,8 +1792,20 @@ public Spigot spigot() { return spigot; } + /** + * Displays the given particle to all players. + * + * @param loc the location + * @param particle the particle type + * @param offsetX TODO: document this parameter + * @param offsetY TODO: document this parameter + * @param offsetZ TODO: document this parameter + * @param speed TODO: document this parameter + * @param amount the number of particles + */ //@Override - public void showParticle(Location loc, Effect particle, float offsetX, float offsetY, float offsetZ, float speed, int amount) { + public void showParticle(Location loc, Effect particle, float offsetX, float offsetY, + float offsetZ, float speed, int amount) { int radius; if (GlowParticle.isLongDistance(particle)) { radius = 48; @@ -1803,18 +1813,37 @@ public void showParticle(Location loc, Effect particle, float offsetX, float off radius = 16; } - showParticle(loc, particle, particle.getId(), 0, offsetX, offsetY, offsetZ, speed, amount, radius); + showParticle(loc, particle, particle + .getId(), 0, offsetX, offsetY, offsetZ, speed, amount, radius); } + /** + * Displays the given particle to all players. + * + * @param loc the location + * @param particle the particle type + * @param id the block or item type ID + * @param data the block or item data + * @param offsetX TODO: document this parameter + * @param offsetY TODO: document this parameter + * @param offsetZ TODO: document this parameter + * @param speed TODO: document this parameter + * @param amount the number of particles + */ //@Override - public void showParticle(Location loc, Effect particle, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int amount, int radius) { + public void showParticle(Location loc, Effect particle, int id, int data, float offsetX, + float offsetY, float offsetZ, float speed, int amount, int radius) { if (loc == null || particle == null) { return; } double radiusSquared = radius * radius; - getRawPlayers().stream().filter(player -> player.getLocation().distanceSquared(loc) <= radiusSquared).forEach(player -> player.spigot().playEffect(loc, particle, id, data, offsetX, offsetY, offsetZ, speed, amount, radius)); + getRawPlayers().stream() + .filter(player -> player.getLocation().distanceSquared(loc) <= radiusSquared) + .forEach(player -> player.spigot() + .playEffect(loc, particle, id, data, offsetX, offsetY, offsetZ, speed, + amount, radius)); } /** @@ -1825,14 +1854,14 @@ public void showParticle(Location loc, Effect particle, int id, int data, float private void writeWorldData(boolean async) { maybeAsync(async, () -> { try { - storageProvider.getMetadataService().writeWorldData(); - storageProvider.getScoreboardIoService().save(); + storage.getMetadataService().writeWorldData(); + storage.getScoreboardIoService().save(); } catch (IOException e) { server.getLogger().severe("Could not save metadata for world: " + getName()); e.printStackTrace(); } - storageProvider.getStructureDataService().writeStructuresData(structures); + storage.getStructureDataService().writeStructuresData(structures); }); } @@ -1865,23 +1894,14 @@ public boolean unload() { return false; } try { - storageProvider.getChunkIoService().unload(); - storageProvider.getScoreboardIoService().unload(); + storage.getChunkIoService().unload(); + storage.getScoreboardIoService().unload(); } catch (IOException e) { return false; } return true; } - /** - * Get the storage provider for the world. - * - * @return The {@link WorldStorageProvider}. - */ - public WorldStorageProvider getStorage() { - return storageProvider; - } - /** * Get the world folder. * @@ -1889,12 +1909,12 @@ public WorldStorageProvider getStorage() { */ @Override public File getWorldFolder() { - return storageProvider.getFolder(); + return storage.getFolder(); } @Override public String[] getGameRules() { - return gameRules.getKeys(); + return gameRuleMap.getKeys(); } //////////////////////////////////////////////////////////////////////////// @@ -1902,12 +1922,12 @@ public String[] getGameRules() { @Override public String getGameRuleValue(String rule) { - return gameRules.getString(rule); + return gameRuleMap.getString(rule); } @Override public boolean setGameRuleValue(String rule, String value) { - if (!gameRules.setValue(rule, value)) { + if (!gameRuleMap.setValue(rule, value)) { return false; } if (rule.equals("doDaylightCycle")) { @@ -1915,7 +1935,10 @@ public boolean setGameRuleValue(String rule, String value) { getRawPlayers().forEach(GlowPlayer::sendTime); } else if (rule.equals("reducedDebugInfo")) { // inform clients about the debug info change - EntityStatusMessage message = new EntityStatusMessage(0, gameRules.getBoolean("reducedDebugInfo") ? EntityStatusMessage.ENABLE_REDUCED_DEBUG_INFO : EntityStatusMessage.DISABLE_REDUCED_DEBUG_INFO); + EntityStatusMessage message = new EntityStatusMessage(0, + gameRuleMap.getBoolean("reducedDebugInfo") + ? EntityStatusMessage.ENABLE_REDUCED_DEBUG_INFO + : EntityStatusMessage.DISABLE_REDUCED_DEBUG_INFO); for (GlowPlayer player : getRawPlayers()) { player.getSession().send(message); } @@ -1925,15 +1948,11 @@ public boolean setGameRuleValue(String rule, String value) { @Override public boolean isGameRule(String rule) { - return gameRules.isGameRule(rule); - } - - @Override - public GlowWorldBorder getWorldBorder() { - return worldBorder; + return gameRuleMap.isGameRule(rule); } public Map getFunctions() { + // TODO: replace this with a facade return functions; } @@ -1953,48 +1972,60 @@ public void spawnParticle(Particle particle, Location location, int count, T } @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, T data) { + public void spawnParticle(Particle particle, double x, double y, double z, int count, + T data) { spawnParticle(particle, x, y, z, count, 0, 0, 0, data); } @Override - public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ) { - spawnParticle(particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ); + public void spawnParticle(Particle particle, Location location, int count, double offsetX, + double offsetY, double offsetZ) { + spawnParticle(particle, location.getX(), location.getY(), location + .getZ(), count, offsetX, offsetY, offsetZ); } @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ) { + public void spawnParticle(Particle particle, double x, double y, double z, int count, + double offsetX, double offsetY, double offsetZ) { spawnParticle(particle, x, y, z, count, offsetX, offsetY, offsetZ, null); } @Override - public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ, T data) { - spawnParticle(particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, data); + public void spawnParticle(Particle particle, Location location, int count, double offsetX, + double offsetY, double offsetZ, T data) { + spawnParticle(particle, location.getX(), location.getY(), location + .getZ(), count, offsetX, offsetY, offsetZ, data); } @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, T data) { + public void spawnParticle(Particle particle, double x, double y, double z, int count, + double offsetX, double offsetY, double offsetZ, T data) { spawnParticle(particle, x, y, z, count, offsetX, offsetY, offsetZ, 1, data); } @Override - public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ, double extra) { - spawnParticle(particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra); + public void spawnParticle(Particle particle, Location location, int count, double offsetX, + double offsetY, double offsetZ, double extra) { + spawnParticle(particle, location.getX(), location.getY(), location + .getZ(), count, offsetX, offsetY, offsetZ, extra); } @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra) { + public void spawnParticle(Particle particle, double x, double y, double z, int count, + double offsetX, double offsetY, double offsetZ, double extra) { spawnParticle(particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, null); } @Override - public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) { + public void spawnParticle(Particle particle, Location location, int count, double offsetX, + double offsetY, double offsetZ, double extra, T data) { if (particle == null) { throw new IllegalArgumentException("particle cannot be null!"); } if (data != null && !particle.getDataType().isInstance(data)) { - throw new IllegalArgumentException("wrong data type " + data.getClass() + " should be " + particle.getDataType()); + throw new IllegalArgumentException( + "wrong data type " + data.getClass() + " should be " + particle.getDataType()); } for (GlowPlayer player : getRawPlayers()) { @@ -2006,12 +2037,10 @@ public void spawnParticle(Particle particle, Location location, int count, d } @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) { - spawnParticle(particle, new Location(this, x, y, z), count, offsetX, offsetY, offsetZ, extra, data); - } - - public GameRuleManager getGameRuleMap() { - return gameRules; + public void spawnParticle(Particle particle, double x, double y, double z, int count, + double offsetX, double offsetY, double offsetZ, double extra, T data) { + spawnParticle(particle, new Location(this, x, y, z), count, offsetX, offsetY, offsetZ, + extra, data); } @Override @@ -2059,24 +2088,26 @@ public Set getListeningPluginChannels() { private void pulseTickMap() { ItemTable itemTable = ItemTable.instance(); - for (Location location : getTickMap()) { + for (Location location : tickMap) { GlowChunk chunk = (GlowChunk) location.getChunk(); if (!chunk.isLoaded()) { continue; } - int typeId = chunk.getType(location.getBlockX() & 0xF, location.getBlockZ() & 0xF, location.getBlockY()); + int typeId = chunk.getType( + location.getBlockX() & 0xF, location.getBlockZ() & 0xF, location.getBlockY()); BlockType type = itemTable.getBlock(Material.getMaterial(typeId)); if (type == null) { cancelPulse(location); continue; } - GlowBlock block = new GlowBlock(chunk, location.getBlockX(), location.getBlockY(), location.getBlockZ()); + GlowBlock block = new GlowBlock(chunk, location.getBlockX(), location + .getBlockY(), location.getBlockZ()); Integer speed = type.getPulseTickSpeed(block); boolean once = type.isPulseOnce(block); if (speed == 0) { continue; } - if (worldAge % speed == 0) { + if (fullTime % speed == 0) { type.receivePulse(block); if (once) { cancelPulse(location); @@ -2086,6 +2117,7 @@ private void pulseTickMap() { } public ConcurrentSet getTickMap() { + // TODO: replace with a facade return tickMap; } @@ -2118,7 +2150,8 @@ public boolean equals(Object obj) { /** * The metadata store class for worlds. */ - private static final class WorldMetadataStore extends MetadataStoreBase implements MetadataStore { + private static final class WorldMetadataStore extends MetadataStoreBase + implements MetadataStore { @Override protected String disambiguate(World subject, String metadataKey) { diff --git a/src/main/java/net/glowstone/GlowWorldBorder.java b/src/main/java/net/glowstone/GlowWorldBorder.java index 1a8fb36fd8..63c1215aca 100644 --- a/src/main/java/net/glowstone/GlowWorldBorder.java +++ b/src/main/java/net/glowstone/GlowWorldBorder.java @@ -1,5 +1,7 @@ package net.glowstone; +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.GlowPlayer; import net.glowstone.net.message.play.game.WorldBorderMessage; import org.bukkit.Location; @@ -9,15 +11,35 @@ public class GlowWorldBorder implements WorldBorder { private final World world; + @Getter private double size; - private double futureSize; + /** + * The target side length the world border is being resized to, in blocks. + * + * @return the target side length the world border is being resized to. + */ + @Getter + private double sizeLerpTarget; private double step; + @Getter private Location center; + @Getter + @Setter private double damageBuffer; - private double damagePerBlock; + @Getter + @Setter + private double damageAmount; + @Getter private int warningTime; + @Getter private int warningDistance; - private long time; + /** + * The delay in ticks until the world border's sides should reach the target length. + * + * @return the delay until the world border's sides should reach the target length. + */ + @Getter + private long sizeLerpTime; private long lastWorldTick; /** @@ -29,23 +51,27 @@ public GlowWorldBorder(World world) { this.world = world; lastWorldTick = world.getFullTime(); size = 60000000; - time = 0; - futureSize = size; + sizeLerpTime = 0; + sizeLerpTarget = size; step = 0; center = new Location(world, 0, 0, 0); damageBuffer = 5; - damagePerBlock = 0.2; + damageAmount = 0.2; warningTime = 15; warningDistance = 5; } /** - * Creates a {@link WorldBorderMessage} containing information to initialize the world border on the client-side. + * Creates a {@link WorldBorderMessage} containing information to initialize the world border on + * the client-side. * * @return a new {@link WorldBorderMessage} for this world border. */ public WorldBorderMessage createMessage() { - return new WorldBorderMessage(WorldBorderMessage.Action.INITIALIZE, center.getX(), center.getZ(), size, futureSize, time * 1000, 29999984, warningTime, warningDistance); + return new WorldBorderMessage( + WorldBorderMessage.Action.INITIALIZE, center.getX(), center.getZ(), + size, sizeLerpTarget, sizeLerpTime * 1000, 29999984, + warningTime, warningDistance); } /** @@ -61,10 +87,10 @@ public void pulse() { lastWorldTick = world.getFullTime(); if (step != 0) { size += step; - if (Math.abs(size - futureSize) < 1) { + if (Math.abs(size - sizeLerpTarget) < 1) { // completed - size = futureSize; - time = 0; + size = sizeLerpTarget; + sizeLerpTime = 0; step = 0; } } @@ -73,8 +99,8 @@ public void pulse() { @Override public void reset() { setSize(60000000); - time = 0; - futureSize = size; + sizeLerpTime = 0; + sizeLerpTarget = size; step = 0; setCenter(new Location(world, 0, 0, 0)); setDamageBuffer(5); @@ -83,15 +109,10 @@ public void reset() { setWarningDistance(5); } - @Override - public double getSize() { - return size; - } - @Override public void setSize(double size) { this.size = size; - this.futureSize = size; + this.sizeLerpTarget = size; broadcast(new WorldBorderMessage(WorldBorderMessage.Action.SET_SIZE, size)); } @@ -103,20 +124,17 @@ public void setSize(double size, long seconds) { } long ticks = seconds * 20; step = (size - this.size) / (double) ticks; - futureSize = size; - time = seconds; - broadcast(new WorldBorderMessage(WorldBorderMessage.Action.LERP_SIZE, this.size, futureSize, time * 1000)); - } - - @Override - public Location getCenter() { - return center; + sizeLerpTarget = size; + sizeLerpTime = seconds; + broadcast(new WorldBorderMessage(WorldBorderMessage.Action.LERP_SIZE, + this.size, sizeLerpTarget, sizeLerpTime * 1000)); } @Override public void setCenter(Location location) { center = location.clone(); - broadcast(new WorldBorderMessage(WorldBorderMessage.Action.SET_CENTER, center.getX(), center.getZ())); + broadcast(new WorldBorderMessage( + WorldBorderMessage.Action.SET_CENTER, center.getX(), center.getZ())); } @Override @@ -124,42 +142,12 @@ public void setCenter(double x, double z) { setCenter(new Location(world, x, 0, z)); } - @Override - public double getDamageBuffer() { - return damageBuffer; - } - - @Override - public void setDamageBuffer(double blocks) { - this.damageBuffer = blocks; - } - - @Override - public double getDamageAmount() { - return damagePerBlock; - } - - @Override - public void setDamageAmount(double damage) { - this.damagePerBlock = damage; - } - - @Override - public int getWarningTime() { - return warningTime; - } - @Override public void setWarningTime(int seconds) { this.warningTime = seconds; broadcast(new WorldBorderMessage(WorldBorderMessage.Action.SET_WARNING_TIME, seconds)); } - @Override - public int getWarningDistance() { - return warningDistance; - } - @Override public void setWarningDistance(int distance) { this.warningDistance = distance; @@ -170,25 +158,8 @@ public void setWarningDistance(int distance) { public boolean isInside(Location location) { Location max = center.clone().add(size / 2, 0, size / 2); Location min = center.clone().subtract(size / 2, 0, size / 2); - return location.getX() <= max.getX() && location.getZ() <= max.getZ() && location.getX() >= min.getX() && location.getZ() >= min.getZ(); - } - - /** - * The target side length the world border is being resized to, in blocks. - * - * @return the target side length the world border is being resized to. - */ - public double getSizeLerpTarget() { - return futureSize; - } - - /** - * The delay in ticks until the world border's sides should reach the target length. - * - * @return the delay until the world border's sides should reach the target length. - */ - public long getSizeLerpTime() { - return time; + return location.getX() <= max.getX() && location.getZ() <= max.getZ() + && location.getX() >= min.getX() && location.getZ() >= min.getZ(); } private void broadcast(WorldBorderMessage message) { diff --git a/src/main/java/net/glowstone/advancement/GlowAdvancement.java b/src/main/java/net/glowstone/advancement/GlowAdvancement.java index 44c715e56f..51825791b7 100644 --- a/src/main/java/net/glowstone/advancement/GlowAdvancement.java +++ b/src/main/java/net/glowstone/advancement/GlowAdvancement.java @@ -56,6 +56,7 @@ public void addRequirement(List criteria) { requirements.add(criteria); } + @Override public List getCriteria() { return criteriaIds; } diff --git a/src/main/java/net/glowstone/block/GlowBlock.java b/src/main/java/net/glowstone/block/GlowBlock.java index 5801563aab..0b60f1ce78 100644 --- a/src/main/java/net/glowstone/block/GlowBlock.java +++ b/src/main/java/net/glowstone/block/GlowBlock.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; +import lombok.Getter; import net.glowstone.GlowServer; import net.glowstone.GlowWorld; import net.glowstone.block.MaterialValueManager.ValueCollection; @@ -54,9 +55,13 @@ public final class GlowBlock implements Block { */ private static final MetadataStore metadata = new BlockMetadataStore(); private static final Map> counterMap = new HashMap<>(); + @Getter private final int x; + @Getter private final int y; + @Getter private final int z; + @Getter private GlowWorld world; /** @@ -76,31 +81,11 @@ public GlowBlock(GlowChunk chunk, int x, int y, int z) { //////////////////////////////////////////////////////////////////////////// // Basics - @Override - public GlowWorld getWorld() { - return world; - } - @Override public GlowChunk getChunk() { return (GlowChunk) world.getChunkAt(this); } - @Override - public int getX() { - return x; - } - - @Override - public int getY() { - return y; - } - - @Override - public int getZ() { - return z; - } - @Override public Location getLocation() { return new Location(getWorld(), x, y, z); diff --git a/src/main/java/net/glowstone/block/GlowBlockState.java b/src/main/java/net/glowstone/block/GlowBlockState.java index 2e42acd4aa..f132eb5233 100644 --- a/src/main/java/net/glowstone/block/GlowBlockState.java +++ b/src/main/java/net/glowstone/block/GlowBlockState.java @@ -1,6 +1,8 @@ package net.glowstone.block; import java.util.List; +import lombok.Getter; +import lombok.Setter; import net.glowstone.GlowWorld; import net.glowstone.chunk.GlowChunk; import org.bukkit.Location; @@ -16,13 +18,23 @@ */ public class GlowBlockState implements BlockState { + @Getter private final GlowWorld world; + @Getter private final int x; + @Getter private final int y; + @Getter private final int z; - private final byte light; - protected int type; + @Getter + private final byte lightLevel; + @Getter + protected int typeId; + @Getter + @Setter protected MaterialData data; + @Getter + @Setter private boolean flowed; //////////////////////////////////////////////////////////////////////////// @@ -38,16 +50,11 @@ public GlowBlockState(GlowBlock block) { x = block.getX(); y = block.getY(); z = block.getZ(); - type = block.getTypeId(); - light = block.getLightLevel(); + typeId = block.getTypeId(); + lightLevel = block.getLightLevel(); makeData(block.getData()); } - @Override - public GlowWorld getWorld() { - return world; - } - @Override public GlowChunk getChunk() { return getBlock().getChunk(); @@ -58,21 +65,6 @@ public GlowBlock getBlock() { return world.getBlockAt(x, y, z); } - @Override - public int getX() { - return x; - } - - @Override - public int getY() { - return y; - } - - @Override - public int getZ() { - return z; - } - @Override public Location getLocation() { return getBlock().getLocation(); @@ -88,7 +80,7 @@ public Location getLocation(Location loc) { @Override public final Material getType() { - return Material.getMaterial(type); + return Material.getMaterial(typeId); } @Override @@ -96,28 +88,13 @@ public final void setType(Material type) { setTypeId(type.getId()); } - @Override - public final int getTypeId() { - return type; - } - @Override public final boolean setTypeId(int type) { - this.type = type; + this.typeId = type; makeData((byte) 0); return true; } - @Override - public final MaterialData getData() { - return data; - } - - @Override - public final void setData(MaterialData data) { - this.data = data; - } - @Override public final byte getRawData() { return getData().getData(); @@ -136,11 +113,6 @@ public boolean isPlaced() { //////////////////////////////////////////////////////////////////////////// // Update - @Override - public final byte getLightLevel() { - return light; - } - @Override public final boolean update() { return update(false, true); @@ -155,25 +127,17 @@ public final boolean update(boolean force) { public boolean update(boolean force, boolean applyPhysics) { Block block = getBlock(); - return (block.getTypeId() == type || force) - && block.setTypeIdAndData(type, getRawData(), applyPhysics); - } - - public boolean getFlowed() { - return flowed; - } - - public void setFlowed(boolean flowed) { - this.flowed = flowed; + return (block.getTypeId() == typeId || force) + && block.setTypeIdAndData(typeId, getRawData(), applyPhysics); } //////////////////////////////////////////////////////////////////////////// // Internals private void makeData(byte data) { - Material mat = Material.getMaterial(type); + Material mat = Material.getMaterial(typeId); if (mat == null) { - this.data = new MaterialData(type, data); + this.data = new MaterialData(typeId, data); } else { this.data = mat.getNewData(data); } @@ -210,7 +174,7 @@ public int hashCode() { result = prime * result + x; result = prime * result + y; result = prime * result + z; - result = prime * result + type; + result = prime * result + typeId; result = prime * result + (data != null ? data.hashCode() : 0); return result; } @@ -234,7 +198,7 @@ public boolean equals(Object obj) { } else if (!data.equals(other.data)) { return false; } - if (type != other.type) { + if (typeId != other.typeId) { return false; } if (world == null) { diff --git a/src/main/java/net/glowstone/block/ItemTable.java b/src/main/java/net/glowstone/block/ItemTable.java index eae0c6d62c..6125cf338c 100644 --- a/src/main/java/net/glowstone/block/ItemTable.java +++ b/src/main/java/net/glowstone/block/ItemTable.java @@ -40,6 +40,7 @@ import net.glowstone.block.blocktype.BlockFlowerPot; import net.glowstone.block.blocktype.BlockFurnace; import net.glowstone.block.blocktype.BlockGrass; +import net.glowstone.block.blocktype.BlockGrassPath; import net.glowstone.block.blocktype.BlockGravel; import net.glowstone.block.blocktype.BlockHay; import net.glowstone.block.blocktype.BlockHopper; @@ -349,8 +350,10 @@ private void registerBuiltins() { reg(Material.DIODE_BLOCK_ON, new BlockRedstoneRepeater()); reg(Material.DIODE_BLOCK_OFF, new BlockRedstoneRepeater()); reg(Material.MAGMA, new BlockMagma()); - reg(Material.NETHER_WART_BLOCK, new BlockDirectDrops(Material.NETHER_WART_BLOCK, ToolType.AXE)); - reg(Material.RED_NETHER_BRICK, new BlockDirectDrops(Material.RED_NETHER_BRICK, ToolType.PICKAXE)); + reg(Material.NETHER_WART_BLOCK, new BlockDirectDrops(Material.NETHER_WART_BLOCK, ToolType + .AXE)); + reg(Material.RED_NETHER_BRICK, new BlockDirectDrops(Material.RED_NETHER_BRICK, ToolType + .PICKAXE)); reg(Material.BONE_BLOCK, new BlockDirectDrops(Material.BONE_BLOCK, ToolType.PICKAXE)); reg(Material.OBSERVER, new BlockObserver()); reg(Material.REDSTONE_COMPARATOR_ON, new BlockRedstoneComparator()); @@ -361,24 +364,35 @@ private void registerBuiltins() { reg(Material.END_ROD, new BlockEndRod()); reg(Material.CONCRETE, new BlockDirectDrops(Material.CONCRETE)); reg(Material.CONCRETE_POWDER, new BlockConcretePowder()); - reg(Material.WHITE_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.WHITE_GLAZED_TERRACOTTA)); - reg(Material.BLACK_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.BLACK_GLAZED_TERRACOTTA)); + reg(Material.WHITE_GLAZED_TERRACOTTA, new BlockDirectDrops(Material + .WHITE_GLAZED_TERRACOTTA)); + reg(Material.BLACK_GLAZED_TERRACOTTA, new BlockDirectDrops(Material + .BLACK_GLAZED_TERRACOTTA)); reg(Material.BLUE_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.BLUE_GLAZED_TERRACOTTA)); - reg(Material.BROWN_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.BROWN_GLAZED_TERRACOTTA)); + reg(Material.BROWN_GLAZED_TERRACOTTA, new BlockDirectDrops(Material + .BROWN_GLAZED_TERRACOTTA)); reg(Material.CYAN_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.CYAN_GLAZED_TERRACOTTA)); reg(Material.GRAY_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.GRAY_GLAZED_TERRACOTTA)); - reg(Material.GREEN_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.GREEN_GLAZED_TERRACOTTA)); - reg(Material.LIGHT_BLUE_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.LIGHT_BLUE_GLAZED_TERRACOTTA)); + reg(Material.GREEN_GLAZED_TERRACOTTA, new BlockDirectDrops(Material + .GREEN_GLAZED_TERRACOTTA)); + reg(Material.LIGHT_BLUE_GLAZED_TERRACOTTA, new BlockDirectDrops(Material + .LIGHT_BLUE_GLAZED_TERRACOTTA)); reg(Material.LIME_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.LIME_GLAZED_TERRACOTTA)); - reg(Material.MAGENTA_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.MAGENTA_GLAZED_TERRACOTTA)); - reg(Material.ORANGE_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.ORANGE_GLAZED_TERRACOTTA)); + reg(Material.MAGENTA_GLAZED_TERRACOTTA, new BlockDirectDrops(Material + .MAGENTA_GLAZED_TERRACOTTA)); + reg(Material.ORANGE_GLAZED_TERRACOTTA, new BlockDirectDrops(Material + .ORANGE_GLAZED_TERRACOTTA)); reg(Material.PINK_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.PINK_GLAZED_TERRACOTTA)); - reg(Material.PURPLE_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.PURPLE_GLAZED_TERRACOTTA)); + reg(Material.PURPLE_GLAZED_TERRACOTTA, new BlockDirectDrops(Material + .PURPLE_GLAZED_TERRACOTTA)); reg(Material.RED_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.RED_GLAZED_TERRACOTTA)); - reg(Material.SILVER_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.SILVER_GLAZED_TERRACOTTA)); - reg(Material.YELLOW_GLAZED_TERRACOTTA, new BlockDirectDrops(Material.YELLOW_GLAZED_TERRACOTTA)); + reg(Material.SILVER_GLAZED_TERRACOTTA, new BlockDirectDrops(Material + .SILVER_GLAZED_TERRACOTTA)); + reg(Material.YELLOW_GLAZED_TERRACOTTA, new BlockDirectDrops(Material + .YELLOW_GLAZED_TERRACOTTA)); reg(Material.CHORUS_FLOWER, new BlockChorusFlower()); reg(Material.CHORUS_PLANT, new BlockChorusPlant()); + reg(Material.GRASS_PATH, new BlockGrassPath(), Sound.BLOCK_GRASS_BREAK); reg(Material.FLINT_AND_STEEL, new ItemFlintAndSteel()); reg(Material.SIGN, new ItemSign()); @@ -473,12 +487,14 @@ private void registerBuiltins() { private void reg(Material material, ItemType type) { if (material.isBlock() != type instanceof BlockType) { - throw new IllegalArgumentException("Cannot mismatch item and block: " + material + ", " + type); + throw new IllegalArgumentException( + "Cannot mismatch item and block: " + material + ", " + type); } if (materialToType.containsKey(material)) { - throw new IllegalArgumentException("Cannot use " + type + " for " + material + ", is already " + materialToType - .get(material)); + throw new IllegalArgumentException( + "Cannot use " + type + " for " + material + ", is already " + materialToType + .get(material)); } materialToType.put(material, type); @@ -496,12 +512,14 @@ private void reg(Material material, ItemType type) { private void reg(Material material, ItemType type, Sound sound) { if (material.isBlock() != type instanceof BlockType) { - throw new IllegalArgumentException("Cannot mismatch item and block: " + material + ", " + type); + throw new IllegalArgumentException( + "Cannot mismatch item and block: " + material + ", " + type); } if (materialToType.containsKey(material)) { - throw new IllegalArgumentException("Cannot use " + type + " for " + material + ", is already " + materialToType - .get(material)); + throw new IllegalArgumentException( + "Cannot use " + type + " for " + material + ", is already " + materialToType + .get(material)); } materialToType.put(material, type); @@ -566,6 +584,12 @@ public ItemType getItem(int id) { return getItem(Material.getMaterial(id)); } + /** + * Returns the {@link ItemType} for a {@link Material}, or null if not a block. + * + * @param mat a {@link Material} + * @return {@code mat} as an {@link ItemType} + */ public ItemType getItem(Material mat) { ItemType type = materialToType.get(mat); if (type == null) { @@ -579,6 +603,12 @@ public BlockType getBlock(int id) { return getBlock(Material.getMaterial(id)); } + /** + * Returns the {@link BlockType} for a {@link Material}, or null if not a block. + * + * @param mat a {@link Material} + * @return {@code mat} as a {@link BlockType}, or null if {@code mat} isn't a block + */ public BlockType getBlock(Material mat) { ItemType itemType = getItem(mat); if (itemType instanceof BlockType) { diff --git a/src/main/java/net/glowstone/block/MaterialValueManager.java b/src/main/java/net/glowstone/block/MaterialValueManager.java index c30f1fd3fa..975adbe4cd 100644 --- a/src/main/java/net/glowstone/block/MaterialValueManager.java +++ b/src/main/java/net/glowstone/block/MaterialValueManager.java @@ -3,12 +3,14 @@ import org.bukkit.Material; /** - * MaterialValueManager provides easily access to {@link Material} related values (e.g. block hardness). + * MaterialValueManager provides easily access to {@link Material} related values (e.g. block + * hardness). */ public interface MaterialValueManager { /** - * Returns the {@link ValueCollection} for the given material. If there aren't concrete values for this material, a {@link ValueCollection} with default values will be returned. + * Returns the {@link ValueCollection} for the given material. If there aren't concrete values + * for this material, a {@link ValueCollection} with default values will be returned. * * @param material The material to look for * @return a {@link ValueCollection} object with values for the given material or default values diff --git a/src/main/java/net/glowstone/block/blocktype/BlockCactus.java b/src/main/java/net/glowstone/block/blocktype/BlockCactus.java index 8d5e895f92..afdd809f1d 100644 --- a/src/main/java/net/glowstone/block/blocktype/BlockCactus.java +++ b/src/main/java/net/glowstone/block/blocktype/BlockCactus.java @@ -1,5 +1,8 @@ package net.glowstone.block.blocktype; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import net.glowstone.EventFactory; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; @@ -7,6 +10,7 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.event.block.BlockGrowEvent; +import org.bukkit.inventory.ItemStack; public class BlockCactus extends BlockType { @@ -123,4 +127,10 @@ private boolean canPlaceNear(Material type) { return true; } } + + @Override + public Collection getDrops(GlowBlock me, ItemStack tool) { + // Overridden for cactus to remove data from the dropped item + return Collections.unmodifiableList(Arrays.asList(new ItemStack(Material.CACTUS))); + } } diff --git a/src/main/java/net/glowstone/block/blocktype/BlockDeadBush.java b/src/main/java/net/glowstone/block/blocktype/BlockDeadBush.java index 1f3ead0b08..699593d2c5 100644 --- a/src/main/java/net/glowstone/block/blocktype/BlockDeadBush.java +++ b/src/main/java/net/glowstone/block/blocktype/BlockDeadBush.java @@ -1,6 +1,9 @@ package net.glowstone.block.blocktype; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.ThreadLocalRandom; import net.glowstone.block.GlowBlock; import org.bukkit.Material; import org.bukkit.block.BlockFace; @@ -25,6 +28,20 @@ public boolean canPlaceAt(GlowBlock block, BlockFace against) { @Override public Collection getDrops(GlowBlock me, ItemStack tool) { - return BlockDropless.EMPTY_STACK; + // If the block below the dead bush is removed, + // the bush will simply disappear without dropping anything. + if (tool == null) { + return BlockDropless.EMPTY_STACK; + } + + // Dead bush drops it self when broken with shears + if (tool.getType().equals(Material.SHEARS)) { + return Collections.unmodifiableList(Arrays.asList(new ItemStack(Material.DEAD_BUSH))); + } + + // Dead bush drops 0-2 sticks when broken without shears + ThreadLocalRandom random = ThreadLocalRandom.current(); + return Collections.unmodifiableList(Arrays.asList( + new ItemStack(Material.STICK,random.nextInt(3)))); } } diff --git a/src/main/java/net/glowstone/block/blocktype/BlockGrassPath.java b/src/main/java/net/glowstone/block/blocktype/BlockGrassPath.java new file mode 100644 index 0000000000..6140e81e78 --- /dev/null +++ b/src/main/java/net/glowstone/block/blocktype/BlockGrassPath.java @@ -0,0 +1,20 @@ +package net.glowstone.block.blocktype; + +import net.glowstone.block.GlowBlock; +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +public class BlockGrassPath extends BlockDirectDrops { + + public BlockGrassPath() { + super(Material.DIRT); + } + + @Override + public void onNearBlockChanged(GlowBlock block, BlockFace face, GlowBlock changedBlock, + Material oldType, byte oldData, Material newType, byte newData) { + if (face == BlockFace.UP && newType.isSolid()) { + block.setType(Material.DIRT); + } + } +} diff --git a/src/main/java/net/glowstone/block/blocktype/BlockLiquid.java b/src/main/java/net/glowstone/block/blocktype/BlockLiquid.java index 03f1605f31..cc4d4f5c7b 100644 --- a/src/main/java/net/glowstone/block/blocktype/BlockLiquid.java +++ b/src/main/java/net/glowstone/block/blocktype/BlockLiquid.java @@ -7,6 +7,7 @@ import static org.bukkit.block.BlockFace.UP; import static org.bukkit.block.BlockFace.WEST; +import lombok.Getter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.ItemTable; @@ -28,6 +29,12 @@ public abstract class BlockLiquid extends BlockType { private static final int TICK_RATE_WATER = 4; private static final int TICK_RATE_LAVA = 20; + /** + * Get the bucket type to replace the empty bucket when the liquid has been collected. + * + * @return The associated bucket types material + */ + @Getter private final Material bucketType; protected BlockLiquid(Material bucketType) { @@ -73,15 +80,6 @@ private static Material getOpposite(Material material) { } } - /** - * Get the bucket type to replace the empty bucket when the liquid has been collected. - * - * @return The associated bucket types material - */ - public Material getBucketType() { - return bucketType; - } - /** * Check if the BlockState block is collectible by a bucket. * @@ -102,7 +100,7 @@ public void placeBlock(GlowPlayer player, GlowBlockState state, BlockFace face, @Override public void onNearBlockChanged(GlowBlock block, BlockFace face, GlowBlock changedBlock, Material oldType, byte oldData, Material newType, byte newData) { - if (block.getState().getFlowed() && !(isWater(newType) || newType == Material.LAVA + if (block.getState().isFlowed() && !(isWater(newType) || newType == Material.LAVA || newType == Material.STATIONARY_LAVA)) { block.getState().setFlowed(false); } @@ -120,7 +118,7 @@ public void receivePulse(GlowBlock block) { } private void calculateFlow(GlowBlock block) { - if (!block.getState().getFlowed()) { + if (!block.getState().isFlowed()) { GlowBlockState state = block.getState(); // see if we can flow down if (block.getY() > 0) { @@ -143,7 +141,7 @@ private void calculateFlow(GlowBlock block) { } } // if we already found a match at this radius, stop - if (state.getFlowed()) { + if (state.isFlowed()) { return; } } diff --git a/src/main/java/net/glowstone/block/blocktype/BlockMushroom.java b/src/main/java/net/glowstone/block/blocktype/BlockMushroom.java index 0531bceb85..4935657e1a 100644 --- a/src/main/java/net/glowstone/block/blocktype/BlockMushroom.java +++ b/src/main/java/net/glowstone/block/blocktype/BlockMushroom.java @@ -75,8 +75,8 @@ public void grow(GlowPlayer player, GlowBlock block) { } Location loc = block.getLocation(); BlockStateDelegate blockStateDelegate = new BlockStateDelegate(); - if (GlowTree.newInstance(type, ThreadLocalRandom.current(), loc, blockStateDelegate) - .generate()) { + if (GlowTree.newInstance(type, ThreadLocalRandom.current(), blockStateDelegate) + .generate(loc)) { List blockStates = new ArrayList<>(blockStateDelegate.getBlockStates()); StructureGrowEvent growEvent = new StructureGrowEvent(loc, type, true, player, blockStates); diff --git a/src/main/java/net/glowstone/block/blocktype/BlockPiston.java b/src/main/java/net/glowstone/block/blocktype/BlockPiston.java index 429b9b83b9..344aa4e322 100644 --- a/src/main/java/net/glowstone/block/blocktype/BlockPiston.java +++ b/src/main/java/net/glowstone/block/blocktype/BlockPiston.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import lombok.Getter; import net.glowstone.GlowWorld; import net.glowstone.block.GlowBlock; import net.glowstone.chunk.GlowChunk; @@ -19,6 +20,12 @@ public class BlockPiston extends BlockDirectional { private static final int PUSH_LIMIT = 12; + /** + * The piston is either non-sticky (default), or has a sticky behavior. + * + * @return true if the piston has a sticky base + */ + @Getter private final boolean sticky; /** Creates the basic (non-sticky) piston block type. */ @@ -41,15 +48,6 @@ public BlockPiston(boolean sticky) { } } - /** - * The piston is either non-sticky (default), or has a sticky behavior. - * - * @return true if the piston has a sticky base - */ - public boolean isSticky() { - return sticky; - } - @Override public void blockDestroy(GlowPlayer player, GlowBlock block, BlockFace face) { if (block.getType() == Material.PISTON_BASE) { diff --git a/src/main/java/net/glowstone/block/blocktype/BlockSapling.java b/src/main/java/net/glowstone/block/blocktype/BlockSapling.java index 73a2e3ff62..50f24d0ce0 100644 --- a/src/main/java/net/glowstone/block/blocktype/BlockSapling.java +++ b/src/main/java/net/glowstone/block/blocktype/BlockSapling.java @@ -111,8 +111,8 @@ private void generateTree(TreeType type, GlowBlock block, GlowPlayer player) { Location loc = block.getLocation(); BlockStateDelegate blockStateDelegate = new BlockStateDelegate(); boolean canGrow = false; - if (GlowTree.newInstance(type, ThreadLocalRandom.current(), loc, blockStateDelegate) - .generate()) { + if (GlowTree.newInstance(type, ThreadLocalRandom.current(), blockStateDelegate) + .generate(loc)) { List blockStates = new ArrayList<>(blockStateDelegate.getBlockStates()); StructureGrowEvent growEvent = new StructureGrowEvent(loc, type, player != null, player, blockStates); diff --git a/src/main/java/net/glowstone/block/blocktype/BlockSugarCane.java b/src/main/java/net/glowstone/block/blocktype/BlockSugarCane.java index 8cf7d67010..5a0eda6548 100644 --- a/src/main/java/net/glowstone/block/blocktype/BlockSugarCane.java +++ b/src/main/java/net/glowstone/block/blocktype/BlockSugarCane.java @@ -49,7 +49,7 @@ public void updateBlock(GlowBlock block) { } GlowBlock blockAbove = block.getRelative(BlockFace.UP); - // check it's the highest block of cactus + // check it's the highest block of sugar cane if (blockAbove.isEmpty()) { // check the current cane height Block blockBelow = block.getRelative(BlockFace.DOWN); @@ -98,6 +98,7 @@ private boolean isNearWater(Block block) { @Override public Collection getDrops(GlowBlock me, ItemStack tool) { + // Overridden for sugar cane to remove data from the dropped item return Collections.unmodifiableList(Arrays.asList(new ItemStack(Material.SUGAR_CANE))); } } diff --git a/src/main/java/net/glowstone/block/blocktype/BlockTnt.java b/src/main/java/net/glowstone/block/blocktype/BlockTnt.java index 9a305a9c1b..a208752c80 100644 --- a/src/main/java/net/glowstone/block/blocktype/BlockTnt.java +++ b/src/main/java/net/glowstone/block/blocktype/BlockTnt.java @@ -3,10 +3,11 @@ import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.entity.GlowPlayer; -import net.glowstone.entity.GlowTNTPrimed; +import net.glowstone.entity.GlowTntPrimed; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.World; +import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; @@ -14,20 +15,33 @@ public class BlockTnt extends BlockType { /** - * Convert a TNT block into a primed TNT entity. + * Convert a TNT block into a primed TNT entity with the player who ignited the TNT. * * @param tntBlock The block to ignite. * @param ignitedByExplosion True if another explosion caused this ignition. + * @param player The player who ignited the TNT. */ - public static void igniteBlock(GlowBlock tntBlock, boolean ignitedByExplosion) { + public static void igniteBlock( + Block tntBlock, boolean ignitedByExplosion, GlowPlayer player) { tntBlock.setType(Material.AIR); World world = tntBlock.getWorld(); - GlowTNTPrimed tnt = (GlowTNTPrimed) world + GlowTntPrimed tnt = (GlowTntPrimed) world .spawnEntity(tntBlock.getLocation().add(0.5, 0, 0.5), EntityType.PRIMED_TNT); + tnt.setSource(player); tnt.setIgnitedByExplosion(ignitedByExplosion); world.playSound(tntBlock.getLocation(), Sound.ENTITY_TNT_PRIMED, 1, 1); } + /** + * Convert a TNT block into a primed TNT entity. + * + * @param tntBlock The block to ignite. + * @param ignitedByExplosion True if another explosion caused this ignition. + */ + public static void igniteBlock(Block tntBlock, boolean ignitedByExplosion) { + igniteBlock(tntBlock, ignitedByExplosion, null); + } + @Override public void afterPlace(GlowPlayer player, GlowBlock block, ItemStack holding, GlowBlockState oldState) { @@ -43,7 +57,7 @@ public void onNearBlockChanged(GlowBlock block, BlockFace face, GlowBlock change @Override public void updatePhysics(GlowBlock me) { if (me.isBlockIndirectlyPowered()) { - igniteBlock(me, false); + igniteBlock(me, false, null); } } diff --git a/src/main/java/net/glowstone/block/blocktype/BlockType.java b/src/main/java/net/glowstone/block/blocktype/BlockType.java index a5377f4c49..fad2fc2175 100644 --- a/src/main/java/net/glowstone/block/blocktype/BlockType.java +++ b/src/main/java/net/glowstone/block/blocktype/BlockType.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import lombok.Getter; import net.glowstone.EventFactory; import net.glowstone.GlowServer; import net.glowstone.block.GlowBlock; @@ -43,6 +44,12 @@ public class BlockType extends ItemType { protected List drops; + /** + * Gets the sound that will be played when a player places the block. + * + * @return The sound to be played + */ + @Getter protected SoundInfo placeSound = new SoundInfo(Sound.BLOCK_WOOD_BREAK, 1F, 0.75F); //////////////////////////////////////////////////////////////////////////// @@ -109,15 +116,6 @@ public Collection getDrops(GlowBlock block, ItemStack tool) { } } - /** - * Gets the sound that will be played when a player places the block. - * - * @return The sound to be played - */ - public SoundInfo getPlaceSound() { - return placeSound; - } - /** * Sets the sound that will be played when a player places the block. * diff --git a/src/main/java/net/glowstone/block/blocktype/IBlockGrowable.java b/src/main/java/net/glowstone/block/blocktype/IBlockGrowable.java index e11d4594fc..562d93704b 100644 --- a/src/main/java/net/glowstone/block/blocktype/IBlockGrowable.java +++ b/src/main/java/net/glowstone/block/blocktype/IBlockGrowable.java @@ -27,7 +27,8 @@ public interface IBlockGrowable { /** * Called to grow a growable block. * - * @param player the player who triggered the growth, this can be null if the growth is natural or by plugin source + * @param player the player who triggered the growth, this can be null if the growth is natural + * or by plugin source * @param block the targeted block to grow */ void grow(GlowPlayer player, GlowBlock block); diff --git a/src/main/java/net/glowstone/block/entity/BannerEntity.java b/src/main/java/net/glowstone/block/entity/BannerEntity.java index 90f0af75a7..00ebb69a18 100644 --- a/src/main/java/net/glowstone/block/entity/BannerEntity.java +++ b/src/main/java/net/glowstone/block/entity/BannerEntity.java @@ -2,6 +2,8 @@ import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.blocktype.BlockBanner; @@ -15,6 +17,8 @@ public class BannerEntity extends BlockEntity { + @Getter + @Setter private DyeColor base = DyeColor.WHITE; private List patterns = new ArrayList<>(); @@ -56,19 +60,13 @@ public void update(GlowPlayer player) { player.sendBlockEntityChange(getBlock().getLocation(), GlowBlockEntity.BANNER, nbt); } - public DyeColor getBase() { - return base; - } - - public void setBase(DyeColor base) { - this.base = base; - } - public List getPatterns() { + // TODO: Defensive copy? return patterns; } public void setPatterns(List patterns) { + // TODO: Defensive copy this.patterns = patterns; } } diff --git a/src/main/java/net/glowstone/block/entity/BeaconEntity.java b/src/main/java/net/glowstone/block/entity/BeaconEntity.java index bffa2d070c..357d269f4f 100644 --- a/src/main/java/net/glowstone/block/entity/BeaconEntity.java +++ b/src/main/java/net/glowstone/block/entity/BeaconEntity.java @@ -1,13 +1,21 @@ package net.glowstone.block.entity; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.util.nbt.CompoundTag; public class BeaconEntity extends BlockEntity { private String lock = null; // todo: support item locks + @Getter + @Setter private int levels = 0; + @Getter + @Setter private int primaryId = 0; + @Getter + @Setter private int secondaryId = 0; public BeaconEntity(GlowBlock block) { @@ -36,28 +44,4 @@ public void saveNbt(CompoundTag tag) { tag.putInt("Primary", primaryId); tag.putInt("Secondary", secondaryId); } - - public int getLevels() { - return levels; - } - - public void setLevels(int levels) { - this.levels = levels; - } - - public int getPrimaryId() { - return primaryId; - } - - public void setPrimaryId(int primaryId) { - this.primaryId = primaryId; - } - - public int getSecondaryId() { - return secondaryId; - } - - public void setSecondaryId(int secondaryId) { - this.secondaryId = secondaryId; - } } diff --git a/src/main/java/net/glowstone/block/entity/BlockEntity.java b/src/main/java/net/glowstone/block/entity/BlockEntity.java index a9022e4718..0ee0558ce4 100644 --- a/src/main/java/net/glowstone/block/entity/BlockEntity.java +++ b/src/main/java/net/glowstone/block/entity/BlockEntity.java @@ -1,12 +1,12 @@ package net.glowstone.block.entity; +import lombok.Getter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.chunk.GlowChunk; import net.glowstone.chunk.GlowChunk.Key; import net.glowstone.entity.GlowPlayer; import net.glowstone.util.nbt.CompoundTag; -import org.bukkit.block.Block; /** * Base class for block entities (blocks with NBT data) in the world. Most access to block entities @@ -14,6 +14,12 @@ */ public abstract class BlockEntity { + /** + * Get the block this BlockEntity is associated with. + * + * @return The entity's block. + */ + @Getter protected final GlowBlock block; private String saveId; @@ -29,15 +35,6 @@ public BlockEntity(GlowBlock block) { //////////////////////////////////////////////////////////////////////////// // Utility stuff - /** - * Get the block this BlockEntity is associated with. - * - * @return The entity's block. - */ - public final Block getBlock() { - return block; - } - /** * Update this BlockEntity's visible state to all players in range. */ diff --git a/src/main/java/net/glowstone/block/entity/BrewingStandEntity.java b/src/main/java/net/glowstone/block/entity/BrewingStandEntity.java index 9de31c5234..1850d63d05 100644 --- a/src/main/java/net/glowstone/block/entity/BrewingStandEntity.java +++ b/src/main/java/net/glowstone/block/entity/BrewingStandEntity.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.entity.state.GlowBrewingStand; @@ -8,6 +10,8 @@ public class BrewingStandEntity extends ContainerEntity { + @Getter + @Setter private int brewTime; public BrewingStandEntity(GlowBlock block) { @@ -15,14 +19,6 @@ public BrewingStandEntity(GlowBlock block) { setSaveId("minecraft:brewing_stand"); } - public int getBrewTime() { - return brewTime; - } - - public void setBrewTime(int brewTime) { - this.brewTime = brewTime; - } - @Override public void loadNbt(CompoundTag tag) { super.loadNbt(tag); diff --git a/src/main/java/net/glowstone/block/entity/ContainerEntity.java b/src/main/java/net/glowstone/block/entity/ContainerEntity.java index d31ba04398..21074c4169 100644 --- a/src/main/java/net/glowstone/block/entity/ContainerEntity.java +++ b/src/main/java/net/glowstone/block/entity/ContainerEntity.java @@ -1,11 +1,11 @@ package net.glowstone.block.entity; +import lombok.Getter; import net.glowstone.block.GlowBlock; import net.glowstone.inventory.GlowInventory; import net.glowstone.io.nbt.NbtSerialization; import net.glowstone.util.nbt.CompoundTag; import net.glowstone.util.nbt.TagType; -import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; /** @@ -13,6 +13,7 @@ */ public abstract class ContainerEntity extends BlockEntity { + @Getter private final GlowInventory inventory; public ContainerEntity(GlowBlock block, GlowInventory inventory) { @@ -20,10 +21,6 @@ public ContainerEntity(GlowBlock block, GlowInventory inventory) { this.inventory = inventory; } - public Inventory getInventory() { - return inventory; - } - public void setContents(ItemStack... contents) { inventory.setContents(contents); } diff --git a/src/main/java/net/glowstone/block/entity/FlowerPotEntity.java b/src/main/java/net/glowstone/block/entity/FlowerPotEntity.java index f0ad571f10..75a2eab731 100644 --- a/src/main/java/net/glowstone/block/entity/FlowerPotEntity.java +++ b/src/main/java/net/glowstone/block/entity/FlowerPotEntity.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.entity.state.GlowFlowerPot; @@ -11,7 +13,8 @@ import org.bukkit.material.MaterialData; public class FlowerPotEntity extends BlockEntity { - + @Getter + @Setter private MaterialData contents; public FlowerPotEntity(GlowBlock block) { @@ -19,14 +22,6 @@ public FlowerPotEntity(GlowBlock block) { setSaveId("minecraft:flower_pot"); } - public MaterialData getContents() { - return contents; - } - - public void setContents(MaterialData contents) { - this.contents = contents; - } - @Override public void loadNbt(CompoundTag tag) { super.loadNbt(tag); diff --git a/src/main/java/net/glowstone/block/entity/FurnaceEntity.java b/src/main/java/net/glowstone/block/entity/FurnaceEntity.java index 5fec20e047..8e467c4c76 100644 --- a/src/main/java/net/glowstone/block/entity/FurnaceEntity.java +++ b/src/main/java/net/glowstone/block/entity/FurnaceEntity.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity; +import lombok.Getter; +import lombok.Setter; import net.glowstone.EventFactory; import net.glowstone.GlowServer; import net.glowstone.block.GlowBlock; @@ -20,7 +22,11 @@ public class FurnaceEntity extends ContainerEntity { + @Getter + @Setter private short burnTime; + @Getter + @Setter private short cookTime; private short burnTimeFuel; @@ -59,22 +65,6 @@ public void loadNbt(CompoundTag tag) { } } - public short getBurnTime() { - return burnTime; - } - - public void setBurnTime(short burnTime) { - this.burnTime = burnTime; - } - - public short getCookTime() { - return cookTime; - } - - public void setCookTime(short cookTime) { - this.cookTime = cookTime; - } - /** * Advances the cooking process for the tick. */ diff --git a/src/main/java/net/glowstone/block/entity/JukeboxEntity.java b/src/main/java/net/glowstone/block/entity/JukeboxEntity.java index 155477f75c..d72443eb69 100644 --- a/src/main/java/net/glowstone/block/entity/JukeboxEntity.java +++ b/src/main/java/net/glowstone/block/entity/JukeboxEntity.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.entity.state.GlowJukebox; @@ -9,6 +11,8 @@ public class JukeboxEntity extends BlockEntity { + @Getter + @Setter private ItemStack playing; public JukeboxEntity(GlowBlock block) { @@ -34,12 +38,4 @@ public void saveNbt(CompoundTag tag) { public GlowBlockState getState() { return new GlowJukebox(block); } - - public ItemStack getPlaying() { - return playing; - } - - public void setPlaying(ItemStack playing) { - this.playing = playing; - } } diff --git a/src/main/java/net/glowstone/block/entity/MobSpawnerEntity.java b/src/main/java/net/glowstone/block/entity/MobSpawnerEntity.java index 7080d3269c..f37d0cc3a6 100644 --- a/src/main/java/net/glowstone/block/entity/MobSpawnerEntity.java +++ b/src/main/java/net/glowstone/block/entity/MobSpawnerEntity.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.entity.state.GlowCreatureSpawner; @@ -10,7 +12,11 @@ public class MobSpawnerEntity extends BlockEntity { private static final EntityType DEFAULT = EntityType.PIG; + @Getter + @Setter private EntityType spawning; + @Getter + @Setter private int delay; public MobSpawnerEntity(GlowBlock block) { @@ -38,31 +44,15 @@ public void loadNbt(CompoundTag tag) { } } - @Override - public void saveNbt(CompoundTag tag) { - super.saveNbt(tag); - tag.putString("EntityId", spawning == null ? "" : spawning.getName()); - tag.putInt("Delay", delay); - } - @Override public GlowBlockState getState() { return new GlowCreatureSpawner(block); } - public EntityType getSpawning() { - return spawning; - } - - public void setSpawning(EntityType spawning) { - this.spawning = spawning; - } - - public int getDelay() { - return delay; - } - - public void setDelay(int delay) { - this.delay = delay; + @Override + public void saveNbt(CompoundTag tag) { + super.saveNbt(tag); + tag.putString("EntityId", spawning == null ? "" : spawning.getName()); + tag.putInt("Delay", delay); } } diff --git a/src/main/java/net/glowstone/block/entity/NoteblockEntity.java b/src/main/java/net/glowstone/block/entity/NoteblockEntity.java index e9a4aaeb1e..f7a38b9fd5 100644 --- a/src/main/java/net/glowstone/block/entity/NoteblockEntity.java +++ b/src/main/java/net/glowstone/block/entity/NoteblockEntity.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.entity.state.GlowNoteBlock; @@ -8,6 +10,8 @@ public class NoteblockEntity extends BlockEntity { + @Getter + @Setter private Note note = new Note(0); public NoteblockEntity(GlowBlock block) { @@ -31,12 +35,4 @@ public void saveNbt(CompoundTag tag) { public GlowBlockState getState() { return new GlowNoteBlock(block); } - - public Note getNote() { - return note; - } - - public void setNote(Note note) { - this.note = note; - } } diff --git a/src/main/java/net/glowstone/block/entity/SignEntity.java b/src/main/java/net/glowstone/block/entity/SignEntity.java index 09fd1afbfe..29165c1d3f 100644 --- a/src/main/java/net/glowstone/block/entity/SignEntity.java +++ b/src/main/java/net/glowstone/block/entity/SignEntity.java @@ -13,6 +13,11 @@ public class SignEntity extends BlockEntity { private final TextMessage[] lines = new TextMessage[4]; + /** + * Creates the entity for the given sign block. + * + * @param block a sign block (wall or post) + */ public SignEntity(GlowBlock block) { super(block); setSaveId("minecraft:sign"); diff --git a/src/main/java/net/glowstone/block/entity/SkullEntity.java b/src/main/java/net/glowstone/block/entity/SkullEntity.java index a6e17cd5ea..82dd7999de 100644 --- a/src/main/java/net/glowstone/block/entity/SkullEntity.java +++ b/src/main/java/net/glowstone/block/entity/SkullEntity.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.blocktype.BlockSkull; @@ -13,8 +15,13 @@ public class SkullEntity extends BlockEntity { + @Getter + @Setter private byte type; + @Getter + @Setter private byte rotation; + @Getter private PlayerProfile owner; public SkullEntity(GlowBlock block) { @@ -32,7 +39,7 @@ public void loadNbt(CompoundTag tag) { } if (tag.containsKey("Owner")) { CompoundTag ownerTag = tag.getCompound("Owner"); - owner = PlayerProfile.fromNBT(ownerTag).join(); + owner = PlayerProfile.fromNbt(ownerTag).join(); } else if (tag.containsKey("ExtraType")) { // Pre-1.8 uses just a name, instead of a profile object String name = tag.getString("ExtraType"); @@ -50,7 +57,7 @@ public void saveNbt(CompoundTag tag) { tag.putByte("Rot", rotation); } if (type == BlockSkull.getType(SkullType.PLAYER) && owner != null) { - tag.putCompound("Owner", owner.toNBT()); + tag.putCompound("Owner", owner.toNbt()); } } @@ -67,26 +74,6 @@ public void update(GlowPlayer player) { player.sendBlockEntityChange(getBlock().getLocation(), GlowBlockEntity.SKULL, nbt); } - public byte getType() { - return type; - } - - public void setType(byte type) { - this.type = type; - } - - public byte getRotation() { - return rotation; - } - - public void setRotation(byte rotation) { - this.rotation = rotation; - } - - public PlayerProfile getOwner() { - return owner; - } - public void setOwner(PlayerProfile owner) { this.owner = owner; type = BlockSkull.getType(SkullType.PLAYER); diff --git a/src/main/java/net/glowstone/block/entity/state/GlowBanner.java b/src/main/java/net/glowstone/block/entity/state/GlowBanner.java index 388de37bb0..d044ea56b6 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowBanner.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowBanner.java @@ -3,6 +3,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.List; +import lombok.Getter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.entity.BannerEntity; @@ -12,7 +13,8 @@ public class GlowBanner extends GlowBlockState implements Banner { - private DyeColor base; + @Getter + private DyeColor baseColor; private List patterns; /** @@ -22,7 +24,7 @@ public class GlowBanner extends GlowBlockState implements Banner { */ public GlowBanner(GlowBlock block) { super(block); - base = getBlockEntity().getBase(); + baseColor = getBlockEntity().getBase(); patterns = getBlockEntity().getPatterns(); } @@ -41,24 +43,21 @@ public int numberOfPatterns() { return patterns.size(); } - @Override - public DyeColor getBaseColor() { - return base; - } - @Override public void setBaseColor(DyeColor dyeColor) { - checkNotNull(base, "Base cannot be null"); - base = dyeColor; + checkNotNull(baseColor, "Base cannot be null"); + baseColor = dyeColor; } @Override public List getPatterns() { + // TODO: Defensive copy return patterns; } @Override public void setPatterns(List patterns) { + // TODO: Defensive copy this.patterns = patterns; } @@ -83,7 +82,7 @@ public boolean update(boolean force, boolean applyPhysics) { boolean result = super.update(force, applyPhysics); if (result) { BannerEntity banner = getBlockEntity(); - banner.setBase(base); + banner.setBase(baseColor); banner.setPatterns(patterns); getBlockEntity().updateInRange(); } diff --git a/src/main/java/net/glowstone/block/entity/state/GlowBeacon.java b/src/main/java/net/glowstone/block/entity/state/GlowBeacon.java index 45f7299037..6cf6dc7ee2 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowBeacon.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowBeacon.java @@ -2,6 +2,7 @@ import java.util.Collection; import java.util.Collections; +import lombok.Getter; import net.glowstone.block.GlowBlock; import net.glowstone.block.entity.BeaconEntity; import org.bukkit.block.Beacon; @@ -12,7 +13,9 @@ public class GlowBeacon extends GlowContainer implements Beacon { + @Getter private PotionEffect primaryEffect; + @Getter private PotionEffect secondaryEffect; /** @@ -44,22 +47,12 @@ public int getTier() { return getBlockEntity().getLevels(); } - @Override - public PotionEffect getPrimaryEffect() { - return primaryEffect; - } - @Override public void setPrimaryEffect(PotionEffectType primary) { this.primaryEffect = new PotionEffect(primary, 7, getTier(), true); getBlockEntity().setPrimaryId(primary.getId()); } - @Override - public PotionEffect getSecondaryEffect() { - return secondaryEffect; - } - @Override public void setSecondaryEffect(PotionEffectType secondary) { this.secondaryEffect = new PotionEffect(secondary, 7, getTier(), true); diff --git a/src/main/java/net/glowstone/block/entity/state/GlowBed.java b/src/main/java/net/glowstone/block/entity/state/GlowBed.java index 9edda88d0f..d933efc486 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowBed.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowBed.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity.state; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.entity.BedEntity; @@ -8,6 +10,8 @@ public class GlowBed extends GlowBlockState implements Bed { + @Getter + @Setter private DyeColor color; public GlowBed(GlowBlock block) { @@ -19,16 +23,6 @@ public BedEntity getBlockEntity() { return (BedEntity) getBlock().getBlockEntity(); } - @Override - public DyeColor getColor() { - return color; - } - - @Override - public void setColor(DyeColor color) { - this.color = color; - } - @Override public boolean update(boolean force, boolean applyPhysics) { boolean result = super.update(force, applyPhysics); diff --git a/src/main/java/net/glowstone/block/entity/state/GlowBrewingStand.java b/src/main/java/net/glowstone/block/entity/state/GlowBrewingStand.java index 49c80dbefe..6d2cbcc3a1 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowBrewingStand.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowBrewingStand.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity.state; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.entity.BrewingStandEntity; import org.bukkit.block.BrewingStand; @@ -7,42 +9,27 @@ public class GlowBrewingStand extends GlowContainer implements BrewingStand { - private int brewTime; + @Getter + @Setter + private int brewingTime; + @Getter + @Setter + private int fuelLevel; public GlowBrewingStand(GlowBlock block) { super(block); - brewTime = getBlockEntity().getBrewTime(); + brewingTime = getBlockEntity().getBrewTime(); } public GlowBrewingStand(GlowBlock block, int brewTime) { super(block); - this.brewTime = brewTime; + this.brewingTime = brewTime; } private BrewingStandEntity getBlockEntity() { return (BrewingStandEntity) getBlock().getBlockEntity(); } - @Override - public int getBrewingTime() { - return brewTime; - } - - @Override - public void setBrewingTime(int brewTime) { - this.brewTime = brewTime; - } - - @Override - public int getFuelLevel() { - return 0; - } - - @Override - public void setFuelLevel(int i) { - - } - @Override public BrewerInventory getInventory() { return (BrewerInventory) getBlockEntity().getInventory(); @@ -53,7 +40,7 @@ public boolean update(boolean force, boolean applyPhysics) { boolean result = super.update(force, applyPhysics); if (result) { BrewingStandEntity stand = getBlockEntity(); - stand.setBrewTime(brewTime); + stand.setBrewTime(brewingTime); stand.updateInRange(); } return result; diff --git a/src/main/java/net/glowstone/block/entity/state/GlowContainer.java b/src/main/java/net/glowstone/block/entity/state/GlowContainer.java index a43f7f792d..40103673e9 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowContainer.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowContainer.java @@ -1,7 +1,13 @@ package net.glowstone.block.entity.state; import com.destroystokyo.paper.loottable.LootableBlockInventory; +import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import org.bukkit.Nameable; @@ -11,6 +17,17 @@ public abstract class GlowContainer extends GlowBlockState implements LootableBlockInventory, Lockable, Nameable, Container { + private final AtomicLong lastFilled = new AtomicLong(-1); + private final AtomicLong nextRefill = new AtomicLong(-1); + private final AtomicLong lootTableSeed = new AtomicLong(0); + private final AtomicReference lootTable = new AtomicReference<>(null); + private final Map playersWhoHaveLooted = new ConcurrentHashMap<>(); + @Getter + @Setter + private String lock; + @Getter + @Setter + private String customName; public GlowContainer(GlowBlock block) { super(block); @@ -20,111 +37,96 @@ public GlowContainer(GlowBlock block) { @Override public String getLootTableName() { - return null; + return lootTable.get(); } @Override public boolean hasLootTable() { - return false; + return lootTable.get() != null; } @Override public String setLootTable(String name) { - return null; + return setLootTable(name, 0); } @Override - public String setLootTable(String s, long l) { - return null; + public String setLootTable(String name, long seed) { + setLootTableSeed(seed); + return lootTable.getAndSet(name); } @Override public long getLootTableSeed() { - return 0; + return lootTableSeed.get(); } @Override public long setLootTableSeed(long seed) { - return 0; + return lootTableSeed.getAndSet(seed); } @Override public void clearLootTable() { - + setLootTable(null); } @Override public boolean isRefillEnabled() { + // TODO return false; } @Override public boolean hasBeenFilled() { - return false; + return lastFilled.get() >= 0; } @Override public boolean hasPlayerLooted(UUID uuid) { - return false; + return playersWhoHaveLooted.containsKey(uuid); } @Override public Long getLastLooted(UUID uuid) { - return null; + return playersWhoHaveLooted.get(uuid); } @Override public boolean setHasPlayerLooted(UUID uuid, boolean b) { - return false; + return b + ? playersWhoHaveLooted.put(uuid, getWorld().getFullTime()) != null + : playersWhoHaveLooted.remove(uuid) != null; } @Override public boolean hasPendingRefill() { - return false; + return getNextRefill() >= Math.max(0, getLastFilled()); } @Override public long getLastFilled() { - return 0; + return lastFilled.get(); } @Override public long getNextRefill() { - return 0; + return nextRefill.get(); } @Override public long setNextRefill(long l) { - return 0; - } - - @Override - public String getCustomName() { - return null; - } - - @Override - public void setCustomName(String s) { - + return nextRefill.getAndSet(l); } @Override public boolean isLocked() { - return false; - } - - @Override - public String getLock() { - return null; - } - - @Override - public void setLock(String s) { - + return getLock() != null; } @Override public Inventory getSnapshotInventory() { + // TODO throw new UnsupportedOperationException(); } } diff --git a/src/main/java/net/glowstone/block/entity/state/GlowCreatureSpawner.java b/src/main/java/net/glowstone/block/entity/state/GlowCreatureSpawner.java index 5bf0f98799..141579ed81 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowCreatureSpawner.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowCreatureSpawner.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity.state; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.entity.MobSpawnerEntity; @@ -8,7 +10,10 @@ public class GlowCreatureSpawner extends GlowBlockState implements CreatureSpawner { - private EntityType spawned; + @Getter + @Setter + private EntityType spawnedType; + @Getter private int delay; /** @@ -20,7 +25,7 @@ public GlowCreatureSpawner(GlowBlock block) { super(block); MobSpawnerEntity spawner = getBlockEntity(); - spawned = spawner.getSpawning(); + spawnedType = spawner.getSpawning(); delay = spawner.getDelay(); } @@ -33,18 +38,13 @@ public boolean update(boolean force, boolean applyPhysics) { boolean result = super.update(force, applyPhysics); if (result) { MobSpawnerEntity spawner = getBlockEntity(); - spawner.setSpawning(spawned); + spawner.setSpawning(spawnedType); spawner.setDelay(delay); spawner.updateInRange(); } return result; } - @Override - public int getDelay() { - return delay; - } - @Override public void setDelay(int i) { if (i < 0) { @@ -56,27 +56,17 @@ public void setDelay(int i) { //////////////////////////////////////////////////////////////////////////// // Spawned Type - @Override - public EntityType getSpawnedType() { - return spawned; - } - - @Override - public void setSpawnedType(EntityType creatureType) { - spawned = creatureType; - } - @Override public void setCreatureTypeByName(String creatureType) { EntityType type = EntityType.fromName(creatureType); if (type != null) { - spawned = type; + spawnedType = type; } } @Override public String getCreatureTypeName() { - return spawned.getName(); + return spawnedType.getName(); } } diff --git a/src/main/java/net/glowstone/block/entity/state/GlowDispenser.java b/src/main/java/net/glowstone/block/entity/state/GlowDispenser.java index bd543458a9..22356e1789 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowDispenser.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowDispenser.java @@ -2,6 +2,7 @@ import java.util.Map; import java.util.concurrent.ThreadLocalRandom; +import lombok.Getter; import net.glowstone.block.GlowBlock; import net.glowstone.block.entity.DispenserEntity; import net.glowstone.dispenser.ArmorDispenseBehavior; @@ -11,7 +12,7 @@ import net.glowstone.dispenser.DispenseBehaviorRegistry; import net.glowstone.dispenser.EmptyBucketDispenseBehavior; import net.glowstone.dispenser.FlintAndSteelDispenseBehavior; -import net.glowstone.dispenser.TNTDispenseBehavior; +import net.glowstone.dispenser.TntDispenseBehavior; import net.glowstone.util.InventoryUtil; import org.bukkit.Effect; import org.bukkit.Material; @@ -24,6 +25,7 @@ public class GlowDispenser extends GlowContainer implements Dispenser, BlockProjectileSource { + @Getter private static final DispenseBehaviorRegistry dispenseBehaviorRegistry = new DispenseBehaviorRegistry(); @@ -31,10 +33,6 @@ public GlowDispenser(GlowBlock block) { super(block); } - public static DispenseBehaviorRegistry getDispenseBehaviorRegistry() { - return dispenseBehaviorRegistry; - } - /** * Registers all vanilla dispense behaviors. */ @@ -47,7 +45,7 @@ public static void register() { .putBehavior(Material.BUCKET, new EmptyBucketDispenseBehavior()); getDispenseBehaviorRegistry() .putBehavior(Material.FLINT_AND_STEEL, new FlintAndSteelDispenseBehavior()); - getDispenseBehaviorRegistry().putBehavior(Material.TNT, new TNTDispenseBehavior()); + getDispenseBehaviorRegistry().putBehavior(Material.TNT, new TntDispenseBehavior()); ArmorDispenseBehavior armorDispenseBehavior = new ArmorDispenseBehavior(); getDispenseBehaviorRegistry().putBehavior(Material.LEATHER_BOOTS, armorDispenseBehavior); diff --git a/src/main/java/net/glowstone/block/entity/state/GlowFlowerPot.java b/src/main/java/net/glowstone/block/entity/state/GlowFlowerPot.java index ab071618b1..30cb0e1fb9 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowFlowerPot.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowFlowerPot.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity.state; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.entity.FlowerPotEntity; @@ -8,6 +10,8 @@ public class GlowFlowerPot extends GlowBlockState implements FlowerPot { + @Getter + @Setter private MaterialData contents; /** @@ -33,16 +37,6 @@ private boolean hasFlowerPotData() { return getData() instanceof org.bukkit.material.FlowerPot; } - @Override - public MaterialData getContents() { - return contents; - } - - @Override - public void setContents(MaterialData contents) { - this.contents = contents; - } - @Override public boolean update(boolean force, boolean applyPhysics) { // Pre-1.7 uses block data. diff --git a/src/main/java/net/glowstone/block/entity/state/GlowFurnace.java b/src/main/java/net/glowstone/block/entity/state/GlowFurnace.java index 24a3cf53cb..be7ad37bcd 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowFurnace.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowFurnace.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity.state; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.entity.FurnaceEntity; import org.bukkit.block.Furnace; @@ -7,7 +9,11 @@ public class GlowFurnace extends GlowContainer implements Furnace { + @Getter + @Setter private short burnTime; + @Getter + @Setter private short cookTime; /** @@ -40,26 +46,6 @@ private FurnaceEntity getBlockEntity() { return (FurnaceEntity) getBlock().getBlockEntity(); } - @Override - public short getBurnTime() { - return burnTime; - } - - @Override - public void setBurnTime(short burnTime) { - this.burnTime = burnTime; - } - - @Override - public short getCookTime() { - return cookTime; - } - - @Override - public void setCookTime(short cookTime) { - this.cookTime = cookTime; - } - @Override public FurnaceInventory getInventory() { return (FurnaceInventory) getBlockEntity().getInventory(); diff --git a/src/main/java/net/glowstone/block/entity/state/GlowJukebox.java b/src/main/java/net/glowstone/block/entity/state/GlowJukebox.java index 5746d7be09..587942e95b 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowJukebox.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowJukebox.java @@ -1,6 +1,7 @@ package net.glowstone.block.entity.state; import java.util.Collection; +import lombok.Getter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.entity.JukeboxEntity; @@ -12,7 +13,8 @@ public class GlowJukebox extends GlowBlockState implements Jukebox { - private ItemStack playing; + @Getter + private ItemStack playingItem; /** * Creates a block state for the given jukebox block. @@ -25,7 +27,7 @@ public GlowJukebox(GlowBlock block) { throw new IllegalArgumentException( "GlowJukebox: expected JUKEBOX, got " + block.getType()); } - playing = getBlockEntity().getPlaying(); + playingItem = getBlockEntity().getPlaying(); } private JukeboxEntity getBlockEntity() { @@ -36,21 +38,17 @@ private JukeboxEntity getBlockEntity() { public boolean update(boolean force, boolean applyPhysics) { boolean result = super.update(force, applyPhysics); if (result) { - getBlockEntity().setPlaying(playing); + getBlockEntity().setPlaying(playingItem); } return result; } - public ItemStack getPlayingItem() { - return playing; - } - //////////////////////////////////////////////////////////////////////////// // Implementation @Override public Material getPlaying() { - return playing.getType(); + return playingItem.getType(); } @Override @@ -62,9 +60,9 @@ public boolean isPlaying() { public void setPlaying(Material record) { int id = 0; if (record == null || record == Material.AIR) { - playing = null; + playingItem = null; } else { - playing = new ItemStack(record); + playingItem = new ItemStack(record); id = record.getId(); } Collection players = getWorld().getRawPlayers(); @@ -77,7 +75,7 @@ public void setPlaying(Material record) { @Override public boolean eject() { if (isPlaying()) { - getWorld().dropItemNaturally(getLocation(), playing); + getWorld().dropItemNaturally(getLocation(), playingItem); setPlaying(null); return true; } diff --git a/src/main/java/net/glowstone/block/entity/state/GlowNoteBlock.java b/src/main/java/net/glowstone/block/entity/state/GlowNoteBlock.java index 437d1054a8..2cfee90a33 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowNoteBlock.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowNoteBlock.java @@ -2,6 +2,7 @@ import static com.google.common.base.Preconditions.checkNotNull; +import lombok.Getter; import net.glowstone.EventFactory; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; @@ -18,8 +19,14 @@ public class GlowNoteBlock extends GlowBlockState implements NoteBlock { + @Getter private Note note; + /** + * Creates the instance for a note block. + * + * @param block the note block + */ public GlowNoteBlock(GlowBlock block) { super(block); if (block.getType() != Material.NOTE_BLOCK) { @@ -152,11 +159,6 @@ public boolean update(boolean force, boolean applyPhysics) { return result; } - @Override - public Note getNote() { - return note; - } - @Override public void setNote(Note note) { checkNotNull(note); diff --git a/src/main/java/net/glowstone/block/entity/state/GlowSign.java b/src/main/java/net/glowstone/block/entity/state/GlowSign.java index 763c1137c0..9aa6d0738f 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowSign.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowSign.java @@ -10,6 +10,11 @@ public class GlowSign extends GlowBlockState implements Sign { private final String[] lines; + /** + * Creates the instance for the given sign block. + * + * @param block a sign block (wall or post) + */ public GlowSign(GlowBlock block) { super(block); if (block.getType() != Material.WALL_SIGN && block.getType() != Material.SIGN_POST) { @@ -25,7 +30,7 @@ private SignEntity getBlockEntity() { @Override public String[] getLines() { - return lines; + return lines.clone(); } @Override diff --git a/src/main/java/net/glowstone/block/entity/state/GlowSkull.java b/src/main/java/net/glowstone/block/entity/state/GlowSkull.java index e8ccdabfab..0fe8a2bebb 100644 --- a/src/main/java/net/glowstone/block/entity/state/GlowSkull.java +++ b/src/main/java/net/glowstone/block/entity/state/GlowSkull.java @@ -1,5 +1,7 @@ package net.glowstone.block.entity.state; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.block.blocktype.BlockSkull; @@ -14,13 +16,21 @@ public class GlowSkull extends GlowBlockState implements Skull { - private SkullType type; + @Getter + private SkullType skullType; private PlayerProfile owner; + @Getter + @Setter private BlockFace rotation; + /** + * Creates the instance for the given block. + * + * @param block a head/skull block + */ public GlowSkull(GlowBlock block) { super(block); - type = BlockSkull.getType(getBlockEntity().getType()); + skullType = BlockSkull.getType(getBlockEntity().getType()); rotation = Position.getDirection(getBlockEntity().getRotation()); owner = getBlockEntity().getOwner(); } @@ -34,11 +44,11 @@ public boolean update(boolean force, boolean applyPhysics) { boolean result = super.update(force, applyPhysics); if (result) { SkullEntity skull = getBlockEntity(); - skull.setType(BlockSkull.getType(type)); + skull.setType(BlockSkull.getType(skullType)); if (BlockSkull.canRotate((org.bukkit.material.Skull) getBlock().getState().getData())) { skull.setRotation(Position.getDirection(rotation)); } - if (type == SkullType.PLAYER) { + if (skullType == SkullType.PLAYER) { skull.setOwner(owner); } getBlockEntity().updateInRange(); @@ -77,26 +87,11 @@ public void setOwningPlayer(OfflinePlayer offlinePlayer) { this.owner = new PlayerProfile(offlinePlayer.getName(), offlinePlayer.getUniqueId()); } - @Override - public BlockFace getRotation() { - return rotation; - } - - @Override - public void setRotation(BlockFace rotation) { - this.rotation = rotation; - } - - @Override - public SkullType getSkullType() { - return type; - } - @Override public void setSkullType(SkullType type) { if (type != SkullType.PLAYER) { owner = null; } - this.type = type; + this.skullType = type; } } diff --git a/src/main/java/net/glowstone/block/itemtype/ItemBoat.java b/src/main/java/net/glowstone/block/itemtype/ItemBoat.java index 670052eda2..04657d93af 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemBoat.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemBoat.java @@ -28,15 +28,19 @@ public void rightClickAir(GlowPlayer player, ItemStack holding) { } @Override - public void rightClickBlock(GlowPlayer player, GlowBlock target, BlockFace face, ItemStack holding, Vector clickedLoc, EquipmentSlot hand) { - // Two cases are handled here: Either the player clicked on a block on the land or beneath water + public void rightClickBlock( + GlowPlayer player, GlowBlock target, BlockFace face, ItemStack holding, + Vector clickedLoc, EquipmentSlot hand) { + // Two cases are handled here: Either the player clicked on a block on the land or beneath + // water placeBoat(player); } private void placeBoat(GlowPlayer player) { Block targetBlock = player.getTargetBlock((Set) null, 5); - if (targetBlock != null && !targetBlock.isEmpty() && targetBlock.getRelative(BlockFace.UP).isEmpty()) { + if (targetBlock != null && !targetBlock.isEmpty() + && targetBlock.getRelative(BlockFace.UP).isEmpty()) { Location location = targetBlock.getRelative(BlockFace.UP).getLocation(); // center boat on cursor location location.add(0.6875f, 0, 0.6875f); diff --git a/src/main/java/net/glowstone/block/itemtype/ItemBucket.java b/src/main/java/net/glowstone/block/itemtype/ItemBucket.java index 28d2f23b36..febe943240 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemBucket.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemBucket.java @@ -35,7 +35,9 @@ public void rightClickAir(GlowPlayer player, ItemStack holding) { } @Override - public void rightClickBlock(GlowPlayer player, GlowBlock target, BlockFace face, ItemStack holding, Vector clickedLoc, EquipmentSlot hand) { + public void rightClickBlock( + GlowPlayer player, GlowBlock target, BlockFace face, ItemStack holding, + Vector clickedLoc, EquipmentSlot hand) { clickBucket(player, holding); } @@ -47,7 +49,8 @@ private void clickBucket(GlowPlayer player, ItemStack holding) { BlockType targetBlockType = null; boolean validTarget = false; - // Find the next available non-air liquid block type which is collectible in a radius of 5 blocks + // Find the next available non-air liquid block type which is collectible in a radius of 5 + // blocks while (itr.hasNext()) { previousTarget = target; target = itr.next(); diff --git a/src/main/java/net/glowstone/block/itemtype/ItemChorusFruit.java b/src/main/java/net/glowstone/block/itemtype/ItemChorusFruit.java index 70999bb7ff..34c5e5ac10 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemChorusFruit.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemChorusFruit.java @@ -43,32 +43,32 @@ public boolean eat(GlowPlayer player, ItemStack item) { } private Location getSafeLocation(Location loc) { - int yCoord = loc.getBlockY(); + int blockY = loc.getBlockY(); World world = loc.getWorld(); - if (yCoord > world.getHighestBlockYAt(loc)) { - yCoord = world.getHighestBlockYAt(loc) + 1; + if (blockY > world.getHighestBlockYAt(loc)) { + blockY = world.getHighestBlockYAt(loc) + 1; } boolean found = false; boolean hadSpace = false; - while (yCoord > 0) { - Block current = world.getBlockAt(loc.getBlockX(), yCoord, loc.getBlockZ()); + while (blockY > 0) { + Block current = world.getBlockAt(loc.getBlockX(), blockY, loc.getBlockZ()); if (current.isEmpty() && current.getRelative(BlockFace.UP).isEmpty()) { hadSpace = true; } else if (hadSpace) { if (current.getType().isSolid()) { found = true; - yCoord++; + blockY++; break; } else { hadSpace = false; } } - yCoord--; + blockY--; } if (found) { - loc.setY(yCoord); - loc.setX(loc.getBlockX() - + 0.5); //TODO: Do a proper bounding box check instead of just centering the location + loc.setY(blockY); + loc.setX(loc.getBlockX() + 0.5); + //TODO: Do a proper bounding box check instead of just centering the location loc.setZ(loc.getBlockZ() + 0.5); return loc; } else { diff --git a/src/main/java/net/glowstone/block/itemtype/ItemFilledBucket.java b/src/main/java/net/glowstone/block/itemtype/ItemFilledBucket.java index 45f805693a..3e8867c581 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemFilledBucket.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemFilledBucket.java @@ -1,5 +1,6 @@ package net.glowstone.block.itemtype; +import lombok.Getter; import net.glowstone.EventFactory; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; @@ -16,6 +17,7 @@ public class ItemFilledBucket extends ItemType { + @Getter private final BlockType liquid; public ItemFilledBucket(Material liquid) { @@ -23,10 +25,6 @@ public ItemFilledBucket(Material liquid) { setMaxStackSize(1); } - public BlockType getLiquid() { - return liquid; - } - @Override public void rightClickBlock(GlowPlayer player, GlowBlock against, BlockFace face, ItemStack holding, Vector clickedLoc, EquipmentSlot hand) { diff --git a/src/main/java/net/glowstone/block/itemtype/ItemFishCooked.java b/src/main/java/net/glowstone/block/itemtype/ItemFishCooked.java index 965d86d1ea..77fac23e70 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemFishCooked.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemFishCooked.java @@ -12,8 +12,9 @@ protected float getSaturation(ItemStack stack) { return 6f; case 1: return 9.6f; + default: + throw new IllegalArgumentException("Cannot find fish(350) for data: " + data); } - throw new IllegalArgumentException("Cannot find fish(350) for data: " + data); } @Override @@ -24,7 +25,8 @@ protected int getFoodLevel(ItemStack stack) { return 5; case 1: return 6; + default: + throw new IllegalArgumentException("Cannot find fish(350) for data: " + data); } - throw new IllegalArgumentException("Cannot find fish(350) for data: " + data); } } diff --git a/src/main/java/net/glowstone/block/itemtype/ItemFishRaw.java b/src/main/java/net/glowstone/block/itemtype/ItemFishRaw.java index 527e492471..4f8c9cbfb1 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemFishRaw.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemFishRaw.java @@ -17,8 +17,9 @@ protected float getSaturation(ItemStack stack) { case 2: case 3: return 0.2f; + default: + throw new IllegalArgumentException("Cannot find fish(349) for data: " + data); } - throw new IllegalArgumentException("Cannot find fish(349) for data: " + data); } @Override @@ -31,8 +32,9 @@ protected int getFoodLevel(ItemStack stack) { case 2: case 3: return 1; + default: + throw new IllegalArgumentException("Cannot find fish(349) for data: " + data); } - throw new IllegalArgumentException("Cannot find fish(349) for data: " + data); } @Override diff --git a/src/main/java/net/glowstone/block/itemtype/ItemFlintAndSteel.java b/src/main/java/net/glowstone/block/itemtype/ItemFlintAndSteel.java index cea9c712dc..9a28f8c45e 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemFlintAndSteel.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemFlintAndSteel.java @@ -27,7 +27,7 @@ public boolean onToolRightClick(GlowPlayer player, GlowBlock target, BlockFace f return true; } if (target.getType() == Material.TNT) { - fireTnt(target); + fireTnt(target, player); return true; } if (target.isFlammable() || target.getType().isOccluding()) { @@ -49,8 +49,8 @@ private void fireNetherPortal(GlowBlock target, BlockFace face) { } } - private void fireTnt(GlowBlock tnt) { - BlockTnt.igniteBlock(tnt, false); + private void fireTnt(GlowBlock tnt,GlowPlayer player) { + BlockTnt.igniteBlock(tnt, false, player); } private boolean setBlockOnFire(GlowPlayer player, GlowBlock clicked, BlockFace face, diff --git a/src/main/java/net/glowstone/block/itemtype/ItemFood.java b/src/main/java/net/glowstone/block/itemtype/ItemFood.java index fe7cdce65e..ddde2083c2 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemFood.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemFood.java @@ -50,6 +50,13 @@ protected boolean handleEat(GlowPlayer player, ItemStack item) { return true; } + /** + * Player attempts to eat this food. + * + * @param player the eating player + * @param item the item stack eaten from + * @return whether food was eaten successfully + */ public boolean eat(GlowPlayer player, ItemStack item) { if (!handleEat(player, item)) { return false; diff --git a/src/main/java/net/glowstone/block/itemtype/ItemFoodSeeds.java b/src/main/java/net/glowstone/block/itemtype/ItemFoodSeeds.java index acebe16d64..61a8d940ff 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemFoodSeeds.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemFoodSeeds.java @@ -10,11 +10,23 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; +/** + * A type of edible item that can be planted on one specific type of block, such as a carrot or + * potato. + */ public class ItemFoodSeeds extends ItemFood { private Material cropsType; private Material soilType; + /** + * Creates an instance. + * + * @param cropsType this item's block form + * @param soilType the type of block this can be planted on + * @param food the amount of hunger this food fills, in half icons + * @param saturation the amount of saturation this food grants, in half icons saved + */ public ItemFoodSeeds(Material cropsType, Material soilType, int food, float saturation) { super(food, saturation); this.cropsType = cropsType; diff --git a/src/main/java/net/glowstone/block/itemtype/ItemKnowledgeBook.java b/src/main/java/net/glowstone/block/itemtype/ItemKnowledgeBook.java index 6a6fd9cf00..b91b79a722 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemKnowledgeBook.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemKnowledgeBook.java @@ -24,7 +24,9 @@ public Context getContext() { } @Override - public void rightClickBlock(GlowPlayer player, GlowBlock target, BlockFace face, ItemStack holding, Vector clickedLoc, EquipmentSlot hand) { + public void rightClickBlock( + GlowPlayer player, GlowBlock target, BlockFace face, ItemStack holding, + Vector clickedLoc, EquipmentSlot hand) { rightClickBook(player, holding); } diff --git a/src/main/java/net/glowstone/block/itemtype/ItemMinecart.java b/src/main/java/net/glowstone/block/itemtype/ItemMinecart.java index 44b0654f08..f88b4ac40c 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemMinecart.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemMinecart.java @@ -54,8 +54,8 @@ private float getYaw(BlockFace face) { case WEST: return 90f; case SOUTH: + default: return 0f; } - return getYaw(BlockFace.SOUTH); } } diff --git a/src/main/java/net/glowstone/block/itemtype/ItemPainting.java b/src/main/java/net/glowstone/block/itemtype/ItemPainting.java index 227aa36730..066ab9a533 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemPainting.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemPainting.java @@ -25,7 +25,7 @@ public class ItemPainting extends ItemType { /** - * Contains all Arts Key is the size of the art in descending order + * Contains all Arts. Key is the size of the art in descending order. */ private static final ListMultimap ART_BY_SIZE; diff --git a/src/main/java/net/glowstone/block/itemtype/ItemShovel.java b/src/main/java/net/glowstone/block/itemtype/ItemShovel.java index 087cbbc1e0..8152e02fb1 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemShovel.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemShovel.java @@ -15,14 +15,12 @@ public class ItemShovel extends ItemTool { public boolean onToolRightClick(GlowPlayer player, GlowBlock target, BlockFace face, ItemStack holding, Vector clickedLoc, EquipmentSlot hand) { if (target.getRelative(BlockFace.UP).getType() == Material.AIR - && target.getType() == Material.GRASS) { - if (target.getType() == Material.GRASS) { - target.getWorld() - .playSound(target.getLocation().add(0.5D, 0.5D, 0.5D), Sound.BLOCK_GRAVEL_STEP, - 1, 0.8F); - target.setType(Material.GRASS_PATH); - return true; - } + && target.getType() == Material.GRASS && face != BlockFace.DOWN) { + target.getWorld() + .playSound(target.getLocation().add(0.5D, 0.5D, 0.5D), Sound.BLOCK_GRAVEL_STEP, + 1, 0.8F); + target.setType(Material.GRASS_PATH); + return true; } return false; } diff --git a/src/main/java/net/glowstone/block/itemtype/ItemType.java b/src/main/java/net/glowstone/block/itemtype/ItemType.java index e3cdb7e7ce..002ea92b23 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemType.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemType.java @@ -1,6 +1,10 @@ package net.glowstone.block.itemtype; import com.google.common.base.Preconditions; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.ItemTable; import net.glowstone.block.blocktype.BlockType; @@ -17,13 +21,29 @@ public class ItemType { private int id = -1; + /** + * Get the Material assigned to this ItemType. + * + * @return The corresponding Material. + */ + @Getter private Material material; + /** + * The type of block to place when the item is used. + * + * @return the type of block to place + */ + @Getter private BlockType placeAs; /** * The maximum stack size of the item. + * + * @return The maximum stack size. */ + @Getter + @Setter(AccessLevel.PROTECTED) private int maxStackSize = 64; /** @@ -57,15 +77,6 @@ public final void setId(int id) { } } - /** - * Get the Material assigned to this ItemType. - * - * @return The corresponding Material. - */ - public final Material getMaterial() { - return material; - } - /** * Assign a Material to this ItemType (for internal use only). * @@ -106,44 +117,16 @@ protected final void setPlaceAs(Material placeAs) { * @param placeAs The block to place as. */ protected final void setPlaceAs(BlockType placeAs) { + // Cannot be Lombokified because of the overload this.placeAs = placeAs; } - /** - * The type of block to place when the item is used. - * - * @return the type of block to place - */ - public BlockType getPlaceAs() { - return placeAs; - } - - /** - * Get the maximum stack size of the item. - * - * @return The maximum stack size. - */ - public int getMaxStackSize() { - return maxStackSize; - } - - //////////////////////////////////////////////////////////////////////////// - // Public accessors - - /** - * Set the maximum stack size of the item. - * - * @param maxStackSize The new maximum stack size. - */ - protected final void setMaxStackSize(int maxStackSize) { - this.maxStackSize = maxStackSize; - } - //////////////////////////////////////////////////////////////////////////// // Actions /** - * Called when a player right-clicks in midair while holding this item. + * Called when a player right-clicks in midair while holding this item. Also called by default + * if rightClickBlock is not overridden. * * @param player The player * @param holding The ItemStack the player was holding @@ -153,7 +136,7 @@ public void rightClickAir(GlowPlayer player, ItemStack holding) { } /** - * Get the context this item can be used in + * Get the context this item can be used in. * * @return context of the item, default is {{@link Context#BLOCK}} */ @@ -172,8 +155,10 @@ public Context getContext() { */ public void rightClickBlock(GlowPlayer player, GlowBlock target, BlockFace face, ItemStack holding, Vector clickedLoc, EquipmentSlot hand) { - if (placeAs != null && (placeAs.getContext() == Context.ANY || placeAs.getContext() == Context.BLOCK)) { - placeAs.rightClickBlock(player, target, face, holding, clickedLoc, hand); + if (placeAs != null) { + if (placeAs.getContext().isBlockApplicable()) { + placeAs.rightClickBlock(player, target, face, holding, clickedLoc, hand); + } } } @@ -182,24 +167,31 @@ public void rightClickBlock(GlowPlayer player, GlowBlock target, BlockFace face, @Override public final String toString() { - return getClass().getSimpleName() + "{" + (getMaterial() == null ? getId() : getMaterial()) + "}"; + return getClass().getSimpleName() + + "{" + (getMaterial() == null ? getId() : getMaterial()) + "}"; } /** - * Context of the Items interaction + * Context of the Items interaction. */ + @AllArgsConstructor public enum Context { /** - * The item can only be used when clicking in the air + * The item can only be used when clicking in the air. */ - AIR, + AIR(true, false), /** - * The item can only be used when clicking against a block + * The item can only be used when clicking against a block. */ - BLOCK, + BLOCK(false, true), /** - * The item can be used on any click + * The item can be used on any click. */ - ANY + ANY(true, true); + + @Getter + private boolean airApplicable; + @Getter + private boolean blockApplicable; } } diff --git a/src/main/java/net/glowstone/block/itemtype/ItemWrittenBook.java b/src/main/java/net/glowstone/block/itemtype/ItemWrittenBook.java index c8efb08538..b58f7dfebf 100644 --- a/src/main/java/net/glowstone/block/itemtype/ItemWrittenBook.java +++ b/src/main/java/net/glowstone/block/itemtype/ItemWrittenBook.java @@ -23,7 +23,9 @@ public void rightClickAir(GlowPlayer player, ItemStack holding) { } @Override - public void rightClickBlock(GlowPlayer player, GlowBlock target, BlockFace face, ItemStack holding, Vector clickedLoc, EquipmentSlot hand) { + public void rightClickBlock( + GlowPlayer player, GlowBlock target, BlockFace face, ItemStack holding, + Vector clickedLoc, EquipmentSlot hand) { openBook(player); } diff --git a/src/main/java/net/glowstone/block/state/BlockStateData.java b/src/main/java/net/glowstone/block/state/BlockStateData.java index 18006c6fcd..2aa07b55ee 100644 --- a/src/main/java/net/glowstone/block/state/BlockStateData.java +++ b/src/main/java/net/glowstone/block/state/BlockStateData.java @@ -2,10 +2,12 @@ import com.google.common.collect.Maps; import java.util.Map; +import lombok.Getter; public class BlockStateData { private final Map map = Maps.newHashMap(); + @Getter private final byte numericValue; public BlockStateData(byte numericValue) { @@ -36,10 +38,6 @@ public boolean isNumeric() { return numericValue != -1; } - public byte getNumericValue() { - return numericValue; - } - @Override public String toString() { if (isNumeric()) { diff --git a/src/main/java/net/glowstone/block/state/StateSerialization.java b/src/main/java/net/glowstone/block/state/StateSerialization.java index 90b2f6a465..5d23f66da8 100644 --- a/src/main/java/net/glowstone/block/state/StateSerialization.java +++ b/src/main/java/net/glowstone/block/state/StateSerialization.java @@ -15,6 +15,16 @@ public class StateSerialization { READERS.put(Material.WOOL, new WoolStateDataReader()); } + /** + * Reads a {@link BlockStateData} instance from a string. + * + * @param material the block type + * @param state the state as a string, or null + * @return the default state if {@code state} is null, empty or "*" after stripping leading and + * trailing whitespace; otherwise, a state parsed from the string. + * @throws InvalidBlockStateException if {@code type} isn't a block type with a + * {@link BlockStateReader}, or {@code state} is an invalid block-state string + */ public static BlockStateData parse(Material material, String state) throws InvalidBlockStateException { if (state == null || state.trim().isEmpty() || state.trim().equals("*")) { @@ -47,6 +57,17 @@ public static BlockStateData parse(Material material, String state) return data; } + /** + * Returns whether the given {@link MaterialData} and the given {@link BlockStateData} are valid + * for the given block type and describe the same state. + * @param type the block type, or null + * @param data the block state that's a {@link MaterialData}, or null + * @param state the block state that's a {@link BlockStateData}, or null + * @return true if all parameters are non-null, {@code data} is valid for {@code type}, and + * {@code state} is empty or matches {@code data}; false otherwise + * @throws InvalidBlockStateException if {@code type} is not null but isn't a block type with a + * {@link BlockStateReader} + */ public static boolean matches(Material type, MaterialData data, BlockStateData state) throws InvalidBlockStateException { if (state == null || data == null || data.getItemType() != type) { @@ -62,6 +83,16 @@ public static boolean matches(Material type, MaterialData data, BlockStateData s return reader.matches(state, data); } + /** + * Converts a {@link BlockStateData} instance to a {@link MaterialData} instance. + * + * @param type the block type, or null + * @param state the block state, or null + * @return the block state as a {@link MaterialData} instance, or null if either parameter is + * null + * @throws InvalidBlockStateException if {@code type} is not null but isn't a block type with a + * {@link BlockStateReader} + */ public static MaterialData parseData(Material type, BlockStateData state) throws InvalidBlockStateException { if (type == null || state == null) { @@ -74,13 +105,27 @@ public static MaterialData parseData(Material type, BlockStateData state) return reader.read(type, state); } - public static BlockStateReader getReader(Material material) { + /** + * Returns the {@link BlockStateReader} for a block type. + * + * @param material a material, or null + * @return the {@link BlockStateReader} for {@code material}, or null if {@code material} is + * null or not a block type that has a {@link BlockStateReader} + */ + public static BlockStateReader getReader(Material material) { if (material == null) { return null; } return READERS.get(material); } + /** + * Returns the {@link DyeColor} with a given name (case-insensitive). + * + * @param color the name of a color, or null + * @return the {@link DyeColor} with that name, or null if {@code color} is null or no colors + * match + */ public static DyeColor getColor(String color) { if (color == null) { return null; diff --git a/src/main/java/net/glowstone/block/state/impl/WoolStateDataReader.java b/src/main/java/net/glowstone/block/state/impl/WoolStateDataReader.java index f0abaf12b0..fad6832112 100644 --- a/src/main/java/net/glowstone/block/state/impl/WoolStateDataReader.java +++ b/src/main/java/net/glowstone/block/state/impl/WoolStateDataReader.java @@ -1,6 +1,6 @@ package net.glowstone.block.state.impl; -import com.google.common.collect.Sets; +import com.google.common.collect.ImmutableSet; import java.util.Set; import net.glowstone.block.state.BlockStateData; import net.glowstone.block.state.BlockStateReader; @@ -12,7 +12,7 @@ public class WoolStateDataReader extends BlockStateReader { - private static final Set VALID_STATES = Sets.newHashSet("color"); + private static final Set VALID_STATES = ImmutableSet.of("color"); @Override public Set getValidStates() { diff --git a/src/main/java/net/glowstone/boss/GlowBossBar.java b/src/main/java/net/glowstone/boss/GlowBossBar.java index e9b983bf99..e378e2189e 100644 --- a/src/main/java/net/glowstone/boss/GlowBossBar.java +++ b/src/main/java/net/glowstone/boss/GlowBossBar.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.List; import java.util.UUID; +import lombok.Getter; import net.glowstone.entity.GlowPlayer; import net.glowstone.net.message.play.player.BossBarMessage; import net.glowstone.util.TextMessage; @@ -15,13 +16,19 @@ public class GlowBossBar implements BossBar { + @Getter private final UUID uniqueId; private final List flags = new ArrayList<>(); private final List players = new ArrayList<>(); + @Getter private String title; + @Getter private BarColor color; + @Getter private BarStyle style; + @Getter private double progress = 1.0; + @Getter private boolean visible = true; /** @@ -47,11 +54,6 @@ public GlowBossBar(String title, BarColor color, BarStyle style, BarFlag... flag this(title, color, style, 1.0, flags); } - @Override - public String getTitle() { - return title; - } - @Override public void setTitle(String title) { this.title = title; @@ -61,11 +63,6 @@ public void setTitle(String title) { } } - @Override - public BarColor getColor() { - return color; - } - @Override public void setColor(BarColor color) { this.color = color; @@ -76,11 +73,6 @@ public void setColor(BarColor color) { } } - @Override - public BarStyle getStyle() { - return style; - } - @Override public void setStyle(BarStyle style) { this.style = style; @@ -118,11 +110,6 @@ public boolean hasFlag(BarFlag flag) { return flags.contains(flag); } - @Override - public double getProgress() { - return progress; - } - @Override public void setProgress(double progress) { this.progress = progress; @@ -173,14 +160,10 @@ public void removeAll() { @Override public List getPlayers() { + // TODO: Defensive copy return players; } - @Override - public boolean isVisible() { - return visible; - } - @Override public void setVisible(boolean visible) { if (this.visible != visible) { @@ -203,10 +186,6 @@ public void hide() { setVisible(false); } - public UUID getUniqueId() { - return uniqueId; - } - private byte flagsToByte() { byte flags = 0; if (this.flags.contains(BarFlag.DARKEN_SKY)) { diff --git a/src/main/java/net/glowstone/chunk/ChunkManager.java b/src/main/java/net/glowstone/chunk/ChunkManager.java index 6189478e36..9f13e9f81c 100644 --- a/src/main/java/net/glowstone/chunk/ChunkManager.java +++ b/src/main/java/net/glowstone/chunk/ChunkManager.java @@ -13,6 +13,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; import java.util.stream.Collectors; +import lombok.Getter; import net.glowstone.EventFactory; import net.glowstone.GlowServer; import net.glowstone.GlowWorld; @@ -49,7 +50,10 @@ public final class ChunkManager { /** * The chunk generator used to generate new chunks. + * + * @return the chunk generator */ + @Getter private final ChunkGenerator generator; /** @@ -81,16 +85,7 @@ public ChunkManager(GlowWorld world, ChunkIoService service, ChunkGenerator gene biomeGrid = MapLayer.initialize( world.getSeed(), world.getEnvironment(), world.getWorldType()); } - - /** - * Get the chunk generator. - * - * @return The chunk generator. - */ - public ChunkGenerator getGenerator() { - return generator; - } - + /** * Gets a chunk object representing the specified coordinates, which might not yet be loaded. * diff --git a/src/main/java/net/glowstone/chunk/ChunkSection.java b/src/main/java/net/glowstone/chunk/ChunkSection.java index d11806f541..e3e16b7861 100644 --- a/src/main/java/net/glowstone/chunk/ChunkSection.java +++ b/src/main/java/net/glowstone/chunk/ChunkSection.java @@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntListIterator; import javax.annotation.Nullable; +import lombok.Getter; import net.glowstone.util.NibbleArray; import net.glowstone.util.VariableValueArray; import net.glowstone.util.nbt.CompoundTag; @@ -49,11 +50,16 @@ public final class ChunkSection { private VariableValueArray data; /** * The sky light array. This array is always set, even in dimensions without skylight. + * + * @return The sky light array. If the dimension of this chunk section's chunk's world is not + * the overworld, this array contains only maximum light levels. */ + @Getter private NibbleArray skyLight; /** * The block light array. */ + @Getter private NibbleArray blockLight; /** * The number of non-air blocks in this section, used to determine whether it is empty. @@ -397,15 +403,6 @@ public char[] getTypes() { return types; } - /** - * Gets the block light array. - * - * @return The block light array. - */ - public NibbleArray getBlockLight() { - return blockLight; - } - /** * Gets the block light at the given block. * @@ -430,16 +427,6 @@ public void setBlockLight(int x, int y, int z, byte light) { blockLight.set(index(x, y, z), light); } - /** - * Gets the sky light array. - * - * @return The sky light array. If the dimension of this chunk section's chunk's world is not - * the overworld, this array contains only maximum light levels. - */ - public NibbleArray getSkyLight() { - return skyLight; - } - /** * Gets the sky light at the given block. * diff --git a/src/main/java/net/glowstone/chunk/GlowChunk.java b/src/main/java/net/glowstone/chunk/GlowChunk.java index cc4cd1d53f..a9403a1793 100644 --- a/src/main/java/net/glowstone/chunk/GlowChunk.java +++ b/src/main/java/net/glowstone/chunk/GlowChunk.java @@ -13,6 +13,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import lombok.Data; +import lombok.Getter; +import lombok.Setter; import net.glowstone.EventFactory; import net.glowstone.GlowServer; import net.glowstone.GlowWorld; @@ -60,14 +62,17 @@ public final class GlowChunk implements Chunk { /** * The world of this chunk. */ + @Getter private final GlowWorld world; /** * The x-coordinate of this chunk. */ + @Getter private final int x; /** * The z-coordinate of this chunk. */ + @Getter private final int z; /** * The block entities that reside in this chunk. @@ -79,7 +84,10 @@ public final class GlowChunk implements Chunk { private final Set entities = ConcurrentHashMap.newKeySet(4); /** * The array of chunk sections this chunk contains, or null if it is unloaded. + * + * @return The chunk sections array. */ + @Getter private ChunkSection[] sections; /** * The array of biomes this chunk contains, or null if it is unloaded. @@ -92,7 +100,12 @@ public final class GlowChunk implements Chunk { private byte[] heightMap; /** * Whether the chunk has been populated by special features. Used in map generation. + * + * @param populated Population status. + * @return Population status. */ + @Getter + @Setter private boolean populated; /** @@ -114,21 +127,6 @@ public String toString() { return "GlowChunk{world=" + world.getName() + ",x=" + x + ",z=" + z + '}'; } - @Override - public GlowWorld getWorld() { - return world; - } - - @Override - public int getX() { - return x; - } - - @Override - public int getZ() { - return z; - } - @Override public GlowBlock getBlock(int x, int y, int z) { return new GlowBlock(this, this.x << 4 | x & 0xf, y & 0xff, this.z << 4 | z & 0xf); @@ -197,15 +195,6 @@ public boolean isPopulated() { return populated; } - /** - * Sets the population status of this chunk. - * - * @param populated Population status. - */ - public void setPopulated(boolean populated) { - this.populated = populated; - } - @Override public boolean isLoaded() { return sections != null; @@ -400,15 +389,6 @@ private ChunkSection getSection(int y) { return sections[idx]; } - /** - * Get all ChunkSection of this chunk. - * - * @return The chunk sections array. - */ - public ChunkSection[] getSections() { - return sections; - } - /** * Attempt to get the block entity located at the given coordinates. * diff --git a/src/main/java/net/glowstone/chunk/GlowChunkSnapshot.java b/src/main/java/net/glowstone/chunk/GlowChunkSnapshot.java index bbe7efd392..e54c39b4a8 100644 --- a/src/main/java/net/glowstone/chunk/GlowChunkSnapshot.java +++ b/src/main/java/net/glowstone/chunk/GlowChunkSnapshot.java @@ -16,15 +16,25 @@ public class GlowChunkSnapshot implements ChunkSnapshot { private final int x; @Getter private final int z; - private final String world; - private final long time; + @Getter + private final String worldName; + @Getter + private final long captureFullTime; - private final ChunkSection[] sections; + /** + * The ChunkSection array backing this snapshot. In general, it should not be modified + * externally. + * + * @return The array of ChunkSections. + */ + @Getter + private final ChunkSection[] rawSections; private final byte[] height; private final double[] temp; private final double[] humid; - private final byte[] biomes; + @Getter + private final byte[] rawBiomes; /** * Creates a snapshot of a chunk. @@ -41,19 +51,19 @@ public GlowChunkSnapshot(int x, int z, World world, ChunkSection[] sections, byt byte[] biomes, boolean svTemp) { this.x = x; this.z = z; - this.world = world.getName(); - time = world.getFullTime(); + this.worldName = world.getName(); + captureFullTime = world.getFullTime(); int numSections = sections != null ? sections.length : 0; - this.sections = new ChunkSection[numSections]; + this.rawSections = new ChunkSection[numSections]; for (int i = 0; i < numSections; ++i) { if (sections[i] != null) { - this.sections[i] = sections[i].snapshot(); + this.rawSections[i] = sections[i].snapshot(); } } this.height = height; - this.biomes = biomes; + this.rawBiomes = biomes; if (svTemp) { int baseX = x << 4; @@ -73,19 +83,10 @@ public GlowChunkSnapshot(int x, int z, World world, ChunkSection[] sections, byt private ChunkSection getSection(int y) { int idx = y >> 4; - if (idx < 0 || idx >= sections.length) { + if (idx < 0 || idx >= rawSections.length) { return null; } - return sections[idx]; - } - - /** - * Get the ChunkSection array backing this snapshot. In general, it should not be modified. - * - * @return The array of ChunkSections. - */ - public ChunkSection[] getRawSections() { - return sections; + return rawSections[idx]; } /** @@ -101,23 +102,9 @@ public int[] getRawHeightmap() { return result; } - public byte[] getRawBiomes() { - return biomes; - } - - @Override - public String getWorldName() { - return world; - } - - @Override - public long getCaptureFullTime() { - return time; - } - @Override public boolean isSectionEmpty(int sy) { - return sy < 0 || sy >= sections.length || sections[sy] == null; + return sy < 0 || sy >= rawSections.length || rawSections[sy] == null; } @Override @@ -156,7 +143,7 @@ public int getHighestBlockYAt(int x, int z) { @Override public Biome getBiome(int x, int z) { - return GlowBiome.getBiome(biomes[coordToIndex(x, z)]); + return GlowBiome.getBiome(rawBiomes[coordToIndex(x, z)]); } @Override diff --git a/src/main/java/net/glowstone/command/CommandTarget.java b/src/main/java/net/glowstone/command/CommandTarget.java index 2cfc151a37..fda476d77f 100644 --- a/src/main/java/net/glowstone/command/CommandTarget.java +++ b/src/main/java/net/glowstone/command/CommandTarget.java @@ -9,6 +9,7 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.command.CommandSender; @@ -19,6 +20,12 @@ public class CommandTarget { private final CommandSender sender; + /** + * The type of selector (target). + * + * @return the type of selector of this target + */ + @Getter private final SelectorType selector; private final HashMap arguments; @@ -47,21 +54,13 @@ public CommandTarget(CommandSender sender, String target) { } } - /** - * The type of selector (target). - * - * @return the type of selector of this target - */ - public SelectorType getSelector() { - return selector; - } - /** * The arguments of the selector (target). * * @return the arguments of the selector of this target */ public HashMap getArguments() { + // TODO: Defensive copy return arguments; } @@ -266,6 +265,7 @@ public Entity[] getMatched(Location source) { * Types of selectors, namely @p (closest player), @r (random player), @a (all players), @e * (all entities). */ + @RequiredArgsConstructor enum SelectorType { NEAREST_PLAYER('p'), RANDOM('r'), @@ -273,11 +273,8 @@ enum SelectorType { ALL_ENTITIES('e'), SENDER('s'); - private char selector; - - SelectorType(char selector) { - this.selector = selector; - } + @Getter + private final char selector; public static SelectorType get(char selector) { for (SelectorType selectorType : values()) { @@ -287,10 +284,6 @@ public static SelectorType get(char selector) { } return null; } - - public char getSelector() { - return selector; - } } /** diff --git a/src/main/java/net/glowstone/command/glowstone/GlowstoneCommand.java b/src/main/java/net/glowstone/command/glowstone/GlowstoneCommand.java index 1c1596d39d..bc82941565 100644 --- a/src/main/java/net/glowstone/command/glowstone/GlowstoneCommand.java +++ b/src/main/java/net/glowstone/command/glowstone/GlowstoneCommand.java @@ -27,11 +27,14 @@ public class GlowstoneCommand extends BukkitCommand { private static final List SUBCOMMANDS = Arrays - .asList("about", "chunk", "eval", "help", "property", "vm", "world"); + .asList("about", "chunk", "eval", "help", "property", "vm", "world"); + /** + * Creates the instance for this command. + */ public GlowstoneCommand() { super("glowstone", "A handful of Glowstone commands for debugging purposes", - "/glowstone help", Arrays.asList("gs")); + "/glowstone help", Arrays.asList("gs")); setPermission("glowstone.debug"); } @@ -44,25 +47,28 @@ public boolean execute(CommandSender sender, String label, String[] args) { // some info about this Glowstone server sender.sendMessage("Information about this server:"); sender.sendMessage( - " - " + ChatColor.GOLD + "Server brand: " + ChatColor.AQUA + Bukkit.getName() - + ChatColor.RESET + "."); + " - " + ChatColor.GOLD + "Server brand: " + ChatColor.AQUA + Bukkit.getName() + + ChatColor.RESET + "."); sender.sendMessage( - " - " + ChatColor.GOLD + "Server name: " + ChatColor.AQUA + Bukkit.getServerName() - + ChatColor.RESET + "."); + " - " + ChatColor.GOLD + "Server name: " + ChatColor.AQUA + Bukkit + .getServerName() + + ChatColor.RESET + "."); sender.sendMessage( - " - " + ChatColor.GOLD + "Glowstone version: " + ChatColor.AQUA + Bukkit - .getVersion() + ChatColor.RESET + "."); + " - " + ChatColor.GOLD + "Glowstone version: " + ChatColor.AQUA + Bukkit + .getVersion() + ChatColor.RESET + "."); sender.sendMessage(" - " + ChatColor.GOLD + "API version: " + ChatColor.AQUA + Bukkit - .getBukkitVersion() + ChatColor.RESET + "."); + .getBukkitVersion() + ChatColor.RESET + "."); sender.sendMessage( - " - " + ChatColor.GOLD + "Players: " + ChatColor.AQUA + Bukkit.getOnlinePlayers() - .size() + ChatColor.RESET + "."); + " - " + ChatColor.GOLD + "Players: " + ChatColor.AQUA + Bukkit + .getOnlinePlayers() + .size() + ChatColor.RESET + "."); sender.sendMessage( - " - " + ChatColor.GOLD + "Worlds: " + ChatColor.AQUA + Bukkit.getWorlds().size() - + ChatColor.RESET + "."); + " - " + ChatColor.GOLD + "Worlds: " + ChatColor.AQUA + Bukkit.getWorlds().size() + + ChatColor.RESET + "."); sender.sendMessage( - " - " + ChatColor.GOLD + "Plugins: " + ChatColor.AQUA + Bukkit.getPluginManager() - .getPlugins().length + ChatColor.RESET + "."); + " - " + ChatColor.GOLD + "Plugins: " + ChatColor.AQUA + Bukkit + .getPluginManager() + .getPlugins().length + ChatColor.RESET + "."); // thread count int threadCount = 0; @@ -73,27 +79,31 @@ public boolean execute(CommandSender sender, String label, String[] args) { } } sender.sendMessage(" - " + ChatColor.GOLD + "Threads: " + ChatColor.AQUA + threadCount - + ChatColor.RESET + "."); + + ChatColor.RESET + "."); return false; } if ("help".equalsIgnoreCase(args[0])) { // some help sender.sendMessage(ChatColor.GOLD + "Glowstone command help:"); sender.sendMessage(helpForSubCommand(label, "about", "Information about this server")); - sender.sendMessage(helpForSubCommand(label, "eval ", "Evaluate a reflection string")); + sender.sendMessage(helpForSubCommand(label, "eval ", "Evaluate a reflection " + + "string")); sender.sendMessage(helpForSubCommand(label, "help", "Shows the help screen")); - sender.sendMessage(helpForSubCommand(label, "property [name]", "Lists or gets system properties")); - sender.sendMessage(helpForSubCommand(label, "chunk", "Gets the coordinates of the current chunk")); + sender.sendMessage(helpForSubCommand(label, "property [name]", "Lists or gets system " + + "properties")); + sender.sendMessage(helpForSubCommand(label, "chunk", "Gets the coordinates of the " + + "current chunk")); sender.sendMessage(helpForSubCommand(label, "vm", "Lists JVM options")); - sender.sendMessage(helpForSubCommand(label, "world [teleportTo]", "Lists or teleports to worlds")); + sender.sendMessage(helpForSubCommand(label, "world [teleportTo]", "Lists or teleports" + + " to worlds")); return false; } if ("property".equalsIgnoreCase(args[0])) { if (args.length == 1) { // list all System.getProperties().forEach((key, value) -> sender.sendMessage( - "Property '" + ChatColor.AQUA + key + ChatColor.RESET + "' = \"" - + ChatColor.GOLD + value + ChatColor.RESET + "\".")); + "Property '" + ChatColor.AQUA + key + ChatColor.RESET + "' = \"" + + ChatColor.GOLD + value + ChatColor.RESET + "\".")); } else { // get a property String key = args[1].toLowerCase(); @@ -102,8 +112,8 @@ public boolean execute(CommandSender sender, String label, String[] args) { sender.sendMessage(ChatColor.RED + "Unknown system property '" + key + "'."); } else { sender.sendMessage( - "Property '" + ChatColor.AQUA + key + ChatColor.RESET + "' = \"" - + ChatColor.GOLD + value + ChatColor.RESET + "\"."); + "Property '" + ChatColor.AQUA + key + ChatColor.RESET + "' = \"" + + ChatColor.GOLD + value + ChatColor.RESET + "\"."); } } return false; @@ -126,7 +136,8 @@ public boolean execute(CommandSender sender, String label, String[] args) { if (args.length == 1) { // list worlds sender.sendMessage( - "Worlds: " + CommandUtils.prettyPrint(getWorldNames().toArray(new String[0]))); + "Worlds: " + CommandUtils + .prettyPrint(getWorldNames().toArray(new String[0]))); return true; } if (!(sender instanceof Player)) { @@ -138,7 +149,8 @@ public boolean execute(CommandSender sender, String label, String[] args) { GlowWorld world = player.getServer().getWorld(worldName); if (world == null) { sender.sendMessage( - ChatColor.RED + "World '" + worldName + "' is not loaded, or does not exist"); + ChatColor.RED + "World '" + worldName + + "' is not loaded, or does not exist"); return false; } player.teleport(world.getSpawnLocation()); @@ -147,13 +159,14 @@ public boolean execute(CommandSender sender, String label, String[] args) { } if ("chunk".equalsIgnoreCase(args[0])) { if (!CommandUtils.isPhysical(sender)) { - sender - .sendMessage(ChatColor.RED + "This command may only be used by physical objects"); + sender.sendMessage( + ChatColor.RED + "This command may only be used by physical objects"); return false; } Chunk chunk = CommandUtils.getLocation(sender).getChunk(); sender - .sendMessage("Chunk coordinates: [x=" + chunk.getX() + ", z=" + chunk.getZ() + "]"); + .sendMessage( + "Chunk coordinates: [x=" + chunk.getX() + ", z=" + chunk.getZ() + "]"); return true; } if ("eval".equalsIgnoreCase(args[0])) { @@ -167,11 +180,12 @@ public boolean execute(CommandSender sender, String label, String[] args) { builder.append(args[i] + (i == args.length - 1 ? "" : " ")); } ReflectionProcessor processor = new ReflectionProcessor(builder.toString(), - sender instanceof Entity ? sender : Bukkit.getServer()); + sender instanceof Entity ? sender : Bukkit.getServer()); Object result = processor.process(); sender.sendMessage( - ChatColor.GOLD + "Eval returned: " + (result == null ? ChatColor.RED + "" - : ChatColor.AQUA + result.toString())); + ChatColor.GOLD + "Eval returned: " + (result == null ? ChatColor.RED + + "" + : ChatColor.AQUA + result.toString())); return true; } sender.sendMessage(ChatColor.RED + "Usage: /" + label + " <" @@ -181,7 +195,7 @@ public boolean execute(CommandSender sender, String label, String[] args) { @Override public List tabComplete(CommandSender sender, String alias, String[] args) - throws IllegalArgumentException { + throws IllegalArgumentException { Preconditions.checkNotNull(sender, "Sender cannot be null"); Preconditions.checkNotNull(args, "Arguments cannot be null"); Preconditions.checkNotNull(alias, "Alias cannot be null"); @@ -190,28 +204,30 @@ public List tabComplete(CommandSender sender, String alias, String[] arg } if (args.length == 1) { return StringUtil - .copyPartialMatches(args[0], SUBCOMMANDS, new ArrayList<>(SUBCOMMANDS.size())); + .copyPartialMatches(args[0], SUBCOMMANDS, new ArrayList<>(SUBCOMMANDS.size())); } if (args.length == 2 && args[0].equalsIgnoreCase("property")) { return StringUtil - .copyPartialMatches(args[1], System.getProperties().stringPropertyNames(), - new ArrayList<>(System.getProperties().stringPropertyNames().size())); + .copyPartialMatches(args[1], System.getProperties().stringPropertyNames(), + new ArrayList<>(System.getProperties().stringPropertyNames().size())); } if (args.length == 2 && (args[0].equalsIgnoreCase("world") || args[0] - .equalsIgnoreCase("worlds")) && sender instanceof Player) { + .equalsIgnoreCase("worlds")) && sender instanceof Player) { Collection worlds = getWorldNames(); return StringUtil - .copyPartialMatches(args[1], worlds, new ArrayList<>(worlds.size())); + .copyPartialMatches(args[1], worlds, new ArrayList<>(worlds.size())); } return Collections.emptyList(); } private String helpForSubCommand(String label, String subcommand, String description) { - return "- " + ChatColor.GOLD + "/" + label + " " + ChatColor.AQUA + subcommand + ChatColor.GRAY + ": " + description; + return "- " + ChatColor.GOLD + "/" + label + " " + + ChatColor.AQUA + subcommand + + ChatColor.GRAY + ": " + description; } private Collection getWorldNames() { return Bukkit.getServer().getWorlds().stream().map(World::getName) - .collect(Collectors.toList()); + .collect(Collectors.toList()); } } diff --git a/src/main/java/net/glowstone/command/minecraft/BanCommand.java b/src/main/java/net/glowstone/command/minecraft/BanCommand.java index 564c0fcc6b..ed02b314ce 100644 --- a/src/main/java/net/glowstone/command/minecraft/BanCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/BanCommand.java @@ -2,7 +2,7 @@ import java.util.Collections; import java.util.List; -import net.glowstone.entity.meta.profile.PlayerProfile; +import net.glowstone.GlowServer; import org.bukkit.BanList; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -16,7 +16,7 @@ public class BanCommand extends VanillaCommand { */ public BanCommand() { super("ban", "Bans a player from the server.", "/ban [reason]", - Collections.emptyList()); + Collections.emptyList()); setPermission("minecraft.command.ban"); } @@ -26,20 +26,34 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) return false; } if (args.length > 0) { - if (PlayerProfile.getProfile(args[0]).join() == null) { - sender.sendMessage(ChatColor.RED + "Could not ban player " + args[0]); - return false; - } - if (args.length == 1) { - Bukkit.getBanList(BanList.Type.NAME).addBan(args[0], null, null, null); - } else { - StringBuilder reason = new StringBuilder(); - for (int i = 1; i < args.length; i++) { - reason.append(args[i]).append(" "); + String name = args[0]; + GlowServer server = (GlowServer) Bukkit.getServer(); + // asynchronously lookup player + server.getOfflinePlayerAsync(name).whenCompleteAsync((player, ex) -> { + if (ex != null) { + sender.sendMessage(ChatColor.RED + "Failed to ban " + name + ": " + + ex.getMessage()); + ex.printStackTrace(); + return; } - Bukkit.getBanList(BanList.Type.NAME).addBan(args[0], reason.toString(), null, null); - } - sender.sendMessage("Banned player " + args[0]); + if (player == null) { + sender.sendMessage(ChatColor.RED + "Could not ban player " + args[0]); + return; + } + if (args.length == 1) { + Bukkit.getBanList(BanList.Type.NAME).addBan(player.getName(), + null, null, null); + } else { + StringBuilder reason = new StringBuilder(); + for (int i = 1; i < args.length; i++) { + reason.append(args[i]).append(" "); + } + Bukkit.getBanList(BanList.Type.NAME).addBan(player.getName(), + reason.toString(), null, null); + } + sender.sendMessage("Banned player " + player.getName()); + }); + // todo: asynchronous command callbacks? return true; } sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); @@ -48,7 +62,7 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) @Override public List tabComplete(CommandSender sender, String alias, String[] args) - throws IllegalArgumentException { + throws IllegalArgumentException { if (args.length == 1) { super.tabComplete(sender, alias, args); } diff --git a/src/main/java/net/glowstone/command/minecraft/CloneCommand.java b/src/main/java/net/glowstone/command/minecraft/CloneCommand.java index 9ce5e20449..4cae3ff0a7 100644 --- a/src/main/java/net/glowstone/command/minecraft/CloneCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/CloneCommand.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.Iterator; import lombok.Getter; +import lombok.RequiredArgsConstructor; import net.glowstone.GlowWorld; import net.glowstone.block.GlowBlock; import net.glowstone.block.entity.BlockEntity; @@ -19,21 +20,15 @@ public class CloneCommand extends VanillaCommand { + @RequiredArgsConstructor public enum MaskMode { REPLACE("replace"), MASKED("masked"), FILTERED("filter"); + @Getter private final String commandName; - MaskMode(String commandName) { - this.commandName = commandName; - } - - public String getCommandName() { - return commandName; - } - /** * Returns the MaskMode with a given subcommand name, or null if none match. * diff --git a/src/main/java/net/glowstone/command/minecraft/DeopCommand.java b/src/main/java/net/glowstone/command/minecraft/DeopCommand.java index 9b07788a58..83856d9e8e 100644 --- a/src/main/java/net/glowstone/command/minecraft/DeopCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/DeopCommand.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import net.glowstone.GlowServer; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; @@ -18,7 +19,7 @@ public class DeopCommand extends VanillaCommand { */ public DeopCommand() { super("deop", "Removes server operator status from a player.", "/deop ", - Collections.emptyList()); + Collections.emptyList()); setPermission("minecraft.command.deop"); } @@ -32,19 +33,30 @@ public boolean execute(CommandSender sender, String label, String[] args) { return false; } String name = args[0]; - OfflinePlayer player = Bukkit.getOfflinePlayer(name); - if (player.isOp()) { - player.setOp(false); - sender.sendMessage("Deopped " + player.getName()); - } else { - sender.sendMessage("Could not deop " + player.getName()); - } + GlowServer server = (GlowServer) Bukkit.getServer(); + // asynchronously lookup player + server.getOfflinePlayerAsync(name).whenCompleteAsync((player, ex) -> { + if (ex != null) { + sender.sendMessage(ChatColor.RED + "Failed to deop " + name + ": " + + ex.getMessage()); + ex.printStackTrace(); + return; + } + if (player.isOp()) { + player.setOp(false); + sender.sendMessage("Deopped " + player.getName()); + } else { + sender.sendMessage(ChatColor.RED + "Could not deop " + player.getName() + + ": not an operator"); + } + }); + // todo: asynchronous command callbacks? return true; } @Override public List tabComplete(CommandSender sender, String alias, String[] args) - throws IllegalArgumentException { + throws IllegalArgumentException { if (args.length == 1) { List operators = new ArrayList<>(); Bukkit.getOperators().stream().map(OfflinePlayer::getName) diff --git a/src/main/java/net/glowstone/command/minecraft/KickCommand.java b/src/main/java/net/glowstone/command/minecraft/KickCommand.java index 6326cfe6f1..ac42215c6f 100644 --- a/src/main/java/net/glowstone/command/minecraft/KickCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/KickCommand.java @@ -11,6 +11,9 @@ public class KickCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public KickCommand() { super("kick", "Removes a player from the server.", "/kick [reason]", Collections.emptyList()); diff --git a/src/main/java/net/glowstone/command/minecraft/MeCommand.java b/src/main/java/net/glowstone/command/minecraft/MeCommand.java index f171d8a887..2d0dbd3995 100644 --- a/src/main/java/net/glowstone/command/minecraft/MeCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/MeCommand.java @@ -10,6 +10,9 @@ public class MeCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public MeCommand() { super("me", "Displays a message about yourself.", "/me ", Collections.emptyList()); diff --git a/src/main/java/net/glowstone/command/minecraft/OpCommand.java b/src/main/java/net/glowstone/command/minecraft/OpCommand.java index efd12b48ef..09d43a2337 100644 --- a/src/main/java/net/glowstone/command/minecraft/OpCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/OpCommand.java @@ -1,17 +1,20 @@ package net.glowstone.command.minecraft; import java.util.Collections; +import net.glowstone.GlowServer; import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.command.defaults.VanillaCommand; public class OpCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public OpCommand() { super("op", "Turns a player into a server operator.", "/op ", - Collections.emptyList()); + Collections.emptyList()); setPermission("minecraft.command.op"); } @@ -25,9 +28,19 @@ public boolean execute(CommandSender sender, String label, String[] args) { return false; } String name = args[0]; - OfflinePlayer player = Bukkit.getOfflinePlayer(name); - player.setOp(true); - sender.sendMessage("Opped " + player.getName()); + GlowServer server = (GlowServer) Bukkit.getServer(); + // asynchronously lookup player + server.getOfflinePlayerAsync(name).whenCompleteAsync((player, ex) -> { + if (ex != null) { + sender.sendMessage(ChatColor.RED + "Failed to op " + name + ": " + + ex.getMessage()); + ex.printStackTrace(); + return; + } + player.setOp(true); + sender.sendMessage("Opped " + player.getName()); + }); + // todo: asynchronous command callbacks? return true; } } diff --git a/src/main/java/net/glowstone/command/minecraft/PardonCommand.java b/src/main/java/net/glowstone/command/minecraft/PardonCommand.java index 5d323c8ded..835ed902a1 100644 --- a/src/main/java/net/glowstone/command/minecraft/PardonCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/PardonCommand.java @@ -1,15 +1,18 @@ package net.glowstone.command.minecraft; import java.util.Collections; +import net.glowstone.GlowServer; import org.bukkit.BanList; import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.command.defaults.VanillaCommand; public class PardonCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public PardonCommand() { super("pardon", "Unbans a player from the server.", "/pardon ", Collections.emptyList()); @@ -26,14 +29,25 @@ public boolean execute(CommandSender sender, String label, String[] args) { return false; } String name = args[0]; - OfflinePlayer player = Bukkit.getOfflinePlayer(name); - BanList banList = Bukkit.getServer().getBanList(BanList.Type.NAME); - if (!banList.isBanned(player.getName())) { - sender.sendMessage(ChatColor.RED + "Could not unban player " + name); - return false; - } - banList.pardon(player.getName()); - sender.sendMessage("Unbanned player " + name); + GlowServer server = (GlowServer) Bukkit.getServer(); + // asynchronously lookup player + server.getOfflinePlayerAsync(name).whenCompleteAsync((player, ex) -> { + if (ex != null) { + sender.sendMessage(ChatColor.RED + "Failed to unban " + name + ": " + + ex.getMessage()); + ex.printStackTrace(); + return; + } + BanList banList = Bukkit.getServer().getBanList(BanList.Type.NAME); + if (!banList.isBanned(player.getName())) { + sender.sendMessage(ChatColor.RED + "Could not unban player " + player.getName() + + ": not banned"); + return; + } + banList.pardon(player.getName()); + sender.sendMessage("Unbanned player " + name); + }); + // todo: asynchronous command callbacks? return true; } } diff --git a/src/main/java/net/glowstone/command/minecraft/PardonIpCommand.java b/src/main/java/net/glowstone/command/minecraft/PardonIpCommand.java index 693615ff5a..c6ddf8a0c4 100644 --- a/src/main/java/net/glowstone/command/minecraft/PardonIpCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/PardonIpCommand.java @@ -9,6 +9,9 @@ public class PardonIpCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public PardonIpCommand() { super("pardon-ip", "Unbans an IP address from the server.", "/pardon-ip

", Collections.emptyList()); diff --git a/src/main/java/net/glowstone/command/minecraft/PlaySoundCommand.java b/src/main/java/net/glowstone/command/minecraft/PlaySoundCommand.java index 9f5e50eab5..1492d65f38 100644 --- a/src/main/java/net/glowstone/command/minecraft/PlaySoundCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/PlaySoundCommand.java @@ -29,6 +29,9 @@ public class PlaySoundCommand extends VanillaCommand { private static final Set SOUNDS = GlowSound.getSounds().keySet(); + /** + * Creates the instance for this command. + */ public PlaySoundCommand() { super("playsound", "Plays a sound.", "/playsound [x] [y] [z] [volume] [pitch] [minimumVolume]", @@ -49,13 +52,17 @@ public boolean execute(CommandSender sender, String label, String[] args) { final World world = CommandUtils.getWorld(sender); - String stringSound = args[0], stringCategory = args[1], playerPattern = args[2]; + String stringSound = args[0]; + String stringCategory = args[1]; + String playerPattern = args[2]; final Sound sound = GlowSound.getVanillaSound( stringSound.startsWith("minecraft:") ? stringSound : "minecraft:" + stringSound); final SoundCategory soundCategory = SoundUtil.buildSoundCategory(stringCategory); List targets; boolean relativeLocation = false; - double volume = 1, minimumVolume = 0, pitch = 1; + double volume = 1; + double minimumVolume = 0; + double pitch = 1; if (sound == null) { sender.sendMessage(ChatColor.RED + "'" + stringSound + "' is not a valid sound."); @@ -135,7 +142,8 @@ public boolean execute(CommandSender sender, String label, String[] args) { } for (final GlowPlayer target : targets) { - Location soundLocation, targetLocation = target.getLocation(); + Location soundLocation; + Location targetLocation = target.getLocation(); double targetVolume = volume; try { @@ -162,9 +170,9 @@ public boolean execute(CommandSender sender, String label, String[] args) { ChatColor.RED + target.getName() + " is too far away to hear the sound"); return false; } else { - final double deltaX = soundLocation.getX() - targetLocation.getX(), - deltaY = soundLocation.getX() - targetLocation.getY(), - deltaZ = soundLocation.getX() - targetLocation.getZ(); + final double deltaX = soundLocation.getX() - targetLocation.getX(); + final double deltaY = soundLocation.getX() - targetLocation.getY(); + final double deltaZ = soundLocation.getX() - targetLocation.getZ(); final double delta = Math .sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2) + Math.pow(deltaZ, 2)); diff --git a/src/main/java/net/glowstone/command/minecraft/SaveToggleCommand.java b/src/main/java/net/glowstone/command/minecraft/SaveToggleCommand.java index 1fdb3531d2..a7a0c51b40 100644 --- a/src/main/java/net/glowstone/command/minecraft/SaveToggleCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/SaveToggleCommand.java @@ -10,6 +10,11 @@ public class SaveToggleCommand extends VanillaCommand { private final boolean on; + /** + * Creates the instance for the {@code /save-on} or {@code /save-off} command. + * + * @param on true for {@code /save-on}; false for {@code /save-off} + */ public SaveToggleCommand(boolean on) { super(on ? "save-on" : "save-off", on ? "Enables automatic server saves." : "Disables automatic sever saves.", diff --git a/src/main/java/net/glowstone/command/minecraft/SetBlockCommand.java b/src/main/java/net/glowstone/command/minecraft/SetBlockCommand.java index e92e758a47..a5b99509b9 100644 --- a/src/main/java/net/glowstone/command/minecraft/SetBlockCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/SetBlockCommand.java @@ -21,6 +21,9 @@ public class SetBlockCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public SetBlockCommand() { super("setblock", "Changes a block to another block.", diff --git a/src/main/java/net/glowstone/command/minecraft/SetIdleTimeoutCommand.java b/src/main/java/net/glowstone/command/minecraft/SetIdleTimeoutCommand.java index 5dfaf152fa..fe29cd74c1 100644 --- a/src/main/java/net/glowstone/command/minecraft/SetIdleTimeoutCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/SetIdleTimeoutCommand.java @@ -9,6 +9,9 @@ public class SetIdleTimeoutCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public SetIdleTimeoutCommand() { super("setidletimeout", "Sets the time before idle players are kicked from the server.", "/setidletimeout ", Collections.emptyList()); diff --git a/src/main/java/net/glowstone/command/minecraft/SetWorldSpawnCommand.java b/src/main/java/net/glowstone/command/minecraft/SetWorldSpawnCommand.java index eeb4be846b..df426a6811 100644 --- a/src/main/java/net/glowstone/command/minecraft/SetWorldSpawnCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/SetWorldSpawnCommand.java @@ -13,6 +13,9 @@ public class SetWorldSpawnCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public SetWorldSpawnCommand() { super("setworldspawn", "Sets the world spawn.", "/setworldspawn OR /setworldspawn ", Collections.emptyList()); diff --git a/src/main/java/net/glowstone/command/minecraft/SpawnPointCommand.java b/src/main/java/net/glowstone/command/minecraft/SpawnPointCommand.java index 8222ae7565..d5d538d20a 100644 --- a/src/main/java/net/glowstone/command/minecraft/SpawnPointCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/SpawnPointCommand.java @@ -18,6 +18,9 @@ public class SpawnPointCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public SpawnPointCommand() { super("spawnpoint", "Sets the spawn point for a player.", "/spawnpoint OR /spawnpoint OR /spawnpoint ", diff --git a/src/main/java/net/glowstone/command/minecraft/SummonCommand.java b/src/main/java/net/glowstone/command/minecraft/SummonCommand.java index 11ee02eb4e..00d2b330f7 100644 --- a/src/main/java/net/glowstone/command/minecraft/SummonCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/SummonCommand.java @@ -25,6 +25,9 @@ public class SummonCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public SummonCommand() { super("summon", "Summons an entity.", "/summon [x] [y] [z] [dataTag]", Collections.emptyList()); diff --git a/src/main/java/net/glowstone/command/minecraft/TeleportCommand.java b/src/main/java/net/glowstone/command/minecraft/TeleportCommand.java index 9d37a508e6..fc7576c6a8 100644 --- a/src/main/java/net/glowstone/command/minecraft/TeleportCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/TeleportCommand.java @@ -15,6 +15,9 @@ public class TeleportCommand extends VanillaCommand { private static final Entity[] NO_ENTITY = new Entity[0]; + /** + * Creates the instance for this command. + */ public TeleportCommand() { super("teleport", "Teleports entities to coordinates relative to the sender", @@ -54,10 +57,13 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) sender.sendMessage(ChatColor.RED + "There's no entity matching the target."); } else { for (Entity target : targets) { - String x = args[1], y = args[2], z = args[3]; + String x = args[1]; + String y = args[2]; + String z = args[3]; Location targetLocation = CommandUtils.getLocation(location, x, y, z); if (args.length > 4) { - String yaw = args[4], pitch = args[5]; + String yaw = args[4]; + String pitch = args[5]; targetLocation = CommandUtils.getRotation(target.getLocation(), yaw, pitch); } else { targetLocation.setYaw(target.getLocation().getYaw()); diff --git a/src/main/java/net/glowstone/command/minecraft/TellCommand.java b/src/main/java/net/glowstone/command/minecraft/TellCommand.java index 1f726d614e..1196afa7f8 100644 --- a/src/main/java/net/glowstone/command/minecraft/TellCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/TellCommand.java @@ -16,6 +16,9 @@ public class TellCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public TellCommand() { super("tell", "Send a private message.", "/tell ", Arrays.asList("msg", "w")); diff --git a/src/main/java/net/glowstone/command/minecraft/TellrawCommand.java b/src/main/java/net/glowstone/command/minecraft/TellrawCommand.java index de1409ed0c..8bacb7f3eb 100644 --- a/src/main/java/net/glowstone/command/minecraft/TellrawCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/TellrawCommand.java @@ -15,6 +15,9 @@ public class TellrawCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public TellrawCommand() { super("tellraw", "Send a private JSON message to the given player", "/tellraw ", Collections.emptyList()); diff --git a/src/main/java/net/glowstone/command/minecraft/TestForBlockCommand.java b/src/main/java/net/glowstone/command/minecraft/TestForBlockCommand.java index 031bfeb25d..65618f2b6b 100644 --- a/src/main/java/net/glowstone/command/minecraft/TestForBlockCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/TestForBlockCommand.java @@ -21,11 +21,14 @@ public class TestForBlockCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public TestForBlockCommand() { super("testforblock", - "Tests for a certain block at a given location", - "/testforblock [dataValue|state] [dataTag]", - Collections.emptyList()); + "Tests for a certain block at a given location", + "/testforblock [dataValue|state] [dataTag]", + Collections.emptyList()); setPermission("minecraft.command.testforblock"); } @@ -47,14 +50,15 @@ public boolean execute(CommandSender sender, String label, String[] args) { sender.sendMessage(ChatColor.RED + itemName + " is not a valid block type."); } Location location = CommandUtils - .getLocation(CommandUtils.getLocation(sender), args[0], args[1], args[2]); + .getLocation(CommandUtils.getLocation(sender), args[0], args[1], args[2]); GlowBlock block = (GlowBlock) location.getBlock(); if (block.getType() != type) { sender.sendMessage( - ChatColor.RED + "The block at " + location.getBlockX() + ", " + location.getBlockY() - + ", " + location.getBlockZ() + - " is " + ItemIds.getName(block.getType()) + " (expected: " + ItemIds - .getName(type) + ")"); + ChatColor.RED + "The block at " + location.getBlockX() + ", " + location + .getBlockY() + + ", " + location.getBlockZ() + + " is " + ItemIds.getName(block.getType()) + " (expected: " + ItemIds + .getName(type) + ")"); return false; } if (args.length > 4) { @@ -65,20 +69,22 @@ public boolean execute(CommandSender sender, String label, String[] args) { } if (data.isNumeric() && block.getData() != data.getNumericValue()) { sender.sendMessage( - ChatColor.RED + "The block at " + location.getBlockX() + ", " + location - .getBlockY() + ", " + location.getBlockZ() + - " had the data value of " + block.getData() + " (expected: " + data + ")"); + ChatColor.RED + "The block at " + location.getBlockX() + ", " + location + .getBlockY() + ", " + location.getBlockZ() + + " had the data value of " + block.getData() + + " (expected: " + data + ")"); return false; } else if (!data.isNumeric()) { try { boolean matches = StateSerialization - .matches(block.getType(), block.getState().getData(), data); + .matches(block.getType(), block.getState().getData(), data); if (!matches) { // TODO: Print the actual state of the block sender.sendMessage( - ChatColor.RED + "The block at " + location.getBlockX() + ", " + location - .getBlockY() + ", " + location.getBlockZ() + - " did not match the expected state of " + state); + ChatColor.RED + "The block at " + location.getBlockX() + ", " + + location + .getBlockY() + ", " + location.getBlockZ() + + " did not match the expected state of " + state); return false; } } catch (InvalidBlockStateException e) { @@ -89,16 +95,16 @@ public boolean execute(CommandSender sender, String label, String[] args) { } if (args.length > 5 && block.getBlockEntity() != null) { String dataTag = String - .join(" ", new ArrayList<>(Arrays.asList(args)).subList(5, args.length)); + .join(" ", new ArrayList<>(Arrays.asList(args)).subList(5, args.length)); try { CompoundTag tag = Mojangson.parseCompound(dataTag); CompoundTag blockTag = new CompoundTag(); block.getBlockEntity().saveNbt(blockTag); if (!tag.matches(blockTag)) { sender.sendMessage( - ChatColor.RED + "The block at " + location.getBlockX() + ", " + location - .getBlockY() + ", " + location.getBlockZ() + - " did not have the required NBT keys"); + ChatColor.RED + "The block at " + location.getBlockX() + ", " + location + .getBlockY() + ", " + location.getBlockZ() + + " did not have the required NBT keys"); return false; } } catch (MojangsonParseException e) { @@ -113,7 +119,7 @@ public boolean execute(CommandSender sender, String label, String[] args) { @Override public List tabComplete(CommandSender sender, String alias, String[] args) - throws IllegalArgumentException { + throws IllegalArgumentException { if (args.length == 4) { return ItemIds.getTabCompletion(args[3]); } @@ -122,7 +128,8 @@ public List tabComplete(CommandSender sender, String alias, String[] arg private void sendSuccess(CommandSender sender, Location location) { sender.sendMessage( - "Successfully found the block at " + location.getBlockX() + ", " + location.getBlockY() - + ", " + location.getBlockZ()); + "Successfully found the block at " + location.getBlockX() + ", " + location + .getBlockY() + + ", " + location.getBlockZ()); } } diff --git a/src/main/java/net/glowstone/command/minecraft/TestForBlocksCommand.java b/src/main/java/net/glowstone/command/minecraft/TestForBlocksCommand.java new file mode 100644 index 0000000000..c3e942fe35 --- /dev/null +++ b/src/main/java/net/glowstone/command/minecraft/TestForBlocksCommand.java @@ -0,0 +1,166 @@ +package net.glowstone.command.minecraft; + +import static net.glowstone.util.RectangularRegion.IterationDirection.FORWARDS; + +import java.util.Collections; +import java.util.Iterator; +import java.util.Objects; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.glowstone.GlowWorld; +import net.glowstone.block.GlowBlock; +import net.glowstone.command.CommandUtils; +import net.glowstone.util.RectangularRegion; +import net.glowstone.util.nbt.CompoundTag; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.command.CommandSender; +import org.bukkit.command.defaults.VanillaCommand; + +public class TestForBlocksCommand extends VanillaCommand { + @RequiredArgsConstructor + public enum MatchMode { + ALL("all") { + @Override + public boolean isFiltered(GlowBlock fromBlock) { + return false; + } + }, + MASKED("masked") { + @Override + public boolean isFiltered(GlowBlock fromBlock) { + return fromBlock.getType() == Material.AIR; + } + }; + + @Getter + private final String commandName; + + /** + * Returns the MatchMode with a given subcommand name, or null if none match. + * + * @param commandName the subcommand name to look up. + * @return the mask mode. + */ + public static MatchMode fromCommandName(String commandName) { + for (MatchMode matchMode : values()) { + if (matchMode.getCommandName().equals(commandName)) { + return matchMode; + } + } + return null; + } + + /** + * Whether the source region's block is filtered from matching. + * @param fromBlock The block in the source region. + * @return true if the block is filtered, false otherwise. + */ + public abstract boolean isFiltered(GlowBlock fromBlock); + + /** + * Whether the block from the source region matches the block from the destination region. + * @param fromBlock The block from the source region. + * @param toBlock The block from the destination region. + * @return true if the blocks match, false otherwise. + */ + public boolean matches(GlowBlock fromBlock, GlowBlock toBlock) { + if (isFiltered(fromBlock)) { + return true; + } + CompoundTag fromEntityTag = null; + if (fromBlock.getBlockEntity() != null) { + fromEntityTag = new CompoundTag(); + fromBlock.getBlockEntity().saveNbt(fromEntityTag); + } + CompoundTag toEntityTag = null; + if (toBlock.getBlockEntity() != null) { + toEntityTag = new CompoundTag(); + toBlock.getBlockEntity().saveNbt(fromEntityTag); + } + Material fromType = fromBlock.getType(); + Material toType = toBlock.getType(); + byte fromData = fromBlock.getData(); + byte toData = toBlock.getData(); + return Objects.equals(fromType, toType) + && Objects.equals(fromData, toData) + && Objects.equals(fromEntityTag, toEntityTag); + } + } + + /** + * Creates the instance for this command. + */ + public TestForBlocksCommand() { + super("testforblocks", + "Tests whether the blocks in two regions match.", + "/testforblock [mode]", + Collections.emptyList()); + setPermission("minecraft.command.testforblocks"); + } + + @Override + public boolean execute(CommandSender sender, String commandLabel, String[] args) { + if (!testPermission(sender)) { + return false; + } + + if (args.length < 9) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + if (!CommandUtils.isPhysical(sender)) { + sender.sendMessage("This command may only be executed by physical objects"); + return false; + } + + GlowWorld world = CommandUtils.getWorld(sender); + + Location parsedFrom1 = CommandUtils.getLocation(sender, args[0], args[1], args[2]); + Location parsedFrom2 = CommandUtils.getLocation(sender, args[3], args[4], args[5]); + Location to = CommandUtils.getLocation(sender, args[6], args[7], args[8]); + + MatchMode matchMode = args.length >= 10 + ? MatchMode.fromCommandName(args[9]) : MatchMode.ALL; + + if (matchMode == null) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + RectangularRegion fromRegion = new RectangularRegion(parsedFrom1, parsedFrom2); + RectangularRegion toRegion = fromRegion.moveTo(to); + + Iterator fromIterator = fromRegion + .blockLocations(FORWARDS, FORWARDS, FORWARDS).iterator(); + Iterator toIterator = toRegion + .blockLocations(FORWARDS, FORWARDS, FORWARDS).iterator(); + + int blocksMatched = 0; + + while (fromIterator.hasNext() && toIterator.hasNext()) { + Location fromLocation = fromIterator.next(); + Location toLocation = toIterator.next(); + + GlowBlock fromBlock = world.getBlockAt(fromLocation); + GlowBlock toBlock = world.getBlockAt(toLocation); + + if (matchMode.matches(fromBlock, toBlock)) { + if (!matchMode.isFiltered(fromBlock)) { + blocksMatched++; + } + } else { + sender.sendMessage(ChatColor.RED + "Source and destination are not identical"); + return false; + } + } + + sender.sendMessage(blocksMatched + " blocks compared"); + + return true; + } + + +} diff --git a/src/main/java/net/glowstone/command/minecraft/TestForCommand.java b/src/main/java/net/glowstone/command/minecraft/TestForCommand.java index 9ed5d2282b..cfd1032eff 100644 --- a/src/main/java/net/glowstone/command/minecraft/TestForCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/TestForCommand.java @@ -18,6 +18,9 @@ public class TestForCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public TestForCommand() { super("testfor", "Tests for a certain target in game", @@ -84,7 +87,8 @@ public boolean execute(CommandSender sender, String label, String[] args) { } } - // TODO: When command blocks are implemented, this should be updated to output the number of matching entities. + // TODO: When command blocks are implemented, this should be updated to output the number of + // matching entities. return true; } } diff --git a/src/main/java/net/glowstone/command/minecraft/TimeCommand.java b/src/main/java/net/glowstone/command/minecraft/TimeCommand.java index aa81c36a9f..5f2a9b5281 100644 --- a/src/main/java/net/glowstone/command/minecraft/TimeCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/TimeCommand.java @@ -16,9 +16,13 @@ public class TimeCommand extends VanillaCommand { private static final List SUBCOMMANDS = Arrays.asList("set", "add"); private static final List TIMES = Arrays.asList("day", "night"); + /** + * Creates the instance for this command. + */ public TimeCommand() { - super("time", "Changes the time of the world.", "/time ", - Collections.emptyList()); + super("time", "Changes the time of the world.", + "/time OR /time query ", + Collections.emptyList()); setPermission("minecraft.command.time"); } @@ -60,6 +64,25 @@ public boolean execute(CommandSender sender, String label, String[] args) { return false; } sender.sendMessage("Added " + mod + " to the time"); + } else if (subcommand.equals("query")) { + String output; + switch (value.toLowerCase()) { + case "gametime": + output = "The time is " + world.getTime(); + break; + case "daytime": + output = "The time of day is " + world.getTime() % 24000; + break; + case "day": + output = "The day is " + world.getTime() / 24000; + break; + default: + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + sender.sendMessage(output); + // TODO: Set the success count for command blocks + return true; } else { sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); return false; @@ -70,14 +93,14 @@ public boolean execute(CommandSender sender, String label, String[] args) { @Override public List tabComplete(CommandSender sender, String alias, String[] args) - throws IllegalArgumentException { + throws IllegalArgumentException { if (args.length == 1) { return (List) StringUtil - .copyPartialMatches(args[0], SUBCOMMANDS, new ArrayList(SUBCOMMANDS.size())); + .copyPartialMatches(args[0], SUBCOMMANDS, new ArrayList(SUBCOMMANDS.size())); } if (args.length == 2 && args[0].equals("set")) { return (List) StringUtil - .copyPartialMatches(args[1], TIMES, new ArrayList(TIMES.size())); + .copyPartialMatches(args[1], TIMES, new ArrayList(TIMES.size())); } return Collections.emptyList(); } diff --git a/src/main/java/net/glowstone/command/minecraft/TitleCommand.java b/src/main/java/net/glowstone/command/minecraft/TitleCommand.java index a6d2a1abfb..afa6b4c340 100644 --- a/src/main/java/net/glowstone/command/minecraft/TitleCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/TitleCommand.java @@ -19,9 +19,12 @@ public class TitleCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public TitleCommand() { super("title", "Sends a title to the specified player(s)", - "/title ...", Collections.emptyList()); + "/title ...", Collections.emptyList()); setPermission("minecraft.command.title"); } @@ -48,7 +51,8 @@ private static ChatColor toColor(String name) { } /** - * Converts a valid JSON chat component to a basic colored string. This does not parse components like hover or click events. This returns null on parse failure. + * Converts a valid JSON chat component to a basic colored string. This does not parse + * components like hover or click events. This returns null on parse failure. * * @param json the json chat component * @return the colored string, or null @@ -120,7 +124,7 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) } else if (action.equalsIgnoreCase("title")) { if (args.length < 3) { sender.sendMessage( - ChatColor.RED + "Usage: /title " + action + " "); + ChatColor.RED + "Usage: /title " + action + " "); return false; } @@ -133,7 +137,8 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) String raw = message.toString().trim(); if (!validJson(raw)) { sender - .sendMessage(ChatColor.RED + "Invalid JSON: Could not parse, invalid format?"); + .sendMessage( + ChatColor.RED + "Invalid JSON: Could not parse, invalid format?"); return false; } @@ -150,7 +155,7 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) } else if (action.equalsIgnoreCase("subtitle")) { if (args.length < 3) { sender.sendMessage( - ChatColor.RED + "Usage: /title " + action + " "); + ChatColor.RED + "Usage: /title " + action + " "); return false; } @@ -163,7 +168,8 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) String raw = message.toString().trim(); if (!validJson(raw)) { sender - .sendMessage(ChatColor.RED + "Invalid JSON: Could not parse, invalid format?"); + .sendMessage( + ChatColor.RED + "Invalid JSON: Could not parse, invalid format?"); return false; } @@ -179,7 +185,7 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) } else if (action.equalsIgnoreCase("times")) { if (args.length != 5) { sender.sendMessage(ChatColor.RED + "Usage: /title " + action - + " "); + + " "); return false; } @@ -197,8 +203,8 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) } ((GlowPlayer) player) - .updateTitle(TitleMessage.Action.TIMES, toInt(args[2]), toInt(args[3]), - toInt(args[4])); + .updateTitle(TitleMessage.Action.TIMES, toInt(args[2]), toInt(args[3]), + toInt(args[4])); sender.sendMessage("Updated " + player.getName() + "'s times"); } else { diff --git a/src/main/java/net/glowstone/command/minecraft/TpCommand.java b/src/main/java/net/glowstone/command/minecraft/TpCommand.java index 751bce03bf..0ef4f92080 100644 --- a/src/main/java/net/glowstone/command/minecraft/TpCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/TpCommand.java @@ -13,9 +13,13 @@ public class TpCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public TpCommand() { super("tp", "Teleports an entity to another entity or to specific coordinates.", - "/tp [target entity] OR /tp [target entity] [ ]", + "/tp [target entity] " + + "OR /tp [target entity] [ ]", Collections.emptyList()); setPermission("minecraft.command.tp"); } @@ -69,7 +73,8 @@ public boolean execute(CommandSender sender, String label, String[] args) { } } else { Entity destination; - String fromName = args[0], destName = args[1]; + String fromName = args[0]; + String destName = args[1]; if (fromName.startsWith("@") && fromName.length() >= 2 && CommandUtils .isPhysical(sender)) { Location location = CommandUtils.getLocation(sender); diff --git a/src/main/java/net/glowstone/command/minecraft/WeatherCommand.java b/src/main/java/net/glowstone/command/minecraft/WeatherCommand.java index 120ec9d146..8478671bbb 100644 --- a/src/main/java/net/glowstone/command/minecraft/WeatherCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/WeatherCommand.java @@ -15,6 +15,9 @@ public class WeatherCommand extends VanillaCommand { private static final List WEATHER = Arrays.asList("clear", "rain", "thunder"); + /** + * Creates the instance for this command. + */ public WeatherCommand() { super("weather", "Changes the weather in the world.", "/weather [duration in seconds]", Collections.emptyList()); diff --git a/src/main/java/net/glowstone/command/minecraft/WhitelistCommand.java b/src/main/java/net/glowstone/command/minecraft/WhitelistCommand.java index 4f6d92b0a0..d9a8ea0d43 100644 --- a/src/main/java/net/glowstone/command/minecraft/WhitelistCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/WhitelistCommand.java @@ -6,7 +6,9 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import net.glowstone.GlowServer; import net.glowstone.command.CommandUtils; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; @@ -16,11 +18,14 @@ public class WhitelistCommand extends VanillaCommand { private static final List SUBCOMMANDS = Arrays - .asList("on", "off", "list", "add", "remove", "reload"); + .asList("on", "off", "list", "add", "remove", "reload"); + /** + * Creates the instance for this command. + */ public WhitelistCommand() { super("whitelist", "Manage the server whitelist.", - "/whitelist ", Collections.emptyList()); + "/whitelist ", Collections.emptyList()); setPermission("minecraft.command.whitelist"); } @@ -34,6 +39,7 @@ public boolean execute(CommandSender sender, String label, String[] args) { return false; } String subcommand = args[0]; + GlowServer server = (GlowServer) Bukkit.getServer(); if (subcommand.equals("on")) { sender.getServer().setWhitelist(true); sender.sendMessage("Turned on the whitelist"); @@ -61,9 +67,16 @@ public boolean execute(CommandSender sender, String label, String[] args) { return false; } String name = args[1]; - OfflinePlayer player = sender.getServer().getOfflinePlayer(name); - player.setWhitelisted(true); - sender.sendMessage("Added " + name + " to the whitelist"); + server.getOfflinePlayerAsync(name).whenCompleteAsync((player, ex) -> { + if (ex != null) { + sender.sendMessage(ChatColor.RED + "Failed to add " + name + + " to the whitelist: " + ex.getMessage()); + ex.printStackTrace(); + return; + } + player.setWhitelisted(true); + sender.sendMessage("Added " + player.getName() + " to the whitelist"); + }); return true; } if (subcommand.equals("remove")) { @@ -72,10 +85,16 @@ public boolean execute(CommandSender sender, String label, String[] args) { return false; } String name = args[1]; - OfflinePlayer player = sender.getServer().getOfflinePlayer(name); - player.setWhitelisted(false); - sender.sendMessage("Removed " + name + " to the whitelist"); - return true; + server.getOfflinePlayerAsync(name).whenCompleteAsync((player, ex) -> { + if (ex != null) { + sender.sendMessage(ChatColor.RED + "Failed to remove " + name + + " from the whitelist: " + ex.getMessage()); + ex.printStackTrace(); + return; + } + player.setWhitelisted(false); + sender.sendMessage("Removed " + player.getName() + " from the whitelist"); + }); } if (subcommand.equals("reload")) { sender.getServer().reloadWhitelist(); @@ -88,10 +107,10 @@ public boolean execute(CommandSender sender, String label, String[] args) { @Override public List tabComplete(CommandSender sender, String alias, String[] args) - throws IllegalArgumentException { + throws IllegalArgumentException { if (args.length == 1) { return (List) StringUtil - .copyPartialMatches(args[0], SUBCOMMANDS, new ArrayList(SUBCOMMANDS.size())); + .copyPartialMatches(args[0], SUBCOMMANDS, new ArrayList(SUBCOMMANDS.size())); } if (args.length > 1) { String subcommand = args[0]; @@ -101,9 +120,9 @@ public List tabComplete(CommandSender sender, String alias, String[] arg if (subcommand.equals("remove")) { Set whitelistedPlayers = sender.getServer().getWhitelistedPlayers(); List names = whitelistedPlayers.stream().map(OfflinePlayer::getName) - .collect(Collectors.toList()); + .collect(Collectors.toList()); return (List) StringUtil - .copyPartialMatches(args[1], names, new ArrayList(names.size())); + .copyPartialMatches(args[1], names, new ArrayList(names.size())); } return Collections.emptyList(); } diff --git a/src/main/java/net/glowstone/command/minecraft/WorldBorderCommand.java b/src/main/java/net/glowstone/command/minecraft/WorldBorderCommand.java index 56a0f5ddf9..ac3139ce91 100644 --- a/src/main/java/net/glowstone/command/minecraft/WorldBorderCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/WorldBorderCommand.java @@ -10,6 +10,9 @@ public class WorldBorderCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public WorldBorderCommand() { super("worldborder"); setUsage("/worldborder ..."); @@ -37,7 +40,8 @@ public boolean execute(CommandSender sender, String label, String[] args) { } return true; } else { - double x, z; + double x; + double z; try { x = Double.parseDouble(args[1]); z = Double.parseDouble(args[2]); diff --git a/src/main/java/net/glowstone/command/minecraft/XpCommand.java b/src/main/java/net/glowstone/command/minecraft/XpCommand.java index 4af6e73899..41f9d98766 100644 --- a/src/main/java/net/glowstone/command/minecraft/XpCommand.java +++ b/src/main/java/net/glowstone/command/minecraft/XpCommand.java @@ -16,6 +16,9 @@ public class XpCommand extends VanillaCommand { + /** + * Creates the instance for this command. + */ public XpCommand() { super("xp", "Adds experience to a player.", "/xp [player] OR /xp L [player] OR /xp l [player]", @@ -33,7 +36,8 @@ public boolean execute(CommandSender sender, String label, String[] args) { sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); return false; } else { - final String stringAmount = args[0], playerPattern = (args.length > 1) ? args[1] : null; + final String stringAmount = args[0]; + final String playerPattern = (args.length > 1) ? args[1] : null; final boolean addLevels = stringAmount.endsWith("l") || stringAmount.endsWith("L"); int amount; List targets; diff --git a/src/main/java/net/glowstone/constants/GlowBiomeClimate.java b/src/main/java/net/glowstone/constants/GlowBiomeClimate.java index 8824d138d8..ddfabcb98d 100644 --- a/src/main/java/net/glowstone/constants/GlowBiomeClimate.java +++ b/src/main/java/net/glowstone/constants/GlowBiomeClimate.java @@ -63,6 +63,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Random; +import lombok.Data; import net.glowstone.util.noise.SimplexOctaveGenerator; import org.bukkit.block.Biome; import org.bukkit.block.Block; @@ -168,6 +169,7 @@ private static void setBiomeClimate(BiomeClimate temp, Biome... biomes) { } } + @Data private static class BiomeClimate { public static final BiomeClimate DEFAULT = new BiomeClimate(0.5D, 0.5D, true); @@ -195,23 +197,5 @@ private static class BiomeClimate { private final double temperature; private final double humidity; private final boolean rainy; - - public BiomeClimate(double temperature, double humidity, boolean rainy) { - this.temperature = temperature; - this.humidity = humidity; - this.rainy = rainy; - } - - public double getTemperature() { - return temperature; - } - - public double getHumidity() { - return humidity; - } - - public boolean isRainy() { - return rainy; - } } } diff --git a/src/main/java/net/glowstone/constants/GlowBlockEntity.java b/src/main/java/net/glowstone/constants/GlowBlockEntity.java index c7500e3344..1c20b5fc87 100644 --- a/src/main/java/net/glowstone/constants/GlowBlockEntity.java +++ b/src/main/java/net/glowstone/constants/GlowBlockEntity.java @@ -1,8 +1,12 @@ package net.glowstone.constants; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + /** * Name mappings for magic values in UpdateBlockEntity packet. */ +@RequiredArgsConstructor public enum GlowBlockEntity { MOB_SPAWNER_POTENTIALS(1), COMMAND_BLOCK(2), @@ -16,18 +20,11 @@ public enum GlowBlockEntity { SHULKER_BOX(10), BED(11),; - private final int value; - - GlowBlockEntity(int value) { - this.value = value; - } - /** * Gets the magic number associated with this GlowBlockEntity. * * @return the magic number */ - public int getValue() { - return value; - } + @Getter + private final int value; } diff --git a/src/main/java/net/glowstone/constants/GlowEnchantment.java b/src/main/java/net/glowstone/constants/GlowEnchantment.java index 1aec9764fa..b2b0cdcdd7 100644 --- a/src/main/java/net/glowstone/constants/GlowEnchantment.java +++ b/src/main/java/net/glowstone/constants/GlowEnchantment.java @@ -175,6 +175,7 @@ public int getWeight() { * * @return true if the enchantment is a treasure, otherwise false */ + @Override public boolean isTreasure() { return impl.treasure; } diff --git a/src/main/java/net/glowstone/constants/GlowParticle.java b/src/main/java/net/glowstone/constants/GlowParticle.java index 83d88ccd43..d2a402e582 100644 --- a/src/main/java/net/glowstone/constants/GlowParticle.java +++ b/src/main/java/net/glowstone/constants/GlowParticle.java @@ -102,8 +102,8 @@ public static int[] getExtData(Effect particle, MaterialData material) { } // http://wiki.vg/Protocol#Particle - // data "Length depends on particle. "iconcrack" [Effect.ITEM_BREAK] has length of 2, "blockcrack", - // and "blockdust" have lengths of 1, the rest have 0" + // data 'Length depends on particle. "iconcrack" [Effect.ITEM_BREAK] has length of + // 2, "blockcrack" and "blockdust" have lengths of 1, the rest have 0' // iconcrack_(id)_(data) 36 return new int[]{material.getItemTypeId(), material.getData()}; case TILE_BREAK: @@ -153,8 +153,8 @@ public static int[] getExtData(Particle particle, Object object) { ItemStack item = (ItemStack) object; // http://wiki.vg/Protocol#Particle - // data "Length depends on particle. "iconcrack" [Effect.ITEM_BREAK] has length of 2, "blockcrack", - // and "blockdust" have lengths of 1, the rest have 0" + // data 'Length depends on particle. "iconcrack" [Effect.ITEM_BREAK] has length of 2, + // "blockcrack" and "blockdust" have lengths of 1, the rest have 0' // iconcrack_(id)_(data) 36 return new int[]{item.getTypeId(), item.getDurability()}; } @@ -165,7 +165,8 @@ public static int[] getExtData(Particle particle, Object object) { /** - * Determine whether a particle type is considered long distance, meaning it has a higher visible range than normal. + * Determine whether a particle type is considered long distance, meaning it has a higher + * visible range than normal. * * @param particle the Particle. * @return True if the particle is long distance. @@ -176,13 +177,14 @@ public static boolean isLongDistance(Effect particle) { case EXPLOSION_LARGE: case EXPLOSION_HUGE: return true; + default: + return false; } - - return false; } /** - * Determine whether a particle type is considered long distance, meaning it has a higher visible range than normal. + * Determine whether a particle type is considered long distance, meaning it has a higher + * visible range than normal. * * @param particle the Particle. * @return True if the particle is long distance. @@ -194,9 +196,9 @@ public static boolean isLongDistance(Particle particle) { case EXPLOSION_HUGE: case MOB_APPEARANCE: return true; + default: + return false; } - - return false; } private static void set(Particle particle, Effect effect, int id) { diff --git a/src/main/java/net/glowstone/constants/GlowPotionEffect.java b/src/main/java/net/glowstone/constants/GlowPotionEffect.java index 114b9accc3..68852b27ee 100644 --- a/src/main/java/net/glowstone/constants/GlowPotionEffect.java +++ b/src/main/java/net/glowstone/constants/GlowPotionEffect.java @@ -10,6 +10,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.bukkit.Color; import org.bukkit.entity.LivingEntity; import org.bukkit.potion.Potion; @@ -145,7 +147,8 @@ public double getDurationModifier() { /** * Pulse this potion effect on a specified entity. * - *

If the potion effect is not applicable, nothing happens. For instant effects, will only have an effect if 'ticks' is 0. + *

If the potion effect is not applicable, nothing happens. For instant effects, will only + * have an effect if 'ticks' is 0. * * @param entity The entity to pulse on. * @param effect Information on the effect's state. @@ -158,6 +161,7 @@ public void pulse(LivingEntity entity, PotionEffect effect) { } } + @RequiredArgsConstructor private enum Impl { SPEED(1, false, 1.0, "minecraft:speed"), SLOW(2, false, 0.5, "minecraft:slowness"), @@ -190,19 +194,9 @@ private enum Impl { private final int id; private final boolean instant; private final double modifier; + @Getter private final String vanillaId; - Impl(int id, boolean instant, double modifier, String vanillaId) { - this.id = id; - this.instant = instant; - this.modifier = modifier; - this.vanillaId = vanillaId; - } - - public String getVanillaId() { - return vanillaId; - } - protected void pulse(LivingEntity entity, int amplifier, int ticks) { // TODO implement potion pulse } diff --git a/src/main/java/net/glowstone/constants/GlowSound.java b/src/main/java/net/glowstone/constants/GlowSound.java index 9ab56074d2..e1a5f05333 100644 --- a/src/main/java/net/glowstone/constants/GlowSound.java +++ b/src/main/java/net/glowstone/constants/GlowSound.java @@ -9,14 +9,19 @@ public class GlowSound { private static final Map SOUNDS = new HashMap<>(); + private static final ImmutableMap VANILLA_SOUNDS; static { + ImmutableMap.Builder vanillaSounds = ImmutableMap.builder(); // register vanilla sounds // as of 1.11, sounds do not have a default category // instead, the category of the sound playing is determined by the source of the sound for (Sound sound : Sound.values()) { - reg(getVanillaId(sound), SoundCategory.MASTER); + String vanillaId = getVanillaId(sound); + reg(vanillaId, SoundCategory.MASTER); + vanillaSounds.put(vanillaId, sound); } + VANILLA_SOUNDS = vanillaSounds.build(); } public static void reg(String id, SoundCategory category) { @@ -31,15 +36,14 @@ public static String getVanillaId(Sound sound) { return "minecraft:" + sound.name().toLowerCase().replaceAll("_", "."); } + /** + * Returns a vanilla Minecraft sound with the given ID, or null if none exists. + * + * @param id the id + * @return the sound, or null if none match + */ public static Sound getVanillaSound(String id) { - if (id.startsWith("minecraft:")) { - for (Sound sound : Sound.values()) { - if (getVanillaId(sound).equals(id)) { - return sound; - } - } - } - return null; + return VANILLA_SOUNDS.get(id); } public static SoundCategory getCategory(int category) { @@ -47,6 +51,6 @@ public static SoundCategory getCategory(int category) { } public static Map getSounds() { - return (Map) ImmutableMap.builder().putAll(SOUNDS).build(); + return ImmutableMap.builder().putAll(SOUNDS).build(); } } diff --git a/src/main/java/net/glowstone/constants/GlowTree.java b/src/main/java/net/glowstone/constants/GlowTree.java index a7c3b363f9..d491e504f0 100644 --- a/src/main/java/net/glowstone/constants/GlowTree.java +++ b/src/main/java/net/glowstone/constants/GlowTree.java @@ -17,10 +17,11 @@ import static org.bukkit.TreeType.TALL_REDWOOD; import static org.bukkit.TreeType.TREE; -import java.lang.reflect.Constructor; +import com.google.common.collect.ImmutableMap; import java.util.HashMap; import java.util.Map; import java.util.Random; +import java.util.function.BiFunction; import net.glowstone.generator.objects.trees.AcaciaTree; import net.glowstone.generator.objects.trees.BigTree; import net.glowstone.generator.objects.trees.BirchTree; @@ -38,47 +39,53 @@ import net.glowstone.generator.objects.trees.TallBirchTree; import net.glowstone.generator.objects.trees.TallRedwoodTree; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; import org.bukkit.TreeType; public final class GlowTree { + private static final ImmutableMap> CONSTRUCTORS = + ImmutableMap + .> + builder() + .put(TREE, GenericTree::new) + .put(BIG_TREE, BigTree::new) + .put(REDWOOD, RedwoodTree::new) + .put(TALL_REDWOOD, TallRedwoodTree::new) + .put(BIRCH, BirchTree::new) + .put(JUNGLE, MegaJungleTree::new) + .put(SMALL_JUNGLE, JungleTree::new) + .put(COCOA_TREE, CocoaTree::new) + .put(JUNGLE_BUSH, JungleBush::new) + .put(RED_MUSHROOM, RedMushroomTree::new) + .put(BROWN_MUSHROOM, BrownMushroomTree::new) + .put(SWAMP, SwampTree::new) + .put(ACACIA, AcaciaTree::new) + .put(DARK_OAK, DarkOakTree::new) + .put(MEGA_REDWOOD, MegaRedwoodTree::new) + .put(TALL_BIRCH, TallBirchTree::new) + .build(); + private static final Map> classTable = new HashMap<>(); static { - set(TREE, GenericTree.class); - set(BIG_TREE, BigTree.class); - set(REDWOOD, RedwoodTree.class); - set(TALL_REDWOOD, TallRedwoodTree.class); - set(BIRCH, BirchTree.class); - set(JUNGLE, MegaJungleTree.class); - set(SMALL_JUNGLE, JungleTree.class); - set(COCOA_TREE, CocoaTree.class); - set(JUNGLE_BUSH, JungleBush.class); - set(RED_MUSHROOM, RedMushroomTree.class); - set(BROWN_MUSHROOM, BrownMushroomTree.class); - set(SWAMP, SwampTree.class); - set(ACACIA, AcaciaTree.class); - set(DARK_OAK, DarkOakTree.class); - set(MEGA_REDWOOD, MegaRedwoodTree.class); - set(TALL_BIRCH, TallBirchTree.class); - } - private GlowTree() { } - public static GenericTree newInstance(TreeType type, Random random, Location loc, - BlockStateDelegate delegate) { - try { - Constructor c = classTable.get(type) - .getConstructor(Random.class, Location.class, BlockStateDelegate.class); - return c.newInstance(random, loc, delegate); - } catch (Exception ex) { - return new GenericTree(random, loc, delegate); - } + private GlowTree() { } - private static void set(TreeType type, Class clazz) { - classTable.put(type, clazz); + /** + * Creates a tree of any vanilla type. + * + * @param type the tree type + * @param random the PRNG + * @param delegate the BlockStateDelegate used to check for space and to fill wood and leaf + * blocks + * @return a new tree of {@code type} + */ + public static GenericTree newInstance(TreeType type, Random random, + BlockStateDelegate delegate) { + return CONSTRUCTORS.getOrDefault(type, GenericTree::new).apply(random, delegate); } } diff --git a/src/main/java/net/glowstone/constants/ItemIds.java b/src/main/java/net/glowstone/constants/ItemIds.java index 08c57a05b6..5f0d92c037 100644 --- a/src/main/java/net/glowstone/constants/ItemIds.java +++ b/src/main/java/net/glowstone/constants/ItemIds.java @@ -238,7 +238,7 @@ public final class ItemIds { both(205, "purpur_slab"); both(206, "end_bricks"); block(207, "beetroots"); - block(208, "grass_path"); + both(208, "grass_path"); block(209, "end_gateway"); block(210, "repeating_command_block"); block(211, "chain_command_block"); @@ -539,7 +539,8 @@ public static Material getBlock(String name) { } /** - * Verify that a given material is a valid item. All non-blocks are valid items, but some blocks cannot be represented as items. + * Verify that a given material is a valid item. All non-blocks are valid items, but some blocks + * cannot be represented as items. * * @param material The material to verify. * @return true if the material is a valid item. @@ -549,7 +550,8 @@ public static boolean isValidItem(Material material) { } /** - * Convert an ItemStack which may have a type that is unrepresentable as an item to one that does, or to an empty stack if this is not possible. + * Convert an ItemStack which may have a type that is unrepresentable as an item to one that + * does, or to an empty stack if this is not possible. * * @param stack The stack to sanitize. * @return The sanitized stack, or null. diff --git a/src/main/java/net/glowstone/dispenser/TNTDispenseBehavior.java b/src/main/java/net/glowstone/dispenser/TntDispenseBehavior.java similarity index 82% rename from src/main/java/net/glowstone/dispenser/TNTDispenseBehavior.java rename to src/main/java/net/glowstone/dispenser/TntDispenseBehavior.java index 7da6e6bd9f..d897900e6f 100644 --- a/src/main/java/net/glowstone/dispenser/TNTDispenseBehavior.java +++ b/src/main/java/net/glowstone/dispenser/TntDispenseBehavior.java @@ -3,18 +3,18 @@ import net.glowstone.GlowWorld; import net.glowstone.block.GlowBlock; import net.glowstone.block.blocktype.BlockDispenser; -import net.glowstone.entity.GlowTNTPrimed; +import net.glowstone.entity.GlowTntPrimed; import org.bukkit.Sound; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; -public class TNTDispenseBehavior extends DefaultDispenseBehavior { +public class TntDispenseBehavior extends DefaultDispenseBehavior { @Override protected ItemStack dispenseStack(GlowBlock block, ItemStack stack) { GlowWorld world = block.getWorld(); GlowBlock target = block.getRelative(BlockDispenser.getFacing(block)); - GlowTNTPrimed tnt = (GlowTNTPrimed) world + GlowTntPrimed tnt = (GlowTntPrimed) world .spawnEntity(target.getLocation().add(0.5, 0, 0.5), EntityType.PRIMED_TNT); world.playSound(tnt.getLocation(), Sound.ENTITY_TNT_PRIMED, 1, 1); stack.setAmount(stack.getAmount() - 1); diff --git a/src/main/java/net/glowstone/entity/AttributeManager.java b/src/main/java/net/glowstone/entity/AttributeManager.java index 1818850f4a..57ff08391b 100644 --- a/src/main/java/net/glowstone/entity/AttributeManager.java +++ b/src/main/java/net/glowstone/entity/AttributeManager.java @@ -43,7 +43,7 @@ public void applyMessages(Collection messages) { if (!needsUpdate) { return; } - messages.add(new EntityPropertyMessage(entity.id, properties)); + messages.add(new EntityPropertyMessage(entity.entityId, properties)); needsUpdate = false; } @@ -56,7 +56,7 @@ public void sendMessages(GlowSession session) { if (!needsUpdate) { return; } - int id = entity.id; + int id = entity.entityId; if (entity instanceof GlowPlayer) { GlowPlayer player = (GlowPlayer) entity; if (player.getUniqueId().equals(session.getPlayer().getUniqueId())) { @@ -110,6 +110,7 @@ public double getPropertyValue(Key key) { } public Map getAllProperties() { + // TODO: Defensive copy return properties; } diff --git a/src/main/java/net/glowstone/entity/EntityIdManager.java b/src/main/java/net/glowstone/entity/EntityIdManager.java index 65e22d82b8..f131e8ee32 100644 --- a/src/main/java/net/glowstone/entity/EntityIdManager.java +++ b/src/main/java/net/glowstone/entity/EntityIdManager.java @@ -26,7 +26,7 @@ public class EntityIdManager { * @return The id. */ synchronized int allocate(GlowEntity entity) { - if (entity.id != 0) { + if (entity.entityId != 0) { throw new IllegalStateException("Entity already has an id assigned."); } @@ -39,7 +39,7 @@ synchronized int allocate(GlowEntity entity) { } if (usedIds.add(id)) { - entity.id = id; + entity.entityId = id; lastId = id; return id; } @@ -54,10 +54,10 @@ synchronized int allocate(GlowEntity entity) { * @param entity The entity. */ synchronized void deallocate(GlowEntity entity) { - if (entity.id == 0) { + if (entity.entityId == 0) { throw new IllegalStateException("Entity does not have an id assigned."); } - usedIds.remove(entity.id); + usedIds.remove(entity.entityId); } } diff --git a/src/main/java/net/glowstone/entity/EntityManager.java b/src/main/java/net/glowstone/entity/EntityManager.java index fa03f1cdea..1dd8e7b270 100644 --- a/src/main/java/net/glowstone/entity/EntityManager.java +++ b/src/main/java/net/glowstone/entity/EntityManager.java @@ -34,8 +34,7 @@ public class EntityManager implements Iterable { * A map of entity types to a set containing all entities of that type. */ private final Multimap, GlowEntity> groupedEntities - = newSetMultimap( - new ConcurrentHashMap, Collection>(), + = newSetMultimap(new ConcurrentHashMap<>(), Sets::newConcurrentHashSet); /** @@ -80,10 +79,10 @@ public GlowEntity getEntity(int id) { */ @SuppressWarnings("unchecked") void register(GlowEntity entity) { - if (entity.id == 0) { + if (entity.entityId == 0) { throw new IllegalStateException("Entity has not been assigned an id."); } - entities.put(entity.id, entity); + entities.put(entity.entityId, entity); groupedEntities.put(entity.getClass(), entity); ((GlowChunk) entity.location.getChunk()).getRawEntities().add(entity); } @@ -94,7 +93,7 @@ void register(GlowEntity entity) { * @param entity The entity. */ void unregister(GlowEntity entity) { - entities.remove(entity.id); + entities.remove(entity.entityId); groupedEntities.remove(entity.getClass(), entity); ((GlowChunk) entity.location.getChunk()).getRawEntities().remove(entity); } diff --git a/src/main/java/net/glowstone/entity/EntityRegistry.java b/src/main/java/net/glowstone/entity/EntityRegistry.java index 9c57f5fee8..49223e348d 100644 --- a/src/main/java/net/glowstone/entity/EntityRegistry.java +++ b/src/main/java/net/glowstone/entity/EntityRegistry.java @@ -205,7 +205,7 @@ public class EntityRegistry { .put(PigZombie.class, GlowPigZombie.class) .put(Player.class, GlowPlayer.class) .put(PolarBear.class, GlowPolarBear.class) - .put(TNTPrimed.class, GlowTNTPrimed.class) + .put(TNTPrimed.class, GlowTntPrimed.class) .put(Rabbit.class, GlowRabbit.class) .put(Sheep.class, GlowSheep.class) .put(Shulker.class, GlowShulker.class) diff --git a/src/main/java/net/glowstone/entity/GlowAgeable.java b/src/main/java/net/glowstone/entity/GlowAgeable.java index 8080b1a110..d41bc18996 100644 --- a/src/main/java/net/glowstone/entity/GlowAgeable.java +++ b/src/main/java/net/glowstone/entity/GlowAgeable.java @@ -2,6 +2,8 @@ import com.flowpowered.network.Message; import java.util.List; +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.meta.MetadataIndex; import net.glowstone.entity.meta.MetadataMap; import net.glowstone.inventory.GlowMetaSpawn; @@ -27,10 +29,18 @@ public class GlowAgeable extends GlowCreature implements Ageable { private static final int BREEDING_AGE = 6000; protected float width; protected float height; + @Getter private int age; - private boolean ageLocked; + @Setter + private boolean ageLock; + @Getter + @Setter private int forcedAge; + @Getter + @Setter private int inLove; + @Getter + @Setter private GlowAgeable parent; /** @@ -47,7 +57,7 @@ public GlowAgeable(Location location, EntityType type, double maxHealth) { @Override public void pulse() { super.pulse(); - if (ageLocked) { + if (ageLock) { setScaleForAge(!isAdult()); } else { int currentAge = age; @@ -61,11 +71,6 @@ public void pulse() { } } - @Override - public final int getAge() { - return age; - } - @Override public final void setAge(int age) { this.age = age; @@ -74,12 +79,7 @@ public final void setAge(int age) { @Override public final boolean getAgeLock() { - return ageLocked; - } - - @Override - public final void setAgeLock(boolean ageLocked) { - this.ageLocked = ageLocked; + return ageLock; } @Override @@ -124,7 +124,7 @@ public List createSpawnMessage() { List messages = super.createSpawnMessage(); MetadataMap map = new MetadataMap(GlowAgeable.class); map.set(MetadataIndex.AGE_ISBABY, !isAdult()); - messages.add(new EntityMetadataMessage(id, map.getEntryList())); + messages.add(new EntityMetadataMessage(entityId, map.getEntryList())); return messages; } @@ -132,23 +132,6 @@ protected final void setScale(float scale) { setSize(height * scale, width * scale); } - public int getForcedAge() { - return forcedAge; - } - - public void setForcedAge(int forcedAge) { - this.forcedAge = forcedAge; - } - - public int getInLove() { - return inLove; - } - - public void setInLove(int inLove) { - this.inLove = inLove; - } - - @Override public boolean entityInteract(GlowPlayer player, InteractEntityMessage message) { super.entityInteract(player, message); @@ -194,14 +177,6 @@ public Ageable createBaby() { return ageable; } - public Ageable getParent() { - return parent; - } - - public void setParent(Ageable parent) { - this.parent = (GlowAgeable) parent; - } - @Override protected float getSoundPitch() { if (!isAdult()) { diff --git a/src/main/java/net/glowstone/entity/GlowCreature.java b/src/main/java/net/glowstone/entity/GlowCreature.java index 540fd7a5af..6bf3591459 100644 --- a/src/main/java/net/glowstone/entity/GlowCreature.java +++ b/src/main/java/net/glowstone/entity/GlowCreature.java @@ -3,6 +3,8 @@ import com.flowpowered.network.Message; import java.util.LinkedList; import java.util.List; +import lombok.Getter; +import lombok.Setter; import net.glowstone.net.message.play.entity.EntityHeadRotationMessage; import net.glowstone.net.message.play.entity.SpawnMobMessage; import net.glowstone.util.Position; @@ -19,11 +21,14 @@ public class GlowCreature extends GlowLivingEntity implements Creature { /** * The type of monster. */ + @Getter private final EntityType type; /** * The monster's target. */ + @Getter + @Setter private LivingEntity target; /** @@ -38,34 +43,19 @@ public GlowCreature(Location location, EntityType type, double maxHealth) { this.type = type; } - @Override - public EntityType getType() { - return type; - } - @Override public List createSpawnMessage() { List result = new LinkedList<>(); // spawn mob result.add(new SpawnMobMessage( - id, getUniqueId(), type.getTypeId(), location, metadata.getEntryList())); + entityId, getUniqueId(), type.getTypeId(), location, metadata.getEntryList())); // head facing - result.add(new EntityHeadRotationMessage(id, Position.getIntYaw(location))); + result.add(new EntityHeadRotationMessage(entityId, Position.getIntYaw(location))); // todo: equipment //result.add(createEquipmentMessage()); return result; } - - @Override - public LivingEntity getTarget() { - return target; - } - - @Override - public void setTarget(LivingEntity target) { - this.target = target; - } } diff --git a/src/main/java/net/glowstone/entity/GlowEntity.java b/src/main/java/net/glowstone/entity/GlowEntity.java index ba2e53ea13..e85a526f67 100644 --- a/src/main/java/net/glowstone/entity/GlowEntity.java +++ b/src/main/java/net/glowstone/entity/GlowEntity.java @@ -17,6 +17,7 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import lombok.Getter; +import lombok.Setter; import net.glowstone.EventFactory; import net.glowstone.GlowServer; import net.glowstone.GlowWorld; @@ -89,6 +90,7 @@ public abstract class GlowEntity implements Entity { /** * The server this entity belongs to. */ + @Getter protected final GlowServer server; /** * The entity's metadata. @@ -128,6 +130,7 @@ public abstract class GlowEntity implements Entity { /** * The world this entity belongs to. Guarded by {@link #worldLock}. */ + @Getter protected GlowWorld world; /** * Lock to prevent concurrent modifications affected by switching worlds. @@ -140,10 +143,12 @@ public abstract class GlowEntity implements Entity { /** * This entity's current identifier for its world. */ - protected int id; + @Getter + protected int entityId; /** * Whether the entity should have its position resent as if teleported. */ + @Getter protected boolean teleported; /** * Whether the entity should have its velocity resent. @@ -152,10 +157,13 @@ public abstract class GlowEntity implements Entity { /** * A counter of how long this entity has existed. */ + @Getter + @Setter protected int ticksLived; /** * The entity this entity is currently riding. */ + @Getter protected GlowEntity vehicle; /** * The entity's bounding box, or null if it has no physical presence. @@ -178,6 +186,7 @@ public abstract class GlowEntity implements Entity { /** * Gravity acceleration applied each tick. */ + @Setter protected Vector gravityAccel = new Vector(0, -0.04, 0); /** * The slipperiness multiplier applied according to the block this entity was on. @@ -190,26 +199,35 @@ public abstract class GlowEntity implements Entity { /** * An EntityDamageEvent representing the last damage cause on this entity. */ + @Getter + @Setter private EntityDamageEvent lastDamageCause; /** * A flag indicting if the entity is on the ground. */ + @Getter private boolean onGround = true; /** * The distance the entity is currently falling without touching the ground. */ + @Getter private float fallDistance; /** * How long the entity has been on fire, or 0 if it is not. */ + @Getter + @Setter private int fireTicks; /** * Whether gravity applies to the entity. */ + @Setter private boolean gravity = true; /** * Whether this entity is invulnerable. */ + @Getter + @Setter private boolean invulnerable; /** * The leash holders uuid of the entity. Will be null after the entities first tick. @@ -229,7 +247,15 @@ public abstract class GlowEntity implements Entity { /** * The Nether portal cooldown for the entity. */ + @Getter + @Setter private int portalCooldown; + /** + * Whether this entity has operator permissions. + */ + @Getter + @Setter + private boolean op; private Spigot spigot = new Spigot() { @Override public boolean isInvulnerable() { @@ -276,29 +302,14 @@ public void sendMessage(String[] strings) { throw new UnsupportedOperationException("Not implemented yet."); } - @Override - public final GlowServer getServer() { - return server; - } - @Override public String getName() { - throw new UnsupportedOperationException("Not implemented yet."); + return getType().getName(); } //////////////////////////////////////////////////////////////////////////// // Location stuff - @Override - public final GlowWorld getWorld() { - return world; - } - - @Override - public final int getEntityId() { - return id; - } - @Override public UUID getUniqueId() { if (uuid == null) { @@ -332,7 +343,7 @@ public boolean isDead() { @Override public boolean isValid() { - return world.getEntityManager().getEntity(id) == this; + return world.getEntityManager().getEntity(entityId) == this; } @Override @@ -404,10 +415,6 @@ public Vector getGravityAccel() { } } - public void setGravityAccel(Vector gravity) { - this.gravityAccel = gravity; - } - //////////////////////////////////////////////////////////////////////////// // Internals @@ -460,10 +467,6 @@ public boolean teleport(Entity destination, TeleportCause cause) { return teleport(destination.getLocation(), cause); } - public boolean isTeleported() { - return teleported; - } - /** * Checks if this entity is within the visible radius of another. * @@ -754,29 +757,30 @@ public List createUpdateMessage(GlowSession session) { boolean rotated = hasRotated(); if (teleported || moved && teleport) { - result.add(new EntityTeleportMessage(id, location)); + result.add(new EntityTeleportMessage(entityId, location)); } else if (rotated) { int yaw = Position.getIntYaw(location); int pitch = Position.getIntPitch(location); if (moved) { - result.add(new RelativeEntityPositionRotationMessage(id, + result.add(new RelativeEntityPositionRotationMessage(entityId, (short) dx, (short) dy, (short) dz, yaw, pitch)); } else { - result.add(new EntityRotationMessage(id, yaw, pitch)); + result.add(new EntityRotationMessage(entityId, yaw, pitch)); } } else if (moved) { - result.add(new RelativeEntityPositionMessage(id, (short) dx, (short) dy, (short) dz)); + result.add(new RelativeEntityPositionMessage( + entityId, (short) dx, (short) dy, (short) dz)); } // send changed metadata List changes = metadata.getChanges(); if (!changes.isEmpty()) { - result.add(new EntityMetadataMessage(id, changes)); + result.add(new EntityMetadataMessage(entityId, changes)); } // send velocity if needed if (velocityChanged) { - result.add(new EntityVelocityMessage(id, velocity)); + result.add(new EntityVelocityMessage(entityId, velocity)); } if (passengerChanged) { @@ -991,56 +995,16 @@ protected void updateBoundingBox() { //////////////////////////////////////////////////////////////////////////// // Various properties - @Override - public int getFireTicks() { - return fireTicks; - } - - @Override - public void setFireTicks(int ticks) { - fireTicks = ticks; - } - @Override public int getMaxFireTicks() { return 160; // this appears to be Minecraft's default value } - @Override - public float getFallDistance() { - return fallDistance; - } - @Override public void setFallDistance(float distance) { fallDistance = Math.max(distance, 0); } - @Override - public EntityDamageEvent getLastDamageCause() { - return lastDamageCause; - } - - @Override - public void setLastDamageCause(EntityDamageEvent event) { - lastDamageCause = event; - } - - @Override - public int getTicksLived() { - return ticksLived; - } - - @Override - public void setTicksLived(int value) { - ticksLived = value; - } - - @Override - public boolean isOnGround() { - return onGround; - } - /** * Sets the on-ground flag and clears fall distance. * @@ -1103,7 +1067,7 @@ public List getNearbyEntities(double x, double y, double z) { @Override public void playEffect(EntityEffect type) { - EntityStatusMessage message = new EntityStatusMessage(id, type); + EntityStatusMessage message = new EntityStatusMessage(entityId, type); world.getRawPlayers().stream().filter(player -> player.canSeeEntity(this)) .forEach(player -> player.getSession().send(message)); } @@ -1126,11 +1090,6 @@ public boolean leaveVehicle() { return isInsideVehicle() && vehicle.removePassenger(this); } - @Override - public Entity getVehicle() { - return vehicle; - } - //////////////////////////////////////////////////////////////////////////// // Custom name @@ -1176,16 +1135,6 @@ public void setGlowing(boolean glowing) { metadata.setBit(MetadataIndex.STATUS, StatusFlags.GLOWING, glowing); } - @Override - public boolean isInvulnerable() { - return invulnerable; - } - - @Override - public void setInvulnerable(boolean invulnerable) { - this.invulnerable = invulnerable; - } - @Override public Entity getPassenger() { if (passengers.size() > 0) { @@ -1298,21 +1247,6 @@ public boolean hasGravity() { return gravity; } - @Override - public void setGravity(boolean gravity) { - this.gravity = gravity; - } - - @Override - public int getPortalCooldown() { - return portalCooldown; - } - - @Override - public void setPortalCooldown(int cooldown) { - this.portalCooldown = cooldown; - } - @Override public Set getScoreboardTags() { // todo: 1.11 @@ -1449,16 +1383,6 @@ public Set getEffectivePermissions() { return null; } - @Override - public boolean isOp() { - return false; - } - - @Override - public void setOp(boolean b) { - - } - public boolean entityInteract(GlowPlayer player, InteractEntityMessage message) { // Override in subclasses to implement behavior return false; @@ -1472,7 +1396,7 @@ public Spigot spigot() { public int hashCode() { int prime = 31; int result = 1; - result = prime * result + id; + result = prime * result + entityId; return result; } @@ -1488,7 +1412,7 @@ public boolean equals(Object obj) { return false; } GlowEntity other = (GlowEntity) obj; - return id == other.id; + return entityId == other.entityId; } public boolean isLeashed() { @@ -1512,7 +1436,7 @@ public Entity getLeashHolder() throws IllegalStateException { } /** - *

Sets the leash on this entity to be held by the supplied entity. + * Sets the leash on this entity to be held by the supplied entity. * *

This method has no effect on EnderDragons, Withers, Players, or Bats. Non-living entities * excluding leashes will not persist as leash holders. diff --git a/src/main/java/net/glowstone/entity/GlowHumanEntity.java b/src/main/java/net/glowstone/entity/GlowHumanEntity.java index 7c7ae84eef..789eaa4d08 100644 --- a/src/main/java/net/glowstone/entity/GlowHumanEntity.java +++ b/src/main/java/net/glowstone/entity/GlowHumanEntity.java @@ -9,6 +9,8 @@ import java.util.Random; import java.util.Set; import java.util.UUID; +import lombok.Getter; +import lombok.Setter; import net.glowstone.EventFactory; import net.glowstone.entity.meta.MetadataIndex; import net.glowstone.entity.meta.profile.PlayerProfile; @@ -56,20 +58,24 @@ public abstract class GlowHumanEntity extends GlowLivingEntity implements HumanE /** * The player profile with name and UUID information. */ + @Getter private final PlayerProfile profile; /** * The inventory of this human. */ + @Getter private final GlowPlayerInventory inventory = new GlowPlayerInventory(this); /** * The ender chest inventory of this human. */ + @Getter private final GlowInventory enderChest = new GlowInventory(this, InventoryType.ENDER_CHEST); /** * Whether this human is sleeping or not. */ + @Getter protected boolean sleeping; /** * This human's PermissibleBase for permissions. @@ -78,29 +84,38 @@ public abstract class GlowHumanEntity extends GlowLivingEntity implements HumanE /** * The item the player has on their cursor. */ + @Getter + @Setter private ItemStack itemOnCursor; /** * How long this human has been sleeping. */ - private int sleepingTicks; + @Getter + private int sleepTicks; /** * Whether this human is considered an op. */ - private boolean isOp; + @Getter + private boolean op; /** * The player's active game mode. */ + @Getter + @Setter private GameMode gameMode; /** * The player's currently open inventory. */ - private InventoryView inventoryView; + @Getter + private InventoryView openInventory; /** * The player's xpSeed. Used for calculation of enchantments. */ + @Getter + @Setter private int xpSeed; /** @@ -121,9 +136,9 @@ public GlowHumanEntity(Location location, PlayerProfile profile) { permissions = new PermissibleBase(this); gameMode = server.getDefaultGameMode(); - inventoryView = new GlowInventoryView(this); - addViewer(inventoryView.getTopInventory()); - addViewer(inventoryView.getBottomInventory()); + openInventory = new GlowInventoryView(this); + addViewer(openInventory.getTopInventory()); + addViewer(openInventory.getBottomInventory()); } //////////////////////////////////////////////////////////////////////////// @@ -139,20 +154,20 @@ public List createSpawnMessage() { double z = location.getZ(); int yaw = Position.getIntYaw(location); int pitch = Position.getIntPitch(location); - result.add(new SpawnPlayerMessage(id, profile.getUniqueId(), x, y, z, yaw, pitch, + result.add(new SpawnPlayerMessage(entityId, profile.getUniqueId(), x, y, z, yaw, pitch, metadata.getEntryList())); // head facing - result.add(new EntityHeadRotationMessage(id, yaw)); + result.add(new EntityHeadRotationMessage(entityId, yaw)); // equipment EntityEquipment equipment = getEquipment(); - result.add(new EntityEquipmentMessage(id, EntityEquipmentMessage.HELD_ITEM, equipment + result.add(new EntityEquipmentMessage(entityId, EntityEquipmentMessage.HELD_ITEM, equipment .getItemInMainHand())); - result.add(new EntityEquipmentMessage(id, EntityEquipmentMessage.OFF_HAND, equipment + result.add(new EntityEquipmentMessage(entityId, EntityEquipmentMessage.OFF_HAND, equipment .getItemInOffHand())); for (int i = 0; i < 4; i++) { - result.add(new EntityEquipmentMessage(id, + result.add(new EntityEquipmentMessage(entityId, EntityEquipmentMessage.BOOTS_SLOT + i, equipment.getArmorContents()[i])); } return result; @@ -162,9 +177,9 @@ public List createSpawnMessage() { public void pulse() { super.pulse(); if (sleeping) { - ++sleepingTicks; + ++sleepTicks; } else { - sleepingTicks = 0; + sleepTicks = 0; } processArmorChanges(); } @@ -197,23 +212,6 @@ private void processArmorChanges() { needsArmorUpdate = true; } - /** - * Get this human entity's PlayerProfile with associated data. - * - * @return The PlayerProfile. - */ - public final PlayerProfile getProfile() { - return profile; - } - - public int getXpSeed() { - return xpSeed; - } - - public void setXpSeed(int xpSeed) { - this.xpSeed = xpSeed; - } - @Override public String getName() { return profile.getName(); @@ -236,26 +234,6 @@ public void setUniqueId(UUID uuid) { } } - @Override - public boolean isSleeping() { - return sleeping; - } - - @Override - public int getSleepTicks() { - return sleepingTicks; - } - - @Override - public GameMode getGameMode() { - return gameMode; - } - - @Override - public void setGameMode(GameMode mode) { - gameMode = mode; - } - @Override public boolean isBlocking() { return false; @@ -268,7 +246,7 @@ public int getExpToLevel() { @Override public EntityEquipment getEquipment() { - return inventory; + return getInventory(); } @Override @@ -337,14 +315,9 @@ public Set getEffectivePermissions() { return permissions.getEffectivePermissions(); } - @Override - public boolean isOp() { - return isOp; - } - @Override public void setOp(boolean value) { - isOp = value; + op = value; recalculatePermissions(); } @@ -361,11 +334,6 @@ public boolean canTakeDamage(DamageCause damageCause) { //////////////////////////////////////////////////////////////////////////// // Inventory - @Override - public GlowPlayerInventory getInventory() { - return inventory; - } - @Override public ItemStack getItemInHand() { return getInventory().getItemInMainHand(); @@ -376,30 +344,10 @@ public void setItemInHand(ItemStack item) { getInventory().setItemInMainHand(item); } - @Override - public ItemStack getItemOnCursor() { - return itemOnCursor; - } - - @Override - public void setItemOnCursor(ItemStack item) { - itemOnCursor = item; - } - - @Override - public Inventory getEnderChest() { - return enderChest; - } - @Override public boolean setWindowProperty(Property prop, int value) { // nb: does not actually send anything - return prop.getType() == inventoryView.getType(); - } - - @Override - public InventoryView getOpenInventory() { - return inventoryView; + return prop.getType() == openInventory.getType(); } @Override @@ -415,11 +363,11 @@ public void openInventory(InventoryView inventory) { this.inventory.getDragTracker().reset(); // stop viewing the old inventory and start viewing the new one - removeViewer(inventoryView.getTopInventory()); - removeViewer(inventoryView.getBottomInventory()); - inventoryView = inventory; - addViewer(inventoryView.getTopInventory()); - addViewer(inventoryView.getBottomInventory()); + removeViewer(openInventory.getTopInventory()); + removeViewer(openInventory.getBottomInventory()); + openInventory = inventory; + addViewer(openInventory.getTopInventory()); + addViewer(openInventory.getBottomInventory()); } @Override @@ -446,7 +394,7 @@ public InventoryView openEnchanting(Location location, boolean force) { @Override public void closeInventory() { - EventFactory.callEvent(new InventoryCloseEvent(inventoryView)); + EventFactory.callEvent(new InventoryCloseEvent(openInventory)); if (getGameMode() != GameMode.CREATIVE) { if (!InventoryUtil.isEmpty(getItemOnCursor())) { drop(getItemOnCursor()); diff --git a/src/main/java/net/glowstone/entity/GlowLightningStrike.java b/src/main/java/net/glowstone/entity/GlowLightningStrike.java index 1889a2f3d2..ea5223a1a9 100644 --- a/src/main/java/net/glowstone/entity/GlowLightningStrike.java +++ b/src/main/java/net/glowstone/entity/GlowLightningStrike.java @@ -125,7 +125,7 @@ public List createSpawnMessage() { double x = location.getX(); double y = location.getY(); double z = location.getZ(); - return Collections.singletonList(new SpawnLightningStrikeMessage(id, x, y, z)); + return Collections.singletonList(new SpawnLightningStrikeMessage(entityId, x, y, z)); } @Override @@ -161,6 +161,7 @@ private void setBlockOnFire(GlowBlock block) { } } + @Override public LightningStrike.Spigot spigot() { return spigot; } diff --git a/src/main/java/net/glowstone/entity/GlowLivingEntity.java b/src/main/java/net/glowstone/entity/GlowLivingEntity.java index c63c7ca3b7..46b8125291 100644 --- a/src/main/java/net/glowstone/entity/GlowLivingEntity.java +++ b/src/main/java/net/glowstone/entity/GlowLivingEntity.java @@ -15,6 +15,7 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; import lombok.Getter; +import lombok.Setter; import net.glowstone.EventFactory; import net.glowstone.block.GlowBlock; import net.glowstone.block.ItemTable; @@ -26,6 +27,7 @@ import net.glowstone.entity.meta.MetadataIndex; import net.glowstone.entity.objects.GlowExperienceOrb; import net.glowstone.entity.objects.GlowLeashHitch; +import net.glowstone.entity.passive.GlowWolf; import net.glowstone.inventory.EquipmentMonitor; import net.glowstone.net.GlowSession; import net.glowstone.net.message.play.entity.AnimateEntityMessage; @@ -85,9 +87,37 @@ */ public abstract class GlowLivingEntity extends GlowEntity implements LivingEntity { + /** + * The player that killed this entity, or null if not killed by a player. + */ + @Getter + @Setter + private Player killer; + + /** + * The tick that the entity got hit by a player. + * The default value was set to -101 rather than 0. + */ + @Getter + @Setter + private int playerDamageTick = -101; + + /** + * Whether entities can collide with this entity. + */ + @Getter + @Setter + private boolean collidable = true; + /** + * The number of arrows stuck inside this entity. + */ + @Getter + @Setter + private int arrowsStuck = 0; /** * The entity's AI task manager. */ + @Getter protected final TaskManager taskManager; /** * Potion effects on the entity. @@ -96,10 +126,12 @@ public abstract class GlowLivingEntity extends GlowEntity implements LivingEntit /** * The LivingEntity's AttributeManager. */ + @Getter private final AttributeManager attributeManager; /** * The entity's health. */ + @Getter protected double health; /** * The entity's max health. @@ -116,39 +148,53 @@ public abstract class GlowLivingEntity extends GlowEntity implements LivingEntit * The y value is not used. X is used for forward movement and z is used for sideways movement. * These values are relative to the entity's current yaw.

*/ + @Getter + @Setter protected Vector movement = new Vector(); /** * The speed multiplier of the entity. */ + @Getter + @Setter protected double speed = 1; /** * The magnitude of the last damage the entity took. */ + @Getter + @Setter private double lastDamage; /** * How long the entity has until it runs out of air. */ - private int airTicks = 300; + @Getter + private int remainingAir = 300; /** * The maximum amount of air the entity can hold. */ + @Getter private int maximumAir = 300; /** * The number of ticks remaining in the invincibility period. */ + @Getter + @Setter private int noDamageTicks; /** * The default length of the invincibility period. */ - private int maxNoDamageTicks = 10; + @Getter + @Setter + private int maximumNoDamageTicks = 10; /** * Whether the entity should be removed if it is too distant from players. */ - private boolean removeDistance; + @Setter + private boolean removeWhenFarAway; /** * Whether the (non-Player) entity can pick up armor and tools. */ - private boolean pickupItems; + @Setter + private boolean canPickupItems; /** * Monitor for the equipment of this entity. */ @@ -158,6 +204,8 @@ public abstract class GlowLivingEntity extends GlowEntity implements LivingEntit * Whether the entity can automatically glide when falling with an Elytra equipped. This value * is ignored for players. */ + @Getter + @Setter private boolean fallFlying; /** * Ticks until the next ambient sound roll. @@ -166,10 +214,13 @@ public abstract class GlowLivingEntity extends GlowEntity implements LivingEntit /** * The last entity which damaged this living entity. */ + @Getter + @Setter private Entity lastDamager; /** * The head rotation of the living entity, if applicable. */ + @Getter private float headYaw; /** * Whether the headYaw value should be updated. @@ -178,7 +229,8 @@ public abstract class GlowLivingEntity extends GlowEntity implements LivingEntit /** * The entity's current AI state. */ - private MobState aiState = MobState.NO_AI; + @Getter + private MobState state = MobState.NO_AI; /** * If this entity has swam in lava (for fire application). */ @@ -231,14 +283,14 @@ public void pulse() { // breathing if (mat == Material.WATER || mat == Material.STATIONARY_WATER) { if (canTakeDamage(DamageCause.DROWNING)) { - --airTicks; - if (airTicks <= -20) { - airTicks = 0; + --remainingAir; + if (remainingAir <= -20) { + remainingAir = 0; damage(1, DamageCause.DROWNING); } } } else { - airTicks = maximumAir; + remainingAir = maximumAir; } if (isTouchingMaterial(Material.CACTUS)) { @@ -361,22 +413,6 @@ protected Vector getVelocityFromMovement() { return movement; } - public Vector getMovement() { - return movement.clone(); - } - - public void setMovement(Vector movement) { - this.movement = movement; - } - - public double getSpeed() { - return speed; - } - - public void setSpeed(double speed) { - this.speed = speed; - } - protected void jump() { if (location.getBlock().isLiquid()) { // jump out more when you breach the surface of the liquid @@ -403,20 +439,16 @@ public List createUpdateMessage(GlowSession session) { List messages = super.createUpdateMessage(session); messages.addAll(equipmentMonitor.getChanges().stream() - .map(change -> new EntityEquipmentMessage(id, change.slot, change.item)) + .map(change -> new EntityEquipmentMessage(entityId, change.slot, change.item)) .collect(Collectors.toList())); if (headRotated) { - messages.add(new EntityHeadRotationMessage(id, Position.getIntHeadYaw(headYaw))); + messages.add(new EntityHeadRotationMessage(entityId, Position.getIntHeadYaw(headYaw))); } attributeManager.applyMessages(messages); return messages; } - public AttributeManager getAttributeManager() { - return attributeManager; - } - //////////////////////////////////////////////////////////////////////////// // Properties @@ -435,25 +467,11 @@ public Location getEyeLocation() { return getLocation().add(0, getEyeHeight(), 0); } - @Override - public Player getKiller() { - return null; - } - - @Override - public void setKiller(Player player) { - throw new UnsupportedOperationException("Not implemented yet."); - } - @Override public boolean hasLineOfSight(Entity other) { return false; } - public float getHeadYaw() { - return headYaw; - } - public void setHeadYaw(float headYaw) { this.headYaw = headYaw; this.headRotated = true; @@ -467,39 +485,9 @@ public EntityEquipment getEquipment() { return null; } - @Override - public int getNoDamageTicks() { - return noDamageTicks; - } - - @Override - public void setNoDamageTicks(int ticks) { - noDamageTicks = ticks; - } - - @Override - public int getMaximumNoDamageTicks() { - return maxNoDamageTicks; - } - - @Override - public void setMaximumNoDamageTicks(int ticks) { - maxNoDamageTicks = ticks; - } - - @Override - public int getRemainingAir() { - return airTicks; - } - @Override public void setRemainingAir(int ticks) { - airTicks = Math.min(ticks, maximumAir); - } - - @Override - public int getMaximumAir() { - return maximumAir; + remainingAir = Math.min(ticks, maximumAir); } @Override @@ -509,22 +497,12 @@ public void setMaximumAir(int ticks) { @Override public boolean getRemoveWhenFarAway() { - return removeDistance; - } - - @Override - public void setRemoveWhenFarAway(boolean remove) { - removeDistance = remove; + return removeWhenFarAway; } @Override public boolean getCanPickupItems() { - return pickupItems; - } - - @Override - public void setCanPickupItems(boolean pickup) { - pickupItems = pickup; + return canPickupItems; } /** @@ -702,11 +680,6 @@ public T launchProjectile(Class projectile, return entity; } - @Override - public double getHealth() { - return health; - } - @Override public void setHealth(double health) { if (health < 0) { @@ -767,7 +740,8 @@ public void setHealth(double health) { if (world.getGameRuleMap().getBoolean("doMobLoot")) { LootData data = LootingManager.generate(this); deathEvent.getDrops().addAll(data.getItems()); - if (data.getExperience() > 0) { + // Only drop experience when hit by a player within 5 seconds (100 game ticks) + if (ticksLived - playerDamageTick <= 100 && data.getExperience() > 0) { // split experience Integer[] values = ExperienceSplitter.cut(data.getExperience()); for (Integer exp : values) { @@ -780,6 +754,10 @@ public void setHealth(double health) { GlowExperienceOrb orb = (GlowExperienceOrb) world .spawnEntity(xpLocation, EntityType.EXPERIENCE_ORB); orb.setExperience(exp); + orb.setSourceEntityId(this.getUniqueId()); + if (getLastDamager() != null) { + orb.setTriggerEntityId(getLastDamager().getUniqueId()); + } } } } @@ -797,7 +775,7 @@ public void damage(double amount, Entity source, DamageCause cause) { if (noDamageTicks > 0 || health <= 0 || !canTakeDamage(cause) || isInvulnerable()) { return; } else { - noDamageTicks = maxNoDamageTicks; + noDamageTicks = maximumNoDamageTicks; } // fire resistance @@ -839,6 +817,14 @@ public void damage(double amount, Entity source, DamageCause cause) { // apply damage amount = event.getFinalDamage(); lastDamage = amount; + + if (isPlayerHit(source)) { + playerDamageTick = ticksLived; + if (health - amount <= 0) { + killer = determinePlayer(source); + } + } + setHealth(health - amount); playEffect(EntityEffect.HURT); @@ -863,6 +849,62 @@ public void damage(double amount, Entity source, DamageCause cause) { setLastDamager(source); } + /** + * Checks if the source of damage was caused by a player. + * + * @param source The source of damage + * @return true if the source of damage was caused by a player, false otherwise. + */ + private boolean isPlayerHit(Entity source) { + // If directly damaged by a player + if (source instanceof GlowPlayer) { + return true; + } + + // If damaged by a TNT ignited by a player + if (source instanceof GlowTntPrimed) { + GlowPlayer player = (GlowPlayer)((GlowTntPrimed) source).getSource(); + return + player != null + && (player.getGameMode() == GameMode.SURVIVAL + || player.getGameMode() == GameMode.ADVENTURE); + } + + // If damaged by a tamed wolf + if (source instanceof GlowWolf) { + return ((GlowWolf) source).isTamed(); + } + + // All other cases + return false; + } + + /** + * Determines the player who did the damage from source of damage. + * + * @param source The incoming source of damage + * @return Player object if the source of damage was caused by a player, null otherwise. + */ + private Player determinePlayer(Entity source) { + // If been killed by an ignited tnt + if (source instanceof GlowTntPrimed) { + return (Player)((GlowTntPrimed) source).getSource(); + } + + // If been killed by a player + if (source instanceof GlowPlayer) { + return (Player) source; + } + + // If been killed by a tamed wolf + if (source instanceof GlowWolf) { + return (Player)((GlowWolf) source).getOwner(); + } + + // All other cases + return null; + } + @Override public double getMaxHealth() { return attributeManager.getPropertyValue(Key.KEY_MAX_HEALTH); @@ -878,24 +920,6 @@ public void resetMaxHealth() { setMaxHealth(maxHealth); } - @Override - public double getLastDamage() { - return lastDamage; - } - - @Override - public void setLastDamage(double damage) { - lastDamage = damage; - } - - public Entity getLastDamager() { - return lastDamager; - } - - public void setLastDamager(Entity lastDamager) { - this.lastDamager = lastDamager; - } - //////////////////////////////////////////////////////////////////////////// // Potion effects @@ -998,14 +1022,6 @@ public void setOnGround(boolean onGround) { super.setOnGround(onGround); } - public boolean isFallFlying() { - return fallFlying; - } - - public void setFallFlying(boolean fallFlying) { - this.fallFlying = fallFlying; - } - //////////////////////////////////////////////////////////////////////////// // Leashes @@ -1023,18 +1039,14 @@ public void setGliding(boolean gliding) { metadata.setBit(MetadataIndex.STATUS, MetadataIndex.StatusFlags.GLIDING, gliding); } - public MobState getState() { - return aiState; - } - /** * Sets the AI state. * * @param state the new AI state */ public void setState(MobState state) { - if (aiState != state) { - aiState = state; + if (this.state != state) { + this.state = state; getTaskManager().updateState(); } } @@ -1042,7 +1054,7 @@ public void setState(MobState state) { @Override public void setAI(boolean ai) { if (ai) { - if (aiState == MobState.NO_AI) { + if (state == MobState.NO_AI) { setState(MobState.IDLE); } } else { @@ -1052,29 +1064,7 @@ public void setAI(boolean ai) { @Override public boolean hasAI() { - return aiState != MobState.NO_AI; - } - - @Override - public boolean isCollidable() { - // todo: 1.11 - return true; - } - - @Override - public void setCollidable(boolean collidable) { - // todo: 1.11 - } - - @Override - public int getArrowsStuck() { - // todo: 1.11 - return 0; - } - - @Override - public void setArrowsStuck(int arrowsStuck) { - // todo: 1.11 + return state != MobState.NO_AI; } @Override @@ -1091,10 +1081,6 @@ public AttributeInstance getAttribute(Attribute attribute) { return null; } - public TaskManager getTaskManager() { - return taskManager; - } - @Override public boolean entityInteract(GlowPlayer player, InteractEntityMessage message) { super.entityInteract(player, message); diff --git a/src/main/java/net/glowstone/entity/GlowPlayer.java b/src/main/java/net/glowstone/entity/GlowPlayer.java index 6f374a9f58..413e582682 100644 --- a/src/main/java/net/glowstone/entity/GlowPlayer.java +++ b/src/main/java/net/glowstone/entity/GlowPlayer.java @@ -23,9 +23,11 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Queue; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ThreadLocalRandom; import java.util.logging.Level; import java.util.stream.Collectors; @@ -201,8 +203,11 @@ public class GlowPlayer extends GlowHumanEntity implements Player { public static final int SELF_ID = 0; /** - * This player's session. + * The network session attached to this player. + * + * @return The GlowSession of the player. */ + @Getter private final GlowSession session; /** @@ -223,7 +228,7 @@ public class GlowPlayer extends GlowHumanEntity implements Player { /** * A queue of BlockChangeMessages to be sent. */ - private final List blockChanges = new LinkedList<>(); + private final Queue blockChanges = new ConcurrentLinkedDeque<>(); /** * A queue of messages that should be sent after block changes are processed. @@ -233,7 +238,7 @@ public class GlowPlayer extends GlowHumanEntity implements Player { private final List afterBlockChanges = new LinkedList<>(); /** - * The set of plugin channels this player is listening on + * The set of plugin channels this player is listening on. */ private final Set listeningChannels = new HashSet<>(); @@ -250,19 +255,25 @@ public class GlowPlayer extends GlowHumanEntity implements Player { /** * The time the player first played, or 0 if unknown. */ + @Getter private final long firstPlayed; /** * The time the player last played, or 0 if unknown. */ + @Getter private final long lastPlayed; @Getter private final PlayerRecipeMonitor recipeMonitor; public Location teleportedTo = null; + @Setter public boolean affectsSpawning = true; /** - * The time the player joined. + * The time the player joined, in milliseconds, to be saved as last played time. + * + * @return The player's join time. */ + @Getter private long joinTime; /** * The settings sent by the client. @@ -281,40 +292,49 @@ public class GlowPlayer extends GlowHumanEntity implements Player { */ private String displayName; /** - * The name a player has in the player list + * The name a player has in the player list. */ private String playerListName; /** * Cumulative amount of experience points the player has collected. */ + @Getter private int totalExperience; /** * The current level (or skill point amount) of the player. */ + @Getter private int level; /** * The progress made to the next level, from 0 to 1. */ - private float experience; + @Getter + private float exp; /** - * The human entity's current food level + * The human entity's current food level. */ - private int food = 20; + @Getter + private int foodLevel = 20; /** * The player's current exhaustion level. */ + @Getter + @Setter private float exhaustion; /** * The player's current saturation level. */ + @Getter private float saturation; /** * Whether to perform special scaling of the player's health. */ + @Getter private boolean healthScaled; /** * The scale at which to display the player's health. */ + @Getter private double healthScale = 20; /** * If this player has seen the end credits. @@ -333,7 +353,8 @@ public class GlowPlayer extends GlowHumanEntity implements Player { /** * Whether the time offset is relative. */ - private boolean timeRelative = true; + @Getter + private boolean playerTimeRelative = true; /** * The player-specific weather, or null for normal weather. */ @@ -341,29 +362,35 @@ public class GlowPlayer extends GlowHumanEntity implements Player { /** * The player's compass target. */ + @Getter private Location compassTarget; /** * Whether this player's sleeping state is ignored when changing time. */ private boolean sleepingIgnored; /** - * The bed in which the player currently lies + * The bed in which the player currently lies. */ private GlowBlock bed; /** - * The bed spawn location of a player + * The bed spawn location of a player. */ private Location bedSpawn; /** * Whether to use the bed spawn even if there is no bed block. + * + * @return Whether the player is forced to spawn at their bed. */ + @Getter private boolean bedSpawnForced; private final Player.Spigot spigot = new Player.Spigot() { @Override - public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) { + public void playEffect(Location location, Effect effect, int id, int data, float offsetX, + float offsetY, float offsetZ, float speed, int particleCount, int radius) { if (effect.getType() == Type.PARTICLE) { MaterialData material = new MaterialData(id, (byte) data); - showParticle(location, effect, material, offsetX, offsetY, offsetZ, speed, particleCount); + showParticle(location, effect, material, offsetX, offsetY, offsetZ, speed, + particleCount); } else { GlowPlayer.this.playEffect(location, effect, data); } @@ -391,7 +418,8 @@ public void setCollidesWithEntities(boolean collides) { @Override public Set getHiddenPlayers() { - return hiddenEntities.stream().map(Bukkit::getPlayer).filter(Objects::nonNull).collect(Collectors.toSet()); + return hiddenEntities.stream().map(Bukkit::getPlayer).filter(Objects::nonNull) + .collect(Collectors.toSet()); } @Override @@ -430,26 +458,30 @@ public String getLocale() { /** * Whether the player is currently flying. */ + @Getter private boolean flying; /** * The player's base flight speed. */ + @Getter private float flySpeed = 0.1f; /** * The player's base walking speed. */ + @Getter private float walkSpeed = 0.2f; /** * The scoreboard the player is currently subscribed to. */ private GlowScoreboard scoreboard; /** - * The player's current title, if any + * The player's current title, if any. */ private Title.Builder currentTitle = new Title.Builder(); /** * The one block the player is currently digging. */ + @Getter private GlowBlock digging; /** * The number of ticks elapsed since the player started digging. @@ -575,6 +607,12 @@ private static Location findSafeSpawnLocation(Location spawn) { return new Location(world, blockX + 0.5, y, blockZ + 0.5); } + /** + * Loads the player's state and sends the messages that are necessary on login. + * + * @param session the player's session + * @param reader the source of the player's saved state + */ public void join(GlowSession session, PlayerReader reader) { // send join game // in future, handle hardcore, difficulty, and level type @@ -583,7 +621,9 @@ public void join(GlowSession session, PlayerReader reader) { if (server.isHardcore()) { gameMode |= 0x8; } - session.send(new JoinGameMessage(SELF_ID, gameMode, world.getEnvironment().getId(), world.getDifficulty().getValue(), session.getServer().getMaxPlayers(), type, world.getGameRuleMap().getBoolean("reducedDebugInfo"))); + session.send(new JoinGameMessage(SELF_ID, gameMode, world.getEnvironment().getId(), world + .getDifficulty().getValue(), session.getServer().getMaxPlayers(), type, world + .getGameRuleMap().getBoolean("reducedDebugInfo"))); setGameModeDefaults(); // send server brand and supported plugin channels @@ -671,29 +711,12 @@ public void damage(double amount, DamageCause cause) { @Override public boolean canTakeDamage(DamageCause damageCause) { - return damageCause == DamageCause.FALL ? !getAllowFlight() && super.canTakeDamage(damageCause) : super.canTakeDamage(damageCause); - } - - /** - * Get the network session attached to this player. - * - * @return The GlowSession of the player. - */ - public GlowSession getSession() { - return session; - } - - /** - * Get the join time in milliseconds, to be saved as last played time. - * - * @return The player's join time. - */ - public long getJoinTime() { - return joinTime; + return damageCause == DamageCause.FALL ? !getAllowFlight() && super + .canTakeDamage(damageCause) : super.canTakeDamage(damageCause); } /** - * Kicks this player + * Kicks this player. */ @Override public void remove() { @@ -714,6 +737,11 @@ public void remove() { super.remove(); } + /** + * Handle player disconnection. + * + * @param async if true, the player's data is saved asynchronously + */ public void remove(boolean async) { knownChunks.clear(); chunkLock.clear(); @@ -765,18 +793,21 @@ public void pulse() { saturation = Math.max(saturation - 1f, 0f); sendHealth(); } else if (world.getDifficulty() != Difficulty.PEACEFUL) { - FoodLevelChangeEvent event = EventFactory.callEvent(new FoodLevelChangeEvent(this, Math.max(food - 1, 0))); + FoodLevelChangeEvent event = EventFactory + .callEvent(new FoodLevelChangeEvent(this, Math.max(foodLevel - 1, 0))); if (!event.isCancelled()) { - food = event.getFoodLevel(); + foodLevel = event.getFoodLevel(); } sendHealth(); } } if (getHealth() < getMaxHealth() && !isDead()) { - if (food >= 18 && ticksLived % 80 == 0 || world.getDifficulty() == Difficulty.PEACEFUL) { + if (foodLevel >= 18 && ticksLived % 80 == 0 + || world.getDifficulty() == Difficulty.PEACEFUL) { - EntityRegainHealthEvent event1 = new EntityRegainHealthEvent(this, 1f, RegainReason.SATIATED); + EntityRegainHealthEvent event1 + = new EntityRegainHealthEvent(this, 1f, RegainReason.SATIATED); EventFactory.callEvent(event1); if (!event1.isCancelled()) { setHealth(getHealth() + 1); @@ -787,7 +818,7 @@ public void pulse() { } } - if (food == 0 && getHealth() > 1 && ticksLived % 80 == 0) { + if (foodLevel == 0 && getHealth() > 1 && ticksLived % 80 == 0) { damage(1, DamageCause.STARVATION); } @@ -836,28 +867,31 @@ public void pulse() { } // add entities knownChunks.forEach(key -> - world.getChunkAt(key.getX(), key.getZ()).getRawEntities().stream() - .filter(entity -> this != entity - && isWithinDistance(entity) - && !entity.isDead() - && !knownEntities.contains(entity) - && !hiddenEntities.contains(entity.getUniqueId())) - .forEach((entity) -> Bukkit.getScheduler().runTaskAsynchronously(null, () -> { - worldLock.readLock().lock(); - try { - knownEntities.add(entity); - } finally { - worldLock.readLock().unlock(); - } - entity.createSpawnMessage().forEach(session::send); - entity.createAfterSpawnMessage(session).forEach(session::send); - }))); + world.getChunkAt(key.getX(), key.getZ()).getRawEntities().stream() + .filter(entity -> this != entity + && isWithinDistance(entity) + && !entity.isDead() + && !knownEntities.contains(entity) + && !hiddenEntities.contains(entity.getUniqueId())) + .forEach((entity) -> Bukkit.getScheduler() + .runTaskAsynchronously(null, () -> { + worldLock.readLock().lock(); + try { + knownEntities.add(entity); + } finally { + worldLock.readLock().unlock(); + } + entity.createSpawnMessage().forEach(session::send); + entity.createAfterSpawnMessage(session) + .forEach(session::send); + }))); } finally { worldLock.writeLock().unlock(); } if (passengerChanged) { - session.send(new SetPassengerMessage(SELF_ID, getPassengers().stream().mapToInt(Entity::getEntityId).toArray())); + session.send(new SetPassengerMessage(SELF_ID, getPassengers().stream() + .mapToInt(Entity::getEntityId).toArray())); } getAttributeManager().sendMessages(session); } @@ -878,37 +912,37 @@ protected void jump() { * Process and send pending BlockChangeMessages. */ private void processBlockChanges() { - synchronized (blockChanges) { - List messages = new ArrayList<>(blockChanges); - blockChanges.clear(); - // separate messages by chunk - // inner map is used to only send one entry for same coordinates - Map> chunks = new HashMap<>(); - for (BlockChangeMessage message : messages) { - if (message != null) { - Key key = GlowChunk.Key.of(message.getX() >> 4, message.getZ() >> 4); - if (canSeeChunk(key)) { - Map map = chunks.computeIfAbsent(key, k -> new HashMap<>()); - map.put(new BlockVector(message.getX(), message.getY(), message.getZ()), message); - } - } + // separate messages by chunk + // inner map is used to only send one entry for same coordinates + Map> chunks = new HashMap<>(); + while (true) { + BlockChangeMessage message = blockChanges.poll(); + if (message == null) { + break; } - // send away - for (Map.Entry> entry : chunks.entrySet()) { - Key key = entry.getKey(); - List value = new ArrayList<>(entry.getValue().values()); - - if (value.size() == 1) { - session.send(value.get(0)); - } else if (value.size() > 1) { - session.send(new MultiBlockChangeMessage(key.getX(), key.getZ(), value)); - } + Key key = GlowChunk.Key.of(message.getX() >> 4, message.getZ() >> 4); + if (canSeeChunk(key)) { + Map map = chunks + .computeIfAbsent(key, k -> new HashMap<>()); + map.put(new BlockVector(message.getX(), message.getY(), message + .getZ()), message); + } + } + // send away + for (Map.Entry> entry : chunks.entrySet()) { + Key key = entry.getKey(); + List value = new ArrayList<>(entry.getValue().values()); + + if (value.size() == 1) { + session.send(value.get(0)); + } else if (value.size() > 1) { + session.send(new MultiBlockChangeMessage(key.getX(), key.getZ(), value)); } - // now send post-block-change messages - List postMessages = new ArrayList<>(afterBlockChanges); - afterBlockChanges.clear(); - postMessages.forEach(session::send); } + // now send post-block-change messages + List postMessages = new ArrayList<>(afterBlockChanges); + afterBlockChanges.clear(); + postMessages.forEach(session::send); } /** @@ -929,7 +963,8 @@ private void streamBlocks() { newChunks.add(GlowChunk.Key.of(x, z)); } } - } else if (Math.abs(centralX - prevCentralX) > radius || Math.abs(centralZ - prevCentralZ) > radius) { + } else if (Math.abs(centralX - prevCentralX) > radius + || Math.abs(centralZ - prevCentralZ) > radius) { knownChunks.clear(); for (int x = centralX - radius; x <= centralX + radius; x++) { for (int z = centralZ - radius; z <= centralZ + radius; z++) { @@ -981,12 +1016,12 @@ private void streamBlocks() { boolean skylight = world.getEnvironment() == Environment.NORMAL; newChunks.stream().map(key -> world.getChunkAt(key.getX(), key.getZ()).toMessage(skylight)) - .forEach(session::send); + .forEach(session::send); // send visible block entity data newChunks.stream().flatMap(key -> world.getChunkAt(key.getX(), - key.getZ()).getRawBlockEntities().stream()) - .forEach(entity -> entity.update(this)); + key.getZ()).getRawBlockEntities().stream()) + .forEach(entity -> entity.update(this)); // and remove old chunks if (previousChunks != null) { @@ -1028,7 +1063,8 @@ private void spawnAt(Location location) { // spawn into world String type = world.getWorldType().getName().toLowerCase(); - session.send(new RespawnMessage(world.getEnvironment().getId(), world.getDifficulty().getValue(), getGameMode().getValue(), type)); + session.send(new RespawnMessage(world.getEnvironment().getId(), world.getDifficulty() + .getValue(), getGameMode().getValue(), type)); setRawLocation(location, false); // take us to spawn position session.send(new PositionRotationMessage(location)); @@ -1103,10 +1139,13 @@ public void respawn() { // fire event and perform spawn PlayerRespawnEvent event = new PlayerRespawnEvent(this, dest, spawnAtBed); EventFactory.callEvent(event); - if (event.getRespawnLocation().getWorld().equals(getWorld()) && !knownEntities.isEmpty()) { - // we need to manually reset all known entities if the player respawns in the same world + if (event.getRespawnLocation().getWorld().equals(getWorld()) && !knownEntities + .isEmpty()) { + // we need to manually reset all known entities if the player respawns in the + // same world List entityIds = new ArrayList<>(knownEntities.size()); - entityIds.addAll(knownEntities.stream().map(GlowEntity::getEntityId).collect(Collectors.toList())); + entityIds.addAll(knownEntities.stream().map(GlowEntity::getEntityId) + .collect(Collectors.toList())); session.send(new DestroyEntitiesMessage(entityIds)); knownEntities.clear(); } @@ -1170,7 +1209,8 @@ public void openSignEditor(Location loc) { } /** - * Check that the specified location matches that of the last opened sign editor, and if so, clears the last opened sign editor. + * Check that the specified location matches that of the last opened sign editor, and if so, + * clears the last opened sign editor. * * @param loc The location to check * @return Whether the location matched. @@ -1203,7 +1243,8 @@ public Entry getUserListEntry() { * @param updateMessage The message to send. */ private void updateUserListEntries(UserListItemMessage updateMessage) { - server.getRawOnlinePlayers().stream().filter(player -> player.canSee(this)).forEach(player -> player.getSession().send(updateMessage)); + server.getRawOnlinePlayers().stream().filter(player -> player.canSee(this)) + .forEach(player -> player.getSession().send(updateMessage)); } @Override @@ -1222,7 +1263,8 @@ public void setVelocity(Vector velocity) { * @param settings The settings to set. */ public void setSettings(ClientSettings settings) { - forceStream = settings.getViewDistance() != this.settings.getViewDistance() && settings.getViewDistance() + 1 <= server.getViewDistance(); + forceStream = settings.getViewDistance() != this.settings.getViewDistance() + && settings.getViewDistance() + 1 <= server.getViewDistance(); this.settings = settings; metadata.set(MetadataIndex.PLAYER_SKIN_PARTS, settings.getSkinFlags()); metadata.set(MetadataIndex.PLAYER_MAIN_HAND, settings.getMainHand()); @@ -1247,13 +1289,13 @@ public InetSocketAddress getAddress() { @Override public int getProtocolVersion() { - return GlowServer.PROTOCOL_VERSION; + return session.getVersion(); } @Nullable @Override public InetSocketAddress getVirtualHost() { - return session.getAddress(); + return session.getVirtualHost(); } @Override @@ -1296,19 +1338,9 @@ public boolean hasPlayedBefore() { return hasPlayedBefore; } - @Override - public long getFirstPlayed() { - return firstPlayed; - } - - @Override - public long getLastPlayed() { - return lastPlayed; - } - @Override public boolean isOp() { - return getServer().getOpsList().containsUUID(getUniqueId()); + return getServer().getOpsList().containsUuid(getUniqueId()); } @Override @@ -1367,26 +1399,12 @@ public void setPlayerListName(String name) { updateUserListEntries(UserListItemMessage.displayNameOne(getUniqueId(), displayName)); } - @Override - public Location getCompassTarget() { - return compassTarget; - } - @Override public void setCompassTarget(Location loc) { compassTarget = loc; session.send(new SpawnPositionMessage(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); } - /** - * Returns whether the player spawns at their bed even if there is no bed block. - * - * @return Whether the player is forced to spawn at their bed. - */ - public boolean isBedSpawnForced() { - return bedSpawnForced; - } - @Override public Location getBedSpawnLocation() { if (bedSpawn == null) { @@ -1448,6 +1466,7 @@ public void setGameMode(GameMode mode) { } super.setGameMode(mode); + super.setFallDistance(0); updateUserListEntries(UserListItemMessage.gameModeOne(getUniqueId(), mode.getValue())); session.send(new StateChangeMessage(Reason.GAMEMODE, mode.getValue())); } @@ -1528,33 +1547,18 @@ public void setAllowFlight(boolean flight) { //////////////////////////////////////////////////////////////////////////// // Experience and levelling - @Override - public boolean isFlying() { - return flying; - } - @Override public void setFlying(boolean value) { flying = value && canFly; sendAbilities(); } - @Override - public float getFlySpeed() { - return flySpeed; - } - @Override public void setFlySpeed(float value) throws IllegalArgumentException { flySpeed = value; sendAbilities(); } - @Override - public float getWalkSpeed() { - return walkSpeed; - } - @Override public void setWalkSpeed(float value) throws IllegalArgumentException { walkSpeed = value; @@ -1568,22 +1572,12 @@ private void sendAbilities() { session.send(new PlayerAbilitiesMessage(flags, flySpeed / 2f, walkSpeed / 2f)); } - @Override - public int getLevel() { - return level; - } - @Override public void setLevel(int level) { this.level = Math.max(level, 0); sendExperience(); } - @Override - public int getTotalExperience() { - return totalExperience; - } - @Override public void setTotalExperience(int exp) { totalExperience = Math.max(exp, 0); @@ -1597,9 +1591,9 @@ public void giveExp(int xp) { // gradually award levels based on xp points float value = 1.0f / getExpToLevel(); for (int i = 0; i < xp; ++i) { - experience += value; - if (experience >= 1) { - experience -= 1; + exp += value; + if (exp >= 1) { + exp -= 1; value = 1.0f / getExpToLevel(++level); } } @@ -1611,14 +1605,9 @@ public void giveExpLevels(int amount) { setLevel(getLevel() + amount); } - @Override - public float getExp() { - return experience; - } - @Override public void setExp(float percentToLevel) { - experience = Math.min(Math.max(percentToLevel, 0), 1); + exp = Math.min(Math.max(percentToLevel, 0), 1); sendExperience(); } @@ -1696,22 +1685,12 @@ public void setMaxHealth(double health) { sendHealth(); } - @Override - public boolean isHealthScaled() { - return healthScaled; - } - @Override public void setHealthScaled(boolean scale) { healthScaled = scale; sendHealth(); } - @Override - public double getHealthScale() { - return healthScale; - } - @Override public void setHealthScale(double scale) throws IllegalArgumentException { healthScaled = true; @@ -1730,20 +1709,21 @@ public void setSpectatorTarget(Entity entity) { spectating = entity; } + /** + * Updates the hunger bar and hunger saturation. + * + * @param food the amount of food (in half-icons on the hunger bar) + * @param saturation the amount of food saturation (in half-icons of food it will save) + */ public void setFoodLevelAndSaturation(int food, float saturation) { - this.food = Math.max(Math.min(food, 20), 0); - this.saturation = Math.min(this.saturation + food * saturation * 2.0F, this.food); + this.foodLevel = Math.max(Math.min(food, 20), 0); + this.saturation = Math.min(this.saturation + food * saturation * 2.0F, this.foodLevel); sendHealth(); } - @Override - public int getFoodLevel() { - return food; - } - @Override public void setFoodLevel(int food) { - this.food = Math.min(food, 20); + this.foodLevel = Math.min(food, 20); sendHealth(); } @@ -1751,6 +1731,11 @@ private boolean shouldCalculateExhaustion() { return getGameMode() == GameMode.SURVIVAL | getGameMode() == GameMode.ADVENTURE; } + /** + * Increases the exhaustion counter, but applies the maximum. + * + * @param exhaustion the amount of exhaustion to add + */ // todo: effects // todo: swim // todo: jump @@ -1765,36 +1750,25 @@ public void addExhaustion(float exhaustion) { //////////////////////////////////////////////////////////////////////////// // Actions + /** + * Add the exhaustion for sprinting from the given location to the current location, if this + * player is sprinting. + * + * @param move the previous location + */ public void addMoveExhaustion(Location move) { - if (shouldCalculateExhaustion() && !teleported) { + if (shouldCalculateExhaustion() && !teleported && isSprinting()) { double distanceSquared = location.distanceSquared(move); if (distanceSquared > 0) { // update packet and rotation double distance = Math.sqrt(distanceSquared); - if (isSprinting()) { - addExhaustion((float) (0.1f * distance)); - } + addExhaustion((float) (0.1f * distance)); } } } - @Override - public float getExhaustion() { - return exhaustion; - } - - @Override - public void setExhaustion(float value) { - exhaustion = value; - } - - @Override - public float getSaturation() { - return saturation; - } - @Override public void setSaturation(float value) { - saturation = Math.min(value, food); + saturation = Math.min(value, foodLevel); sendHealth(); } @@ -1820,7 +1794,8 @@ public boolean teleport(Location location, TeleportCause cause) { checkNotNull(location.getWorld(), "location's world cannot be null"); checkNotNull(cause, "cause cannot be null"); if (this.location != null && this.location.getWorld() != null) { - PlayerTeleportEvent event = new PlayerTeleportEvent(this, this.location, location, cause); + PlayerTeleportEvent event + = new PlayerTeleportEvent(this, this.location, location, cause); if (EventFactory.callEvent(event).isCancelled()) { return false; } @@ -1846,6 +1821,9 @@ public boolean teleport(Location location, TeleportCause cause) { return true; } + /** + * Finishes the teleport process. + */ public void endTeleport() { Position.copyLocation(teleportedTo, location); teleportedTo = null; @@ -1859,7 +1837,8 @@ protected boolean teleportToSpawn() { target = server.getWorlds().get(0).getSpawnLocation(); } - PlayerPortalEvent event = EventFactory.callEvent(new PlayerPortalEvent(this, location.clone(), target, null)); + PlayerPortalEvent event = EventFactory + .callEvent(new PlayerPortalEvent(this, location.clone(), target, null)); if (event.isCancelled()) { return false; } @@ -1888,7 +1867,8 @@ protected boolean teleportToEnd() { return false; } - PlayerPortalEvent event = EventFactory.callEvent(new PlayerPortalEvent(this, location.clone(), target, null)); + PlayerPortalEvent event = EventFactory + .callEvent(new PlayerPortalEvent(this, location.clone(), target, null)); if (event.isCancelled()) { return false; } @@ -1924,7 +1904,8 @@ public void enterBed(GlowBlock block) { getSession().send(new UseBedMessage(SELF_ID, head.getX(), head.getY(), head.getZ())); UseBedMessage msg = new UseBedMessage(getEntityId(), head.getX(), head.getY(), head.getZ()); - world.getRawPlayers().stream().filter(p -> p != this && p.canSeeEntity(this)).forEach(p -> p.getSession().send(msg)); + world.getRawPlayers().stream().filter(p -> p != this && p.canSeeEntity(this)) + .forEach(p -> p.getSession().send(msg)); } /** @@ -1942,7 +1923,6 @@ public void leaveBed(boolean setSpawn) { if (exitBlock == null) { // If no empty blocks were found fallback to block above bed exitBlock = head.getRelative(BlockFace.UP); } - Location exitLocation = exitBlock.getLocation().add(0.5, 0.1, 0.5); // Use center of block // Set their spawn (normally omitted if their bed gets destroyed instead of them leaving it) if (setSpawn) { @@ -1955,6 +1935,7 @@ public void leaveBed(boolean setSpawn) { sleeping = false; // And eject the player + Location exitLocation = exitBlock.getLocation().add(0.5, 0.1, 0.5); // Use center of block setRawLocation(exitLocation, false); teleported = true; @@ -1989,7 +1970,8 @@ public void sendMessage(BaseComponent... components) { @Override public void sendMessage(ChatMessageType chatMessageType, BaseComponent... baseComponents) { - session.send(new ChatMessage(TextMessage.decode(ComponentSerializer.toString(baseComponents)), chatMessageType.ordinal())); + session.send(new ChatMessage(TextMessage + .decode(ComponentSerializer.toString(baseComponents)), chatMessageType.ordinal())); } @Override @@ -2000,7 +1982,8 @@ public void sendRawMessage(String message) { @Override public void sendActionBar(String message) { - // "old" formatting workaround because apparently "new" styling doesn't work as of 01/18/2015 + // "old" formatting workaround because apparently "new" styling doesn't work as of + // 01/18/2015 JSONObject json = new JSONObject(); json.put("text", message); session.send(new ChatMessage(new TextMessage(json), 2)); @@ -2027,42 +2010,50 @@ public void spawnParticle(Particle particle, Location location, int count, T } @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, T data) { + public void spawnParticle(Particle particle, double x, double y, double z, int count, + T data) { spawnParticle(particle, x, y, z, count, 0, 0, 0, 1, data); } @Override - public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ) { + public void spawnParticle(Particle particle, Location location, int count, double offsetX, + double offsetY, double offsetZ) { spawnParticle(particle, location, count, offsetX, offsetY, offsetZ, 1, null); } @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ) { + public void spawnParticle(Particle particle, double x, double y, double z, int count, + double offsetX, double offsetY, double offsetZ) { spawnParticle(particle, x, y, z, count, offsetX, offsetY, offsetZ, 1, null); } @Override - public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ, T data) { + public void spawnParticle(Particle particle, Location location, int count, double offsetX, + double offsetY, double offsetZ, T data) { spawnParticle(particle, location, count, offsetX, offsetY, offsetZ, 1, data); } @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, T data) { + public void spawnParticle(Particle particle, double x, double y, double z, int count, + double offsetX, double offsetY, double offsetZ, T data) { spawnParticle(particle, x, y, z, count, offsetX, offsetY, offsetY, 1, data); } @Override - public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ, double extra) { + public void spawnParticle(Particle particle, Location location, int count, double offsetX, + double offsetY, double offsetZ, double extra) { spawnParticle(particle, location, count, offsetX, offsetY, offsetZ, extra, null); } @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra) { + public void spawnParticle(Particle particle, double x, double y, double z, int count, + double offsetX, double offsetY, double offsetZ, double extra) { spawnParticle(particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, null); } @Override - public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) { + public void spawnParticle(Particle particle, Location location, int count, double offsetX, + double offsetY, double offsetZ, double extra, T data) { double distance = getLocation().distanceSquared(location); boolean isLongDistance = GlowParticle.isLongDistance(particle); @@ -2070,13 +2061,18 @@ public void spawnParticle(Particle particle, Location location, int count, d int[] particleData = GlowParticle.getExtData(particle, data); if (distance <= 1024.0D || isLongDistance && distance <= 262144.0D) { - getSession().send(new PlayParticleMessage(particleId, isLongDistance, (float) location.getX(), (float) location.getY(), (float) location.getZ(), (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count, particleData)); + getSession().send(new PlayParticleMessage(particleId, isLongDistance, (float) location + .getX(), (float) location.getY(), (float) location + .getZ(), (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, + count, particleData)); } } @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) { - spawnParticle(particle, new Location(world, x, y, z), count, offsetX, offsetY, offsetZ, extra, data); + public void spawnParticle(Particle particle, double x, double y, double z, int count, + double offsetX, double offsetY, double offsetZ, double extra, T data) { + spawnParticle(particle, new Location(world, x, y, z), count, offsetX, offsetY, offsetZ, + extra, data); } @Override @@ -2094,11 +2090,6 @@ public boolean getAffectsSpawning() { return affectsSpawning; } - @Override - public void setAffectsSpawning(boolean affects) { - affectsSpawning = affects; - } - @Override public int getViewDistance() { return settings.getViewDistance(); @@ -2141,13 +2132,16 @@ public void chat(String text, boolean async) { Runnable task = () -> { server.getLogger().info(getName() + " issued command: " + text); try { - PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(this, text); + PlayerCommandPreprocessEvent event + = new PlayerCommandPreprocessEvent(this, text); if (!EventFactory.callEvent(event).isCancelled()) { server.dispatchCommand(this, event.getMessage().substring(1)); } } catch (Exception ex) { - sendMessage(ChatColor.RED + "An internal error occurred while executing your command."); - server.getLogger().log(Level.SEVERE, "Exception while executing command: " + text, ex); + sendMessage(ChatColor.RED + + "An internal error occurred while executing your command."); + server.getLogger() + .log(Level.SEVERE, "Exception while executing command: " + text, ex); } }; @@ -2177,6 +2171,12 @@ public void saveData() { saveData(true); } + /** + * Saves the players current location, health, inventory, motion, and other information into the + * username.dat file, in the world/player folder. + * + * @param async if true, save asynchronously; if false, block until saved + */ public void saveData(boolean async) { if (async) { Bukkit.getScheduler().runTaskAsynchronously(null, () -> { @@ -2290,7 +2290,8 @@ public void playNote(Location loc, byte instrument, byte note) { @Override public void playEffect(Location loc, Effect effect, int data) { int id = effect.getId(); - session.send(new PlayEffectMessage(id, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), data, false)); + session.send(new PlayEffectMessage(id, loc.getBlockX(), loc.getBlockY(), loc + .getBlockZ(), data, false)); } @Override @@ -2300,7 +2301,8 @@ public void playEffect(Location loc, Effect effect, T data) { @Override public void playSound(Location location, Sound sound, float volume, float pitch) { - playSound(location, sound, GlowSound.getSoundCategory(GlowSound.getVanillaId(sound)), volume, pitch); + playSound(location, sound, GlowSound + .getSoundCategory(GlowSound.getVanillaId(sound)), volume, pitch); } @Override @@ -2309,7 +2311,8 @@ public void playSound(Location location, String sound, float volume, float pitch } @Override - public void playSound(Location location, String sound, SoundCategory category, float volume, float pitch) { + public void playSound(Location location, String sound, SoundCategory category, float volume, + float pitch) { if (location == null || sound == null) { return; } @@ -2320,7 +2323,8 @@ public void playSound(Location location, String sound, SoundCategory category, f } @Override - public void playSound(Location location, Sound sound, SoundCategory category, float volume, float pitch) { + public void playSound(Location location, Sound sound, SoundCategory category, float volume, + float pitch) { playSound(location, GlowSound.getVanillaId(sound), category, volume, pitch); } @@ -2380,8 +2384,21 @@ public Player.Spigot spigot() { return spigot; } + /** + * Sends a {@link PlayParticleMessage} to display the given particle. + * + * @param loc the location + * @param particle the particle type + * @param material the item or block data + * @param offsetX TODO: document this parameter + * @param offsetY TODO: document this parameter + * @param offsetZ TODO: document this parameter + * @param speed TODO: document this parameter + * @param amount the number of particles + */ //@Override - public void showParticle(Location loc, Effect particle, MaterialData material, float offsetX, float offsetY, float offsetZ, float speed, int amount) { + public void showParticle(Location loc, Effect particle, MaterialData material, float offsetX, + float offsetY, float offsetZ, float speed, int amount) { if (location == null || particle == null || particle.getType() != Type.PARTICLE) { return; } @@ -2392,7 +2409,8 @@ public void showParticle(Location loc, Effect particle, MaterialData material, f float y = (float) loc.getY(); float z = (float) loc.getZ(); int[] extData = GlowParticle.getExtData(particle, material); - session.send(new PlayParticleMessage(id, longDistance, x, y, z, offsetX, offsetY, offsetZ, speed, amount, extData)); + session.send(new PlayParticleMessage(id, longDistance, x, y, z, offsetX, offsetY, + offsetZ, speed, amount, extData)); } @Override @@ -2402,9 +2420,15 @@ public void sendBlockChange(Location loc, Material material, byte data) { @Override public void sendBlockChange(Location loc, int material, byte data) { - sendBlockChange(new BlockChangeMessage(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), material, data)); + sendBlockChange(new BlockChangeMessage(loc.getBlockX(), loc.getBlockY(), loc + .getBlockZ(), material, data)); } + /** + * Sends the given {@link BlockChangeMessage} if it's in a chunk this player can see. + * + * @param message the message to send + */ public void sendBlockChange(BlockChangeMessage message) { // only send message if the chunk is within visible range Key key = GlowChunk.Key.of(message.getX() >> 4, message.getZ() >> 4); @@ -2429,12 +2453,14 @@ public void sendSignChange(Location location, String[] lines) throws IllegalArgu checkNotNull(lines, "lines cannot be null"); checkArgument(lines.length == 4, "lines.length must equal 4"); - afterBlockChanges.add(UpdateSignMessage.fromPlainText(location.getBlockX(), location.getBlockY(), location.getBlockZ(), lines)); + afterBlockChanges.add(UpdateSignMessage + .fromPlainText(location.getBlockX(), location.getBlockY(), location + .getBlockZ(), lines)); } /** - * Send a sign change, similar to {@link #sendSignChange(Location, String[])}, - * but using complete TextMessages instead of strings. + * Send a sign change, similar to {@link #sendSignChange(Location, String[])}, but using + * complete TextMessages instead of strings. * * @param sign the sign * @param location the location of the sign @@ -2442,14 +2468,16 @@ public void sendSignChange(Location location, String[] lines) throws IllegalArgu * @throws IllegalArgumentException if location is null * @throws IllegalArgumentException if lines is non-null and has a length less than 4 */ - public void sendSignChange(SignEntity sign, Location location, TextMessage[] lines) throws IllegalArgumentException { + public void sendSignChange(SignEntity sign, Location location, + TextMessage[] lines) throws IllegalArgumentException { checkNotNull(location, "location cannot be null"); checkNotNull(lines, "lines cannot be null"); checkArgument(lines.length == 4, "lines.length must equal 4"); CompoundTag tag = new CompoundTag(); sign.saveNbt(tag); - afterBlockChanges.add(new UpdateBlockEntityMessage(location.getBlockX(), location.getBlockY(), location.getBlockZ(), GlowBlockEntity.SIGN.getValue(), tag)); + afterBlockChanges.add(new UpdateBlockEntityMessage(location.getBlockX(), location + .getBlockY(), location.getBlockZ(), GlowBlockEntity.SIGN.getValue(), tag)); } /** @@ -2464,19 +2492,22 @@ public void sendBlockEntityChange(Location location, GlowBlockEntity type, Compo checkNotNull(type, "Type cannot be null"); checkNotNull(nbt, "NBT cannot be null"); - afterBlockChanges.add(new UpdateBlockEntityMessage(location.getBlockX(), location.getBlockY(), location.getBlockZ(), type.getValue(), nbt)); + afterBlockChanges.add(new UpdateBlockEntityMessage(location.getBlockX(), location + .getBlockY(), location.getBlockZ(), type.getValue(), nbt)); } @Override public void sendMap(MapView map) { GlowMapCanvas mapCanvas = GlowMapCanvas.createAndRender(map, this); - session.send(new MapDataMessage(map.getId(), map.getScale().ordinal(), Collections.emptyList(), - mapCanvas.toSection())); + session.send(new MapDataMessage(map.getId(), map.getScale().ordinal(), Collections + .emptyList(), + mapCanvas.toSection())); } @Override public void setPlayerListHeaderFooter(BaseComponent[] header, BaseComponent[] footer) { - TextMessage h = TextMessage.decode(ComponentSerializer.toString(header)), f = TextMessage.decode(ComponentSerializer.toString(footer)); + TextMessage h = TextMessage.decode(ComponentSerializer.toString(header)); + TextMessage f = TextMessage.decode(ComponentSerializer.toString(footer)); session.send(new UserListHeaderFooterMessage(h, f)); } @@ -2513,12 +2544,14 @@ public void showTitle(BaseComponent title) { } @Override - public void showTitle(BaseComponent[] title, BaseComponent[] subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) { + public void showTitle(BaseComponent[] title, BaseComponent[] subtitle, int fadeInTicks, + int stayTicks, int fadeOutTicks) { sendTitle(new Title(title, subtitle, fadeInTicks, stayTicks, fadeOutTicks)); } @Override - public void showTitle(BaseComponent title, BaseComponent subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) { + public void showTitle(BaseComponent title, BaseComponent subtitle, int fadeInTicks, + int stayTicks, int fadeOutTicks) { sendTitle(new Title(title, subtitle, fadeInTicks, stayTicks, fadeOutTicks)); } @@ -2538,7 +2571,7 @@ public void sendTitle(String title, String subtitle, int fadeIn, int stay, int f } /** - * Send the player a title base on a {@link Title.Builder} + * Send the player a title base on a {@link Title.Builder}. * * @param title the {@link Title.Builder} to send the player */ @@ -2547,7 +2580,7 @@ public void sendTitle(Title.Builder title) { } /** - * Send the player their current title + * Send the player their current title. */ public void sendTitle() { sendTitle(currentTitle); @@ -2566,7 +2599,8 @@ public void updateTitle(Title title) { currentTitle.subtitle(title.getSubtitle()); } - if (builtTitle.getFadeIn() != title.getFadeIn() && title.getFadeIn() != Title.DEFAULT_FADE_IN) { + if (builtTitle.getFadeIn() != title.getFadeIn() + && title.getFadeIn() != Title.DEFAULT_FADE_IN) { currentTitle.fadeIn(title.getFadeIn()); } @@ -2574,23 +2608,26 @@ public void updateTitle(Title title) { currentTitle.stay(title.getStay()); } - if (builtTitle.getFadeOut() != title.getFadeOut() && title.getFadeOut() != Title.DEFAULT_FADE_OUT) { + if (builtTitle.getFadeOut() != title.getFadeOut() + && title.getFadeOut() != Title.DEFAULT_FADE_OUT) { currentTitle.fadeOut(title.getFadeOut()); } } /** - * Update a specific attribute of the player's title + * Update a specific attribute of the player's title. * * @param action the attribute to update * @param value the value of the attribute */ public void updateTitle(TitleMessage.Action action, Object... value) { - Preconditions.checkArgument(value.length > 0, "Expected at least one argument. Got " + value.length); + Preconditions.checkArgument( + value.length > 0, "Expected at least one argument. Got " + value.length); switch (action) { case TITLE: - Preconditions.checkArgument(!(value instanceof String[] || value instanceof BaseComponent[]), "Value is not of the correct type"); + Preconditions.checkArgument(!(value instanceof String[] + || value instanceof BaseComponent[]), "Value is not of the correct type"); if (value[0] instanceof String) { StringBuilder builder = new StringBuilder(); @@ -2610,7 +2647,8 @@ public void updateTitle(TitleMessage.Action action, Object... value) { break; case SUBTITLE: - Preconditions.checkArgument(!(value instanceof String[] || value instanceof BaseComponent[]), "Value is not of the correct type"); + Preconditions.checkArgument(!(value instanceof String[] + || value instanceof BaseComponent[]), "Value is not of the correct type"); if (value[0] instanceof String) { StringBuilder builder = new StringBuilder(); @@ -2630,8 +2668,11 @@ public void updateTitle(TitleMessage.Action action, Object... value) { break; case TIMES: - Preconditions.checkArgument(!(value instanceof Integer[]), "Value is not of the correct type"); - Preconditions.checkArgument(value.length == 3, "Expected 3 values. Got " + value.length); + Preconditions + .checkArgument(!(value instanceof Integer[]), "Value is not of the " + + "correct type"); + Preconditions + .checkArgument(value.length == 3, "Expected 3 values. Got " + value.length); currentTitle.fadeIn((int) value[0]); currentTitle.stay((int) value[1]); @@ -2639,7 +2680,9 @@ public void updateTitle(TitleMessage.Action action, Object... value) { break; default: - Preconditions.checkArgument(true, "Action is something other than a title, subtitle, or times"); + Preconditions + .checkArgument(true, "Action is something other than a title, subtitle, " + + "or times"); } } @@ -2663,10 +2706,11 @@ public void awardAchievement(Achievement achievement) { } /** - * Awards the given achievement if the player already has the parent achievement, otherwise does nothing. + * Awards the given achievement if the player already has the parent achievement, otherwise does + * nothing. * - *

If {@code awardParents} is true, award the player all parent achievements and the given achievement, - * making this method equivalent to {@link #awardAchievement(Achievement)}. + *

If {@code awardParents} is true, award the player all parent achievements and the given + * achievement, making this method equivalent to {@link #awardAchievement(Achievement)}. * * @param achievement the achievement to award. * @param awardParents whether parent achievements should be awarded. @@ -2695,7 +2739,9 @@ public boolean awardAchievement(Achievement achievement, boolean awardParents) { if (server.getAnnounceAchievements()) { // todo: make message fancier (hover, translated names) - server.broadcastMessage(getName() + " has just earned the achievement " + ChatColor.GREEN + "[" + GlowAchievement.getFancyName(achievement) + "]"); + server.broadcastMessage( + getName() + " has just earned the achievement " + ChatColor.GREEN + "[" + + GlowAchievement.getFancyName(achievement) + "]"); } return true; } @@ -2722,12 +2768,14 @@ public int getStatistic(Statistic statistic) throws IllegalArgumentException { } @Override - public int getStatistic(Statistic statistic, Material material) throws IllegalArgumentException { + public int getStatistic(Statistic statistic, + Material material) throws IllegalArgumentException { return stats.get(statistic, material); } @Override - public int getStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { + public int getStatistic(Statistic statistic, + EntityType entityType) throws IllegalArgumentException { return stats.get(statistic, entityType); } @@ -2737,7 +2785,8 @@ public void setStatistic(Statistic statistic, int newValue) throws IllegalArgume } @Override - public void setStatistic(Statistic statistic, Material material, int newValue) throws IllegalArgumentException { + public void setStatistic(Statistic statistic, Material material, + int newValue) throws IllegalArgumentException { stats.set(statistic, material, newValue); } @@ -2767,12 +2816,14 @@ public void incrementStatistic(Statistic statistic, Material material, int amoun } @Override - public void incrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { + public void incrementStatistic(Statistic statistic, + EntityType entityType) throws IllegalArgumentException { stats.add(statistic, entityType, 1); } @Override - public void incrementStatistic(Statistic statistic, EntityType entityType, int amount) throws IllegalArgumentException { + public void incrementStatistic(Statistic statistic, EntityType entityType, + int amount) throws IllegalArgumentException { stats.add(statistic, entityType, amount); } @@ -2782,22 +2833,26 @@ public void decrementStatistic(Statistic statistic) throws IllegalArgumentExcept } @Override - public void decrementStatistic(Statistic statistic, int amount) throws IllegalArgumentException { + public void decrementStatistic(Statistic statistic, + int amount) throws IllegalArgumentException { stats.add(statistic, -amount); } @Override - public void decrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException { + public void decrementStatistic(Statistic statistic, + Material material) throws IllegalArgumentException { stats.add(statistic, material, -1); } @Override - public void decrementStatistic(Statistic statistic, Material material, int amount) throws IllegalArgumentException { + public void decrementStatistic(Statistic statistic, Material material, + int amount) throws IllegalArgumentException { stats.add(statistic, material, -amount); } @Override - public void decrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { + public void decrementStatistic(Statistic statistic, + EntityType entityType) throws IllegalArgumentException { stats.add(statistic, entityType, -1); } @@ -2822,6 +2877,12 @@ public void updateInventory() { session.send(new SetWindowContentsMessage(invMonitor.getId(), invMonitor.getContents())); } + /** + * Sends a {@link SetWindowSlotMessage} to update the contents of an inventory slot. + * + * @param slot the slot ID + * @param item the new contents + */ public void sendItemChange(int slot, ItemStack item) { if (invMonitor != null) { session.send(new SetWindowSlotMessage(invMonitor.getId(), slot, item)); @@ -2851,7 +2912,8 @@ public void setCooldown(Material material, int ticks) { @Override public MainHand getMainHand() { - return metadata.getByte(MetadataIndex.PLAYER_MAIN_HAND) == 0 ? MainHand.LEFT : MainHand.RIGHT; + return metadata.getByte(MetadataIndex.PLAYER_MAIN_HAND) == 0 ? MainHand.LEFT + : MainHand.RIGHT; } @Override @@ -2877,7 +2939,8 @@ public void openInventory(InventoryView view) { if (view.getTopInventory() instanceof PlayerInventory && defaultTitle) { title = ((PlayerInventory) view.getTopInventory()).getHolder().getName(); } - Message open = new OpenWindowMessage(viewId, invMonitor.getType(), title, ((GlowInventory) view.getTopInventory()).getRawSlots()); + Message open = new OpenWindowMessage(viewId, invMonitor + .getType(), title, ((GlowInventory) view.getTopInventory()).getRawSlots()); session.send(open); } @@ -2916,13 +2979,13 @@ public GlowItem drop(ItemStack stack) { @Override public void setPlayerTime(long time, boolean relative) { timeOffset = (time % GlowWorld.DAY_LENGTH + GlowWorld.DAY_LENGTH) % GlowWorld.DAY_LENGTH; - timeRelative = relative; + playerTimeRelative = relative; sendTime(); } @Override public long getPlayerTime() { - if (timeRelative) { + if (playerTimeRelative) { // add timeOffset ticks to current time return (world.getTime() + timeOffset) % GlowWorld.DAY_LENGTH; } else { @@ -2936,19 +2999,17 @@ public long getPlayerTimeOffset() { return timeOffset; } - @Override - public boolean isPlayerTimeRelative() { - return timeRelative; - } - @Override public void resetPlayerTime() { setPlayerTime(0, true); } + /** + * Sends a {@link TimeMessage} with the time of day. + */ public void sendTime() { long time = getPlayerTime(); - if (!timeRelative || !world.getGameRuleMap().getBoolean("doDaylightCycle")) { + if (!playerTimeRelative || !world.getGameRuleMap().getBoolean("doDaylightCycle")) { time *= -1; // negative value indicates fixed time } session.send(new TimeMessage(world.getFullTime(), time)); @@ -2973,8 +3034,12 @@ public void resetPlayerWeather() { sendSkyDarkness(); } + /** + * Sends a {@link StateChangeMessage} with the current weather. + */ public void sendWeather() { - boolean stormy = playerWeather == null ? getWorld().hasStorm() : playerWeather == WeatherType.DOWNFALL; + boolean stormy = playerWeather == null ? getWorld().hasStorm() + : playerWeather == WeatherType.DOWNFALL; session.send(new StateChangeMessage(stormy ? Reason.START_RAIN : Reason.STOP_RAIN, 0)); } @@ -3003,7 +3068,8 @@ public void hidePlayer(Player player) { worldLock.writeLock().lock(); try { if (knownEntities.remove(player)) { - session.send(new DestroyEntitiesMessage(Collections.singletonList(player.getEntityId()))); + session.send(new DestroyEntitiesMessage(Collections + .singletonList(player.getEntityId()))); } } finally { worldLock.writeLock().unlock(); @@ -3027,7 +3093,9 @@ public void showPlayer(Player player) { } hiddenEntities.remove(player.getUniqueId()); - session.send(new UserListItemMessage(UserListItemMessage.Action.ADD_PLAYER, ((GlowPlayer) player).getUserListEntry())); + session.send(new UserListItemMessage(UserListItemMessage.Action.ADD_PLAYER, ((GlowPlayer) + player) + .getUserListEntry())); } @Override @@ -3044,7 +3112,8 @@ public boolean canSee(Player player) { // Scoreboard /** - * Called when a player hidden to this player disconnects. This is necessary so the player is visible again after they reconnected. + * Called when a player hidden to this player disconnects. This is necessary so the player is + * visible again after they reconnected. * * @param player The disconnected player */ @@ -3061,7 +3130,8 @@ public Scoreboard getScoreboard() { // Conversable @Override - public void setScoreboard(Scoreboard scoreboard) throws IllegalArgumentException, IllegalStateException { + public void setScoreboard( + Scoreboard scoreboard) throws IllegalArgumentException, IllegalStateException { checkNotNull(scoreboard, "Scoreboard must not be null"); if (!(scoreboard instanceof GlowScoreboard)) { throw new IllegalArgumentException("Scoreboard must be GlowScoreboard"); @@ -3114,7 +3184,8 @@ public void abandonConversation(Conversation conversation, ConversationAbandoned @Override public void sendPluginMessage(Plugin source, String channel, byte[] message) { - StandardMessenger.validatePluginMessage(getServer().getMessenger(), source, channel, message); + StandardMessenger + .validatePluginMessage(getServer().getMessenger(), source, channel, message); if (listeningChannels.contains(channel)) { // only send if player is listening for it session.send(new PluginMessage(channel, message)); @@ -3167,11 +3238,16 @@ private void sendSupportedChannels() { } } + /** + * Updates level after enchanting. + * + * @param clicked the enchanting-table slot used: 0 for top, 1 for middle, 2 for bottom + */ public void enchanted(int clicked) { level -= clicked + 1; if (level < 0) { level = 0; - experience = 0; + exp = 0; totalExperience = 0; } setLevel(level); @@ -3194,10 +3270,11 @@ public void resetTitle() { session.send(new TitleMessage(Action.RESET)); } - public GlowBlock getDigging() { - return digging; - } - + /** + * Starts breaking a block. + * + * @param block the block to start breaking + */ public void setDigging(GlowBlock block) { if (block == null) { if (digging != null) { @@ -3214,12 +3291,17 @@ public void setDigging(GlowBlock block) { } private void sendBlockBreakAnimation(Location loc, int destroyStage) { - afterBlockChanges.add(new BlockBreakAnimationMessage(this.getEntityId(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), destroyStage)); + afterBlockChanges + .add(new BlockBreakAnimationMessage(this.getEntityId(), loc.getBlockX(), loc + .getBlockY(), loc.getBlockZ(), destroyStage)); } private void broadcastBlockBreakAnimation(GlowBlock block, int destroyStage) { GlowChunk.Key key = GlowChunk.Key.of(block.getX() >> 4, block.getZ() >> 4); - block.getWorld().getRawPlayers().stream().filter(player -> player.canSeeChunk(key) && player != this).forEach(player -> player.sendBlockBreakAnimation(block.getLocation(), destroyStage)); + block.getWorld().getRawPlayers().stream() + .filter(player -> player.canSeeChunk(key) && player != this) + .forEach(player -> player + .sendBlockBreakAnimation(block.getLocation(), destroyStage)); } private void pulseDigging() { @@ -3227,8 +3309,8 @@ private void pulseDigging() { float hardness = digging.getMaterialValues().getHardness() * 20; // seconds to ticks - // TODO: take into account the tool used to mine (ineffective=5x, effective=1.5x, material multiplier, etc.) - // for now, assuming hands are used and the block is not dropped + // TODO: take into account the tool used to mine (ineffective=5x, effective=1.5x, material + // multiplier, etc.). For now, assuming hands are used and the block is not dropped. hardness *= 5; double completion = (double) diggingTicks / hardness; @@ -3241,7 +3323,7 @@ private void pulseDigging() { } /** - * Returns true if the player is inside a water block + * Returns true if the player is inside a water block. * * @return True if entity is in water. */ @@ -3258,6 +3340,7 @@ public void playAnimationToSelf(EntityAnimation animation) { /** * Add a boss bar. + * * @param bar the boss bar to add */ public void addBossBar(BossBar bar) { @@ -3266,6 +3349,7 @@ public void addBossBar(BossBar bar) { /** * Remove a boss bar. + * * @param bar the boss bar to remove */ public void removeBossBar(BossBar bar) { @@ -3274,6 +3358,7 @@ public void removeBossBar(BossBar bar) { /** * Returns a collection of the boss bars this player sees. + * * @return the boss bars this player sees */ public Collection getBossBars() { diff --git a/src/main/java/net/glowstone/entity/GlowTNTPrimed.java b/src/main/java/net/glowstone/entity/GlowTntPrimed.java similarity index 63% rename from src/main/java/net/glowstone/entity/GlowTNTPrimed.java rename to src/main/java/net/glowstone/entity/GlowTntPrimed.java index 76e6465a92..0f85d95437 100644 --- a/src/main/java/net/glowstone/entity/GlowTNTPrimed.java +++ b/src/main/java/net/glowstone/entity/GlowTntPrimed.java @@ -4,6 +4,8 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.ThreadLocalRandom; +import lombok.Getter; +import lombok.Setter; import net.glowstone.EventFactory; import net.glowstone.Explosion; import net.glowstone.net.message.play.entity.SpawnObjectMessage; @@ -15,19 +17,39 @@ import org.bukkit.event.entity.ExplosionPrimeEvent; import org.bukkit.util.Vector; -public class GlowTNTPrimed extends GlowExplosive implements TNTPrimed { +public class GlowTntPrimed extends GlowExplosive implements TNTPrimed { + @Getter + @Setter private int fuseTicks; + @Setter private Entity source; - public GlowTNTPrimed(Location location, Entity source) { + /** + * Get the player that ignited the TNT. + * + * @return Player that ignited the TNT + */ + public GlowPlayer getPlayer() { + Entity source = getSource(); + return (source instanceof GlowPlayer) ? (GlowPlayer) source : null; + } + + /** + * Creates a primed TNT block. + * + * @param location the location + * @param source the entity that ignited this + */ + public GlowTntPrimed(Location location, Entity source) { super(location, Explosion.POWER_TNT); setSize(0.98f, 0.98f); fuseTicks = 0; ThreadLocalRandom rand = ThreadLocalRandom.current(); int multiplier = rand.nextBoolean() ? 1 : -1; - double x = 0, z = 0; + double x = 0; + double z = 0; double mag = rand.nextDouble(0, 0.02); if (rand.nextBoolean()) { x = multiplier * mag; @@ -38,9 +60,16 @@ public GlowTNTPrimed(Location location, Entity source) { this.source = source; } + /** + * Sets whether this TNT was ignited by an explosion or not. This is not tracked, but affects + * the fuse length. + * + * @param ignitedByExplosion whether this TNT was ignited by an explosion + */ public void setIgnitedByExplosion(boolean ignitedByExplosion) { if (ignitedByExplosion) { - // if ignited by an explosion, the fuseTicks should be a random number between 10 and 30 ticks + // if ignited by an explosion, the fuseTicks should be a random number between 10 and 30 + // ticks fuseTicks = ThreadLocalRandom.current().nextInt(10, 31); } else { fuseTicks = 80; @@ -64,8 +93,9 @@ private void explode() { if (!event.isCancelled()) { Location location = getLocation(); - double x = location.getX(), y = location.getY() + 0.06125, z = location.getZ(); - world.createExplosion(this, x, y, z, event.getRadius(), event.getFire(), true); + world.createExplosion(this, + location.getX(), location.getY() + 0.06125, location.getZ(), + event.getRadius(), event.getFire(), true); } remove(); @@ -73,22 +103,13 @@ private void explode() { @Override public List createSpawnMessage() { - return Collections.singletonList(new SpawnObjectMessage(id, getUniqueId(), 50, location)); - } - - @Override - public final int getFuseTicks() { - return fuseTicks; - } - - @Override - public final void setFuseTicks(int i) { - fuseTicks = i; + return Collections.singletonList(new SpawnObjectMessage( + entityId, getUniqueId(), 50, location)); } @Override public final Entity getSource() { - return source.isValid() ? source : null; + return (source != null && source.isValid()) ? source : null; } @Override diff --git a/src/main/java/net/glowstone/entity/ai/EntityTask.java b/src/main/java/net/glowstone/entity/ai/EntityTask.java index 84f05278cc..a3bc895808 100644 --- a/src/main/java/net/glowstone/entity/ai/EntityTask.java +++ b/src/main/java/net/glowstone/entity/ai/EntityTask.java @@ -1,13 +1,32 @@ package net.glowstone.entity.ai; import java.util.concurrent.ThreadLocalRandom; +import lombok.Getter; import net.glowstone.entity.GlowLivingEntity; public abstract class EntityTask implements Comparable { + /** + * The name of this EntityTask. Must be unique to each EntityTask implementation. + * + * @return the name of this EntityTask. + */ + @Getter private final String name; + /** + * Whether this task is currently being executed. + * + * @return true if this task is being executed, false otherwise. + */ + @Getter private boolean executing = false; private int duration = 0; + /** + * Whether this task is paused. + * + * @return whether this task is paused. + */ + @Getter private boolean paused = false; public EntityTask(String name) { @@ -62,24 +81,6 @@ public void reset(GlowLivingEntity entity) { executing = false; } - /** - * Whether this task is currently being executed. - * - * @return true if this task is being executed, false otherwise. - */ - public final boolean isExecuting() { - return executing; - } - - /** - * Whether this task is paused. - * - * @return whether this task is paused. - */ - public final boolean isPaused() { - return paused; - } - /** * Resumes the previously paused task for this entity. * @@ -105,15 +106,6 @@ public final void pause(GlowLivingEntity entity) { paused = true; } - /** - * The name of this EntityTask. Must be unique to each EntityTask implementation. - * - * @return the name of this EntityTask. - */ - public String getName() { - return name; - } - /** * The minimum duration of this task. This value is ignored if this task is instant. * diff --git a/src/main/java/net/glowstone/entity/ai/TaskManager.java b/src/main/java/net/glowstone/entity/ai/TaskManager.java index c5fb251e80..bfc545c849 100644 --- a/src/main/java/net/glowstone/entity/ai/TaskManager.java +++ b/src/main/java/net/glowstone/entity/ai/TaskManager.java @@ -1,39 +1,56 @@ package net.glowstone.entity.ai; -import java.util.Objects; +import com.google.common.collect.ClassToInstanceMap; +import com.google.common.collect.MutableClassToInstanceMap; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListSet; import net.glowstone.entity.GlowLivingEntity; public class TaskManager { private final GlowLivingEntity entity; - private final Set tasks; + private final Map tasksByName = new ConcurrentHashMap<>(); + private final ClassToInstanceMap tasksByClass = MutableClassToInstanceMap.create( + new ConcurrentHashMap<>()); + private final Set tasks = new ConcurrentSkipListSet<>(); public TaskManager(GlowLivingEntity entity) { this.entity = entity; - this.tasks = new ConcurrentSkipListSet<>(); } + /** + * Returns the existing task with a given name. + * + * @param name the name to look up + * @return the task with that name, or null if no registered task matches + */ public EntityTask getTask(String name) { - for (EntityTask task : tasks) { - if (task != null && Objects.equals(task.getName(), name)) { - return task; - } - } - return null; + return tasksByName.get(name); } + /** + * Returns the existing task whose class is exactly a given class (and not a subclass -- this + * will always return null for an abstract type). + * + * @param clazz the class to look up + * @return one of this manager's tasks that's an instance of that class and not a subclass, or + * null if no such tasks are registered + */ public EntityTask getTask(Class clazz) { - for (EntityTask task : tasks) { - if (Objects.equals(task.getClass(), clazz)) { - return task; - } - } - return null; + return tasksByClass.get(clazz); } + /** + * Returns a new instance of the task with a given name. + * + * @param name the task name to look up + * @return a task with the given name, or null if none match or the matching task class doesn't + * have a parameterless constructor + */ public EntityTask getNewTask(String name) { + // TODO: Refactor to use a constructor-reference Supplier Class clazz = EntityDirector.getEntityTask(name); try { if (clazz != null) { @@ -45,21 +62,36 @@ public EntityTask getNewTask(String name) { return null; } + /** + * Rebuild the list of tasks according to {@link EntityDirector#getEntityMobStateTask + * (EntityType, MobState)}. + */ public void updateState() { cancelTasks(); for (String task : EntityDirector - .getEntityMobStateTask(entity.getType(), entity.getState())) { + .getEntityMobStateTask(entity.getType(), entity.getState())) { addTask(task); } } + /** + * Cancels and unregisters the given task. + * @param task the task to cancel + */ public void cancel(EntityTask task) { task.reset(entity); + tasksByName.remove(task.getName(), task); + tasksByClass.remove(task.getClass(), task); tasks.remove(task); } + /** + * Cancels and unregisters all tasks. + */ public void cancelTasks() { tasks.forEach(task -> task.reset(entity)); + tasksByName.clear(); + tasksByClass.clear(); tasks.clear(); } @@ -67,19 +99,37 @@ public void pulse() { tasks.forEach(task -> task.pulse(entity)); } + /** + * Add the given task, replacing any existing task with the same name. + * + * @param task the task to add + */ public void addTask(EntityTask task) { if (task != null) { - if (getTask(task.getName()) != null) { - cancel(getTask(task.getName())); + String name = task.getName(); + EntityTask oldTask = getTask(name); + if (oldTask != null) { + cancel(oldTask); } + tasksByName.put(name, task); + tasksByClass.put(task.getClass(), task); tasks.add(task); } } - public void addTask(String task) { - if (getTask(task) != null) { - cancel(getTask(task)); + /** + * Add the task with this name, or replace it with a new instance if it already exists. + * + * @param taskName the task name + */ + public void addTask(String taskName) { + EntityTask oldTask = getTask(taskName); + if (oldTask != null) { + cancel(oldTask); } - tasks.add(getNewTask(task)); + EntityTask newTask = getNewTask(taskName); + tasksByName.put(taskName, newTask); + tasksByClass.put(newTask.getClass(), newTask); + tasks.add(newTask); } } diff --git a/src/main/java/net/glowstone/entity/ai/TransportHelper.java b/src/main/java/net/glowstone/entity/ai/TransportHelper.java index ebe9a2e4cd..343e323e12 100644 --- a/src/main/java/net/glowstone/entity/ai/TransportHelper.java +++ b/src/main/java/net/glowstone/entity/ai/TransportHelper.java @@ -10,6 +10,13 @@ public static void moveTowards(GlowLivingEntity entity, Location direction) { moveTowards(entity, direction, 0.3); } + /** + * Starts an entity moving horizontally toward a location (may overshoot). + * + * @param entity the entity to move + * @param direction the destination to move toward + * @param speed the speed to move + */ public static void moveTowards(GlowLivingEntity entity, Location direction, double speed) { Location location = entity.getLocation(); double deltaX = (direction.getX() - location.getX()); diff --git a/src/main/java/net/glowstone/entity/meta/MetadataIndex.java b/src/main/java/net/glowstone/entity/meta/MetadataIndex.java index a955ae3b84..8d7c3e6a33 100644 --- a/src/main/java/net/glowstone/entity/meta/MetadataIndex.java +++ b/src/main/java/net/glowstone/entity/meta/MetadataIndex.java @@ -3,6 +3,7 @@ import static net.glowstone.entity.meta.MetadataType.BLOCKID; import static net.glowstone.entity.meta.MetadataType.BOOLEAN; import static net.glowstone.entity.meta.MetadataType.BYTE; +import static net.glowstone.entity.meta.MetadataType.CHAT; import static net.glowstone.entity.meta.MetadataType.DIRECTION; import static net.glowstone.entity.meta.MetadataType.FLOAT; import static net.glowstone.entity.meta.MetadataType.INT; @@ -13,6 +14,8 @@ import static net.glowstone.entity.meta.MetadataType.STRING; import static net.glowstone.entity.meta.MetadataType.VECTOR; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import net.glowstone.entity.passive.GlowParrot; import net.glowstone.entity.passive.GlowTameable; import org.bukkit.entity.AbstractHorse; @@ -60,11 +63,13 @@ import org.bukkit.entity.Wolf; import org.bukkit.entity.Zombie; import org.bukkit.entity.ZombieVillager; +import org.bukkit.entity.minecart.CommandMinecart; import org.bukkit.entity.minecart.PoweredMinecart; /** * Index constants for entity metadata. */ +@RequiredArgsConstructor public enum MetadataIndex { //Entity @@ -126,9 +131,10 @@ public enum MetadataIndex { ARMORSTAND_LEFT_LEG_POSITION(16, VECTOR, ArmorStand.class), ARMORSTAND_RIGHT_LEG_POSITION(17, VECTOR, ArmorStand.class), - //NO_AI(10, BYTE, Insentient.class), TODO - 1.9 "Insentient extends Living". Need more information + //NO_AI(10, BYTE, Insentient.class), + // TODO - 1.9 "Insentient extends Living". Need more information - BAT_HANGING(12, BYTE, Bat.class), + BAT_FLAGS(12, BYTE, Bat.class), AGE_ISBABY(12, BOOLEAN, Ageable.class), @@ -158,7 +164,7 @@ public enum MetadataIndex { WOLF_HEALTH(15, FLOAT, Wolf.class), WOLF_BEGGING(16, BOOLEAN, Wolf.class), - WOLF_COLOR(21, BYTE, Wolf.class), + WOLF_COLOR(17, BYTE, Wolf.class), VILLAGER_PROFESSION(13, INT, Villager.class), @@ -196,7 +202,7 @@ public enum MetadataIndex { ZOMBIE_HANDS_RISED_UP(14, BOOLEAN, Zombie.class), ZOMBIE_VILLAGER_IS_CONVERTING(15, BOOLEAN, ZombieVillager.class), - ZOMBIE_VILLAGER_PROFESSION(16, BOOLEAN, ZombieVillager.class), + ZOMBIE_VILLAGER_PROFESSION(16, INT, ZombieVillager.class), ENDERMAN_BLOCK(12, BLOCKID, Enderman.class), ENDERMAN_SCREAMING(13, BOOLEAN, Enderman.class), @@ -224,24 +230,25 @@ public enum MetadataIndex { PARROT_VARIANT(15, INT, GlowParrot.class), - //TODO - 1.9 When Those minecarts are implemented, uncomment this - //MINECARTCOMMANDBLOCK_COMMAND(11, STRING, Minecart.class), //TODO 1.9 - Command block minecraft addition - //MINECARTCOMMANDBLOCK_LAST_OUTPUT(12, CHAT, Minecart.class), //TODO 1.9 - Command block minecraft addition + MINECARTCOMMANDBLOCK_COMMAND(12, STRING, CommandMinecart.class), + MINECARTCOMMANDBLOCK_LAST_OUTPUT(13, CHAT, CommandMinecart.class), FURNACE_MINECART_POWERED(12, BOOLEAN, PoweredMinecart.class), TNT_PRIMED(6, INT, TNTPrimed.class),; - + @Getter private final int index; + @Getter private final MetadataType type; + @Getter private final Class appliesTo; - MetadataIndex(int index, MetadataType type, Class appliesTo) { - this.index = index; - this.type = type; - this.appliesTo = appliesTo; - } - + /** + * Returns the first {@link MetadataIndex} with a given index and {@link MetadataType}. + * @param index the index to look up + * @param type the type to look up + * @return a {@link MetadataIndex} with that index and type, or null if none match + */ public static MetadataIndex getIndex(int index, MetadataType type) { MetadataIndex output = null; for (MetadataIndex entry : values()) { @@ -253,18 +260,6 @@ public static MetadataIndex getIndex(int index, MetadataType type) { return output; } - public int getIndex() { - return index; - } - - public MetadataType getType() { - return type; - } - - public Class getAppliesTo() { - return appliesTo; - } - public boolean appliesTo(Class clazz) { return appliesTo.isAssignableFrom(clazz); } @@ -306,4 +301,9 @@ public interface TameableFlags { int WOLF_IS_ANGRY = 0x02; int IS_TAME = 0x04; } + + public interface BatFlags { + + int IS_HANGING = 0x01; + } } diff --git a/src/main/java/net/glowstone/entity/meta/MetadataMap.java b/src/main/java/net/glowstone/entity/meta/MetadataMap.java index faccfaf25b..7c2f1e5592 100644 --- a/src/main/java/net/glowstone/entity/meta/MetadataMap.java +++ b/src/main/java/net/glowstone/entity/meta/MetadataMap.java @@ -11,6 +11,7 @@ import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; import lombok.ToString; +import net.glowstone.util.DynamicallyTypedMapWithFloats; import org.bukkit.entity.Entity; import org.bukkit.inventory.ItemStack; import org.bukkit.util.BlockVector; @@ -19,7 +20,7 @@ * A map for entity metadata. */ @ToString(of = {"entityClass", "map"}) -public class MetadataMap { +public class MetadataMap implements DynamicallyTypedMapWithFloats { private final Map map = new EnumMap<>(MetadataIndex.class); private final List changes = new ArrayList<>(4); @@ -34,6 +35,12 @@ public boolean containsKey(MetadataIndex index) { return map.containsKey(index); } + /** + * Sets the value of a metadata field. + * + * @param index the field to set + * @param value the new value + */ public void set(MetadataIndex index, Object value) { // take numbers down to the correct precision if (value != null) { @@ -49,6 +56,8 @@ public void set(MetadataIndex index, Object value) { case FLOAT: value = n.floatValue(); break; + default: + // do nothing } } if (!index.getType().getDataType().isAssignableFrom(value.getClass())) { @@ -89,6 +98,13 @@ public boolean getBit(MetadataIndex index, int bit) { return (getNumber(index).intValue() & bit) != 0; } + /** + * Sets or clears bits in an integer field. + * + * @param index the field to update + * @param bit a mask of the bits to set or clear + * @param status true to set; false to clear + */ public void setBit(MetadataIndex index, int bit, boolean status) { if (status) { set(index, getNumber(index).intValue() | bit); @@ -97,6 +113,13 @@ public void setBit(MetadataIndex index, int bit, boolean status) { } } + /** + * Returns the numeric value of a metadata field. + * + * @param index the field to look up + * @return the numeric value + * @throws IllegalArgumentException if the value doesn't exist or isn't numeric + */ public Number getNumber(MetadataIndex index) { if (!containsKey(index)) { return 0; @@ -109,6 +132,7 @@ public Number getNumber(MetadataIndex index) { return (Number) o; } + @Override public boolean getBoolean(MetadataIndex index) { return get(index, MetadataType.BOOLEAN, false); } @@ -117,14 +141,17 @@ public byte getByte(MetadataIndex index) { return get(index, MetadataType.BYTE, (byte) 0); } + @Override public int getInt(MetadataIndex index) { return get(index, MetadataType.INT, 0); } + @Override public float getFloat(MetadataIndex index) { return get(index, MetadataType.FLOAT, 0f); } + @Override public String getString(MetadataIndex index) { return get(index, MetadataType.STRING, null); } @@ -134,7 +161,7 @@ public ItemStack getItem(MetadataIndex index) { } /** - * Gets the optional position value for the given MetadataIndex + * Gets the optional position value for the given MetadataIndex. * * @param index the MetadataIndex of the optional position * @return the position value as a BlockVector, null if the value is not present @@ -143,6 +170,11 @@ public BlockVector getOptPosition(MetadataIndex index) { return get(index, MetadataType.OPTPOSITION, null); } + /** + * Returns a list containing copies of all the entries. + * + * @return a list containing copies of all the entries + */ public List getEntryList() { List result = new ArrayList<>(map.size()); result.addAll( diff --git a/src/main/java/net/glowstone/entity/meta/MetadataType.java b/src/main/java/net/glowstone/entity/meta/MetadataType.java index e6cb45eea8..9b3e334d89 100644 --- a/src/main/java/net/glowstone/entity/meta/MetadataType.java +++ b/src/main/java/net/glowstone/entity/meta/MetadataType.java @@ -1,6 +1,8 @@ package net.glowstone.entity.meta; import java.util.UUID; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import net.glowstone.util.TextMessage; import net.glowstone.util.nbt.CompoundTag; import org.bukkit.inventory.ItemStack; @@ -10,6 +12,7 @@ /** * The types of values that entity metadata can contain. */ +@RequiredArgsConstructor public enum MetadataType { BYTE(Byte.class, false), INT(Integer.class, false), @@ -26,27 +29,16 @@ public enum MetadataType { BLOCKID(Integer.class, false), NBTTAG(CompoundTag.class, false),; + @Getter private final Class dataType; + @Getter private final boolean optional; - MetadataType(Class dataType, boolean optional) { - this.dataType = dataType; - this.optional = optional; - } - public static MetadataType byId(int id) { return values()[id]; } - public Class getDataType() { - return dataType; - } - public int getId() { return ordinal(); } - - public boolean isOptional() { - return optional; - } } diff --git a/src/main/java/net/glowstone/entity/meta/profile/PlayerDataFetcher.java b/src/main/java/net/glowstone/entity/meta/profile/PlayerDataFetcher.java index 360d353ac0..624e9aeda3 100644 --- a/src/main/java/net/glowstone/entity/meta/profile/PlayerDataFetcher.java +++ b/src/main/java/net/glowstone/entity/meta/profile/PlayerDataFetcher.java @@ -71,7 +71,7 @@ public static PlayerProfile getProfile(UUID uuid) { * @param playerName The name to look up. * @return The UUID, or null on failure. */ - public static UUID getUUID(String playerName) { + public static UUID getUuid(String playerName) { HttpsURLConnection conn; try { URL url = new URL(UUID_URL); diff --git a/src/main/java/net/glowstone/entity/meta/profile/PlayerProfile.java b/src/main/java/net/glowstone/entity/meta/profile/PlayerProfile.java index 65980b27b3..2c49d6486d 100644 --- a/src/main/java/net/glowstone/entity/meta/profile/PlayerProfile.java +++ b/src/main/java/net/glowstone/entity/meta/profile/PlayerProfile.java @@ -71,8 +71,9 @@ public static CompletableFuture getProfile(String name) { return CompletableFuture.completedFuture(null); } - if (Bukkit.getServer().getOnlineMode() || ((GlowServer) Bukkit.getServer()).getProxySupport()) { - return ProfileCache.getUUID(name).thenComposeAsync((uuid) -> { + if (Bukkit.getServer().getOnlineMode() + || ((GlowServer) Bukkit.getServer()).getProxySupport()) { + return ProfileCache.getUuid(name).thenComposeAsync((uuid) -> { if (uuid == null) { return CompletableFuture.completedFuture(null); } else { @@ -84,12 +85,12 @@ public static CompletableFuture getProfile(String name) { } /** - * Get the profile from a NBT tag (e.g. skulls). + * Get the profile from a NBT tag (e.g. skulls). Missing information is fetched asynchronously. * * @param tag The NBT tag containing profile information. * @return A PlayerProfile future. May contain a null name if the lookup failed. */ - public static CompletableFuture fromNBT(CompoundTag tag) { + public static CompletableFuture fromNbt(CompoundTag tag) { // NBT: {Id: "", Name: "", Properties: {textures: [{Signature: "", Value: {}}]}} UUID uuid = UUID.fromString(tag.getString("Id")); @@ -105,13 +106,20 @@ public static CompletableFuture fromNBT(CompoundTag tag) { } if (tag.containsKey("Name")) { - return CompletableFuture.completedFuture(new PlayerProfile(tag.getString("Name"), uuid, properties)); + return CompletableFuture.completedFuture( + new PlayerProfile(tag.getString("Name"), uuid, properties)); } else { - return ProfileCache.getProfile(uuid) - .thenApplyAsync((profile) -> new PlayerProfile(profile.getName(), uuid, properties)); + return ProfileCache.getProfile(uuid).thenApplyAsync( + (profile) -> new PlayerProfile(profile.getName(), uuid, properties)); } } + /** + * Reads a PlayerProfile from a JSON object. + * + * @param json a player profile in JSON form + * @return {@code json} as a PlayerProfile + */ public static PlayerProfile fromJson(JSONObject json) { String name = (String) json.get("name"); String id = (String) json.get("id"); @@ -139,7 +147,12 @@ public static PlayerProfile fromJson(JSONObject json) { return new PlayerProfile(name, uuid, properties); } - public CompoundTag toNBT() { + /** + * Converts this player profile to an NBT compound tag. + * + * @return an NBT compound tag that's a copy of this player profile + */ + public CompoundTag toNbt() { CompoundTag profileTag = new CompoundTag(); profileTag.putString("Id", uniqueId.toString()); profileTag.putString("Name", name); diff --git a/src/main/java/net/glowstone/entity/meta/profile/PlayerProperty.java b/src/main/java/net/glowstone/entity/meta/profile/PlayerProperty.java index 6dab5849b2..abe3a682eb 100644 --- a/src/main/java/net/glowstone/entity/meta/profile/PlayerProperty.java +++ b/src/main/java/net/glowstone/entity/meta/profile/PlayerProperty.java @@ -29,14 +29,28 @@ public class PlayerProperty { * The signature of the value for validation. */ @Getter - private String signature; + private final String signature; + /** + * Creates a non-secure instance. + * + * @param name the property name + * @param value the property value + */ public PlayerProperty(String name, String value) { this.name = name; this.value = value; isSigned = false; + signature = null; } + /** + * Creates a signed instance. + * + * @param name the property name + * @param value the property value + * @param signature the signature + */ public PlayerProperty(String name, String value, String signature) { this.name = name; this.value = value; diff --git a/src/main/java/net/glowstone/entity/meta/profile/ProfileCache.java b/src/main/java/net/glowstone/entity/meta/profile/ProfileCache.java index 9d8940e232..ba6322ab07 100644 --- a/src/main/java/net/glowstone/entity/meta/profile/ProfileCache.java +++ b/src/main/java/net/glowstone/entity/meta/profile/ProfileCache.java @@ -35,12 +35,12 @@ public static CompletableFuture getProfile(UUID uuid) { * @param playerName The name to look up. * @return A UUID future, UUID may be null on failure. */ - public static CompletableFuture getUUID(String playerName) { + public static CompletableFuture getUuid(String playerName) { if (uuidCache.containsKey(playerName)) { return CompletableFuture.completedFuture(uuidCache.get(playerName)); } CompletableFuture uuidFuture = CompletableFuture - .supplyAsync(() -> PlayerDataFetcher.getUUID(playerName)); + .supplyAsync(() -> PlayerDataFetcher.getUuid(playerName)); uuidFuture.thenAccept(uid -> uuidCache.put(playerName, uid)); return uuidFuture; } diff --git a/src/main/java/net/glowstone/entity/monster/GlowCreeper.java b/src/main/java/net/glowstone/entity/monster/GlowCreeper.java index d29e2d5bec..bf79b48ba3 100644 --- a/src/main/java/net/glowstone/entity/monster/GlowCreeper.java +++ b/src/main/java/net/glowstone/entity/monster/GlowCreeper.java @@ -2,6 +2,8 @@ import com.flowpowered.network.Message; import java.util.List; +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.meta.MetadataIndex; import org.bukkit.Location; import org.bukkit.Sound; @@ -12,8 +14,14 @@ public class GlowCreeper extends GlowMonster implements Creeper { + @Getter + @Setter private int explosionRadius; - private int fuse; + @Getter + @Setter + private int maxFuseTicks; + @Getter + @Setter private boolean ignited; public GlowCreeper(Location loc) { @@ -37,34 +45,6 @@ public void setPowered(boolean value) { metadata.set(MetadataIndex.CREEPER_POWERED, value); } - @Override - public int getExplosionRadius() { - return explosionRadius; - } - - @Override - public void setExplosionRadius(int explosionRadius) { - this.explosionRadius = explosionRadius; - } - - @Override - public int getMaxFuseTicks() { - return fuse; - } - - @Override - public void setMaxFuseTicks(int fuse) { - this.fuse = fuse; - } - - public boolean isIgnited() { - return ignited; - } - - public void setIgnited(boolean ignited) { - this.ignited = ignited; - } - @Override protected Sound getDeathSound() { return Sound.ENTITY_CREEPER_DEATH; diff --git a/src/main/java/net/glowstone/entity/monster/GlowEnderman.java b/src/main/java/net/glowstone/entity/monster/GlowEnderman.java index fe22f3f7b0..5a12aab6fb 100644 --- a/src/main/java/net/glowstone/entity/monster/GlowEnderman.java +++ b/src/main/java/net/glowstone/entity/monster/GlowEnderman.java @@ -1,5 +1,6 @@ package net.glowstone.entity.monster; +import lombok.Getter; import net.glowstone.entity.meta.MetadataIndex; import org.bukkit.Location; import org.bukkit.Material; @@ -10,6 +11,7 @@ public class GlowEnderman extends GlowMonster implements Enderman { + @Getter private MaterialData carriedMaterial = new MaterialData(Material.AIR); public GlowEnderman(Location loc) { @@ -17,11 +19,6 @@ public GlowEnderman(Location loc) { setBoundingBox(0.6, 2.9); } - @Override - public MaterialData getCarriedMaterial() { - return carriedMaterial; - } - @Override public void setCarriedMaterial(MaterialData type) { carriedMaterial = type; diff --git a/src/main/java/net/glowstone/entity/monster/GlowGhast.java b/src/main/java/net/glowstone/entity/monster/GlowGhast.java index c79674cc00..f8b2ef169a 100644 --- a/src/main/java/net/glowstone/entity/monster/GlowGhast.java +++ b/src/main/java/net/glowstone/entity/monster/GlowGhast.java @@ -1,5 +1,7 @@ package net.glowstone.entity.monster; +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.meta.MetadataIndex; import org.bukkit.Location; import org.bukkit.Sound; @@ -8,6 +10,8 @@ public class GlowGhast extends GlowMonster implements Ghast { + @Getter + @Setter private int explosionPower; public GlowGhast(Location loc) { @@ -15,14 +19,6 @@ public GlowGhast(Location loc) { setBoundingBox(4, 4); } - public int getExplosionPower() { - return explosionPower; - } - - public void setExplosionPower(int explosionPower) { - this.explosionPower = explosionPower; - } - public boolean isAttacking() { return metadata.getBoolean(MetadataIndex.GHAST_ATTACKING); } diff --git a/src/main/java/net/glowstone/entity/monster/GlowPigZombie.java b/src/main/java/net/glowstone/entity/monster/GlowPigZombie.java index e47321f698..cb3a40c84d 100644 --- a/src/main/java/net/glowstone/entity/monster/GlowPigZombie.java +++ b/src/main/java/net/glowstone/entity/monster/GlowPigZombie.java @@ -2,6 +2,8 @@ import java.util.Random; import java.util.UUID; +import lombok.Getter; +import lombok.Setter; import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.EntityType; @@ -10,23 +12,17 @@ public class GlowPigZombie extends GlowZombie implements PigZombie { + @Getter + @Setter private int anger; + @Getter + @Setter private UUID hurtBy; public GlowPigZombie(Location loc) { super(loc, EntityType.PIG_ZOMBIE); } - @Override - public int getAnger() { - return anger; - } - - @Override - public void setAnger(int level) { - anger = level; - } - @Override public boolean isAngry() { return anger > 0; @@ -41,14 +37,6 @@ public void setAngry(boolean angry) { } } - public UUID getHurtBy() { - return hurtBy; - } - - public void setHurtBy(UUID hurtBy) { - this.hurtBy = hurtBy; - } - @Override protected Sound getHurtSound() { return Sound.ENTITY_ZOMBIE_PIG_HURT; diff --git a/src/main/java/net/glowstone/entity/monster/GlowShulker.java b/src/main/java/net/glowstone/entity/monster/GlowShulker.java index 38a042a87d..53f782c3b5 100644 --- a/src/main/java/net/glowstone/entity/monster/GlowShulker.java +++ b/src/main/java/net/glowstone/entity/monster/GlowShulker.java @@ -1,5 +1,6 @@ package net.glowstone.entity.monster; +import lombok.Getter; import net.glowstone.entity.meta.MetadataIndex; import org.bukkit.DyeColor; import org.bukkit.Location; @@ -10,18 +11,29 @@ public class GlowShulker extends GlowMonster implements Shulker { + @Getter private Location attachment; + /** + * Creates a shulker facing down. + * + * @param loc the location + */ public GlowShulker(Location loc) { - super(loc, EntityType.SHULKER, 30); - setDirection(Facing.DOWN); - setShieldHeight((byte) 0); - setAttachment(loc); + this(loc, Facing.DOWN); } + /** + * Creates a shulker facing the given direction. + * + * @param loc the location + * @param direction the direction to initially face + */ public GlowShulker(Location loc, Facing direction) { - this(loc); + super(loc, EntityType.SHULKER, 30); setDirection(direction); + setShieldHeight((byte) 0); + setAttachment(loc); } public Facing getFacingDirection() { @@ -40,10 +52,11 @@ public void setShieldHeight(byte shieldHeight) { this.metadata.set(MetadataIndex.SHULKER_SHIELD_HEIGHT, shieldHeight); } - public Location getAttachment() { - return attachment; - } - + /** + * Sets the point where this shulker is attached, or null to detach the shulker. + * + * @param attachment the new attachment point, or null to detach + */ public void setAttachment(Location attachment) { this.attachment = attachment; if (attachment != null) { diff --git a/src/main/java/net/glowstone/entity/monster/GlowSlime.java b/src/main/java/net/glowstone/entity/monster/GlowSlime.java index 3845ede9d5..1a75629e23 100644 --- a/src/main/java/net/glowstone/entity/monster/GlowSlime.java +++ b/src/main/java/net/glowstone/entity/monster/GlowSlime.java @@ -1,5 +1,7 @@ package net.glowstone.entity.monster; +import static com.google.common.base.Preconditions.checkArgument; + import java.util.concurrent.ThreadLocalRandom; import net.glowstone.entity.meta.MetadataIndex; import org.bukkit.Location; @@ -7,6 +9,7 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Slime; +// TODO: Split when killed public class GlowSlime extends GlowMonster implements Slime { private boolean onGround; @@ -17,26 +20,10 @@ public GlowSlime(Location loc) { protected GlowSlime(Location loc, EntityType type) { super(loc, type, 1); - byte size = 1; - double health = 1; - switch (ThreadLocalRandom.current().nextInt(3)) { - case 0: - size = 1; - health = 1; - break; - case 1: - size = 2; - health = 4; - break; - case 2: - size = 4; - health = 16; - break; - } - setBoundingBox(0.51000005 * size, 0.51000005 * size); + int size = 1 + ThreadLocalRandom.current().nextInt(3); + setMaxHealth(size * size); // max health = size^2 + setHealth(maxHealth); // reset health to max setSize(size); - setMaxHealth(health); - setHealth(health); } @Override @@ -45,8 +32,10 @@ public int getSize() { } @Override - public void setSize(int sz) { - metadata.set(MetadataIndex.SLIME_SIZE, sz); + public void setSize(int size) { + checkArgument(size > 0); + metadata.set(MetadataIndex.SLIME_SIZE, size); + setBoundingBox(0.51000005 * size, 0.51000005 * size); } @Override diff --git a/src/main/java/net/glowstone/entity/monster/GlowVex.java b/src/main/java/net/glowstone/entity/monster/GlowVex.java index 77c83ee076..aaf4f24442 100644 --- a/src/main/java/net/glowstone/entity/monster/GlowVex.java +++ b/src/main/java/net/glowstone/entity/monster/GlowVex.java @@ -1,6 +1,8 @@ package net.glowstone.entity.monster; import java.util.concurrent.ThreadLocalRandom; +import lombok.Getter; +import lombok.Setter; import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.EntityType; @@ -8,8 +10,15 @@ public class GlowVex extends GlowMonster implements Vex { + @Getter + @Setter private int lifeTicks; + /** + * Creates a vex with a random lifespan. + * + * @param loc the location + */ public GlowVex(Location loc) { super(loc, EntityType.VEX, 14); ThreadLocalRandom random = ThreadLocalRandom.current(); @@ -27,14 +36,6 @@ public void pulse() { } } - public int getLifeTicks() { - return lifeTicks; - } - - public void setLifeTicks(int lifeTicks) { - this.lifeTicks = lifeTicks; - } - @Override protected Sound getDeathSound() { return Sound.ENTITY_VEX_DEATH; diff --git a/src/main/java/net/glowstone/entity/monster/GlowWither.java b/src/main/java/net/glowstone/entity/monster/GlowWither.java index 4905ea6da0..2ea2e5f38e 100644 --- a/src/main/java/net/glowstone/entity/monster/GlowWither.java +++ b/src/main/java/net/glowstone/entity/monster/GlowWither.java @@ -1,5 +1,6 @@ package net.glowstone.entity.monster; +import lombok.Getter; import net.glowstone.Explosion; import net.glowstone.entity.meta.MetadataIndex; import org.bukkit.Location; @@ -14,9 +15,20 @@ public class GlowWither extends GlowBoss implements Wither { + @Getter private int invulnerableTicks; - private Entity centerTarget, leftTarget, rightTarget; - + @Getter + private Entity centerTarget; + @Getter + private Entity leftTarget; + @Getter + private Entity rightTarget; + + /** + * Creates a wither. + * + * @param loc the location + */ public GlowWither(Location loc) { super(loc, EntityType.WITHER, 300, "Wither", BarColor.BLUE, BarStyle.SOLID); setInvulnerableTicks(220); @@ -34,43 +46,43 @@ public void damage(double amount, Entity source, EntityDamageEvent.DamageCause c super.damage(amount, source, cause); } - public int getInvulnerableTicks() { - return invulnerableTicks; - } - public void setInvulnerableTicks(int invulnerableTicks) { this.invulnerableTicks = invulnerableTicks; this.metadata.set(MetadataIndex.WITHER_INVULN_TIME, invulnerableTicks); } - public Entity getCenterTarget() { - return centerTarget; - } - + /** + * Sets the center target. + * + * @param centerTarget the new center target + */ public void setCenterTarget(Entity centerTarget) { this.centerTarget = centerTarget; - this.metadata.set(MetadataIndex.WITHER_TARGET_1, - centerTarget == null ? 0 : centerTarget.getEntityId()); + setTargetMetadata(centerTarget, MetadataIndex.WITHER_TARGET_1); } - public Entity getLeftTarget() { - return leftTarget; + private void setTargetMetadata(Entity target, MetadataIndex index) { + this.metadata.set(index, target == null ? 0 : target.getEntityId()); } + /** + * Sets the left target. + * + * @param leftTarget the new left target + */ public void setLeftTarget(Entity leftTarget) { this.leftTarget = leftTarget; - this.metadata - .set(MetadataIndex.WITHER_TARGET_2, leftTarget == null ? 0 : leftTarget.getEntityId()); - } - - public Entity getRightTarget() { - return rightTarget; + setTargetMetadata(leftTarget, MetadataIndex.WITHER_TARGET_2); } + /** + * Sets the right target. + * + * @param rightTarget the new right target + */ public void setRightTarget(Entity rightTarget) { this.rightTarget = rightTarget; - this.metadata.set(MetadataIndex.WITHER_TARGET_3, - rightTarget == null ? 0 : rightTarget.getEntityId()); + setTargetMetadata(rightTarget, MetadataIndex.WITHER_TARGET_3); } @Override diff --git a/src/main/java/net/glowstone/entity/monster/GlowZombie.java b/src/main/java/net/glowstone/entity/monster/GlowZombie.java index 91b36e50d2..3df0be2b96 100644 --- a/src/main/java/net/glowstone/entity/monster/GlowZombie.java +++ b/src/main/java/net/glowstone/entity/monster/GlowZombie.java @@ -17,10 +17,21 @@ public class GlowZombie extends GlowMonster implements Zombie { private boolean canBreakDoors; + /** + * Creates a zombie. + * + * @param loc the location + */ public GlowZombie(Location loc) { this(loc, EntityType.ZOMBIE); } + /** + * Creates a zombie. + * + * @param loc the location + * @param type the zombie type + */ public GlowZombie(Location loc, EntityType type) { super(loc, type, 20); setBoundingBox(0.6, 1.8); diff --git a/src/main/java/net/glowstone/entity/monster/GlowZombieVillager.java b/src/main/java/net/glowstone/entity/monster/GlowZombieVillager.java index 671048dba3..11a801f068 100644 --- a/src/main/java/net/glowstone/entity/monster/GlowZombieVillager.java +++ b/src/main/java/net/glowstone/entity/monster/GlowZombieVillager.java @@ -1,5 +1,10 @@ package net.glowstone.entity.monster; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.meta.MetadataIndex; import org.bukkit.Location; import org.bukkit.Sound; @@ -9,20 +14,42 @@ public class GlowZombieVillager extends GlowZombie implements ZombieVillager { + /** + * The {@link UUID} of the player who converted this Zombie Villager. + */ + @Getter + @Setter + private UUID conversionPlayer; + /** + * The conversion time of this Zombie Villager, in ticks. + * + * @return the conversion time of this Zombie Villager, in ticks + */ + @Getter + private int conversionTime; + + /** + * Creates a zombie villager that is a farmer. + * + * @param loc the initial location + */ public GlowZombieVillager(Location loc) { super(loc, EntityType.ZOMBIE_VILLAGER); setBoundingBox(0.6, 1.95); + setConversionTime(-1); + setVillagerProfession(Villager.Profession.FARMER); } @Override public Villager.Profession getVillagerProfession() { - int profession = metadata.containsKey(MetadataIndex.ZOMBIE_VILLAGER_PROFESSION) ? metadata - .getInt(MetadataIndex.ZOMBIE_VILLAGER_PROFESSION) : 0; + int profession = metadata.containsKey(MetadataIndex.ZOMBIE_VILLAGER_PROFESSION) + ? metadata.getInt(MetadataIndex.ZOMBIE_VILLAGER_PROFESSION) : 0; return Villager.Profession.values()[profession]; } @Override public void setVillagerProfession(Villager.Profession profession) { + checkNotNull(profession); metadata.set(MetadataIndex.ZOMBIE_VILLAGER_PROFESSION, profession.ordinal()); } @@ -40,4 +67,14 @@ protected Sound getDeathSound() { protected Sound getAmbientSound() { return Sound.ENTITY_ZOMBIE_VILLAGER_AMBIENT; } + + /** + * Sets the conversion time of this Zombie Villager. + * + * @param conversionTime the conversion time of this villager, in ticks + */ + public void setConversionTime(int conversionTime) { + this.conversionTime = Math.max(-1, conversionTime); + metadata.set(MetadataIndex.ZOMBIE_VILLAGER_IS_CONVERTING, this.conversionTime != -1); + } } diff --git a/src/main/java/net/glowstone/entity/monster/complex/GlowEnderDragonPart.java b/src/main/java/net/glowstone/entity/monster/complex/GlowEnderDragonPart.java index 5e0b01bea9..562ed8d0d4 100644 --- a/src/main/java/net/glowstone/entity/monster/complex/GlowEnderDragonPart.java +++ b/src/main/java/net/glowstone/entity/monster/complex/GlowEnderDragonPart.java @@ -3,6 +3,7 @@ import com.flowpowered.network.Message; import java.util.Collections; import java.util.List; +import lombok.Getter; import net.glowstone.entity.GlowEntity; import org.bukkit.entity.EnderDragon; import org.bukkit.entity.EnderDragonPart; @@ -11,6 +12,7 @@ public class GlowEnderDragonPart extends GlowEntity implements EnderDragonPart { + @Getter private EnderDragon parent; public GlowEnderDragonPart(EnderDragon parent) { @@ -18,11 +20,6 @@ public GlowEnderDragonPart(EnderDragon parent) { this.parent = parent; } - @Override - public EnderDragon getParent() { - return parent; - } - @Override public List createSpawnMessage() { return Collections.emptyList(); diff --git a/src/main/java/net/glowstone/entity/objects/GlowArmorStand.java b/src/main/java/net/glowstone/entity/objects/GlowArmorStand.java index 4b479e0dc1..03222b3065 100644 --- a/src/main/java/net/glowstone/entity/objects/GlowArmorStand.java +++ b/src/main/java/net/glowstone/entity/objects/GlowArmorStand.java @@ -356,16 +356,18 @@ public boolean canTakeDamage(DamageCause cause) { public List createSpawnMessage() { return Arrays.asList( - new SpawnObjectMessage(id, UUID.randomUUID(), 78, location), + new SpawnObjectMessage(entityId, UUID.randomUUID(), 78, location), // TODO: once UUID is documented, actually use the appropriate ID here - new EntityMetadataMessage(id, metadata.getEntryList()), - new EntityEquipmentMessage(id, EntityEquipmentMessage.HELD_ITEM, getItemInHand()), - new EntityEquipmentMessage(id, EntityEquipmentMessage.OFF_HAND, + new EntityMetadataMessage(entityId, metadata.getEntryList()), + new EntityEquipmentMessage(entityId, EntityEquipmentMessage.HELD_ITEM, getItemInHand()), + new EntityEquipmentMessage(entityId, EntityEquipmentMessage.OFF_HAND, equipment.getItemInOffHand()), - new EntityEquipmentMessage(id, EntityEquipmentMessage.BOOTS_SLOT, getBoots()), - new EntityEquipmentMessage(id, EntityEquipmentMessage.LEGGINGS_SLOT, getLeggings()), - new EntityEquipmentMessage(id, EntityEquipmentMessage.CHESTPLATE_SLOT, getChestplate()), - new EntityEquipmentMessage(id, EntityEquipmentMessage.HELMET_SLOT, getHelmet()) + new EntityEquipmentMessage(entityId, EntityEquipmentMessage.BOOTS_SLOT, getBoots()), + new EntityEquipmentMessage(entityId, EntityEquipmentMessage.LEGGINGS_SLOT, + getLeggings()), + new EntityEquipmentMessage(entityId, EntityEquipmentMessage.CHESTPLATE_SLOT, + getChestplate()), + new EntityEquipmentMessage(entityId, EntityEquipmentMessage.HELMET_SLOT, getHelmet()) ); } @@ -373,7 +375,7 @@ public List createSpawnMessage() { public List createUpdateMessage(GlowSession session) { List messages = super.createUpdateMessage(session); if (needsKill) { - messages.add(new DestroyEntitiesMessage(Collections.singletonList(id))); + messages.add(new DestroyEntitiesMessage(Collections.singletonList(entityId))); } return messages; diff --git a/src/main/java/net/glowstone/entity/objects/GlowBoat.java b/src/main/java/net/glowstone/entity/objects/GlowBoat.java index dedd004825..2e80b35b93 100644 --- a/src/main/java/net/glowstone/entity/objects/GlowBoat.java +++ b/src/main/java/net/glowstone/entity/objects/GlowBoat.java @@ -3,6 +3,7 @@ import com.flowpowered.network.Message; import java.util.Arrays; import java.util.List; +import lombok.Getter; import net.glowstone.EventFactory; import net.glowstone.entity.GlowEntity; import net.glowstone.entity.GlowPlayer; @@ -25,6 +26,7 @@ public class GlowBoat extends GlowEntity implements Boat { + @Getter private TreeSpecies woodType; private boolean workOnLand; @@ -47,8 +49,8 @@ public EntityType getType() { @Override public List createSpawnMessage() { return Arrays.asList( - new SpawnObjectMessage(id, getUniqueId(), SpawnObjectMessage.BOAT, location), - new EntityMetadataMessage(id, metadata.getEntryList()) + new SpawnObjectMessage(entityId, getUniqueId(), SpawnObjectMessage.BOAT, location), + new EntityMetadataMessage(entityId, metadata.getEntryList()) ); } @@ -146,11 +148,6 @@ private void setHitTime(int time) { metadata.set(MetadataIndex.BOAT_HIT_TIME, Math.max(time, 0)); } - @Override - public TreeSpecies getWoodType() { - return woodType; - } - @Override public void setWoodType(TreeSpecies treeSpecies) { this.woodType = treeSpecies; diff --git a/src/main/java/net/glowstone/entity/objects/GlowEnderCrystal.java b/src/main/java/net/glowstone/entity/objects/GlowEnderCrystal.java index 43f2a0d559..27e802ea6c 100644 --- a/src/main/java/net/glowstone/entity/objects/GlowEnderCrystal.java +++ b/src/main/java/net/glowstone/entity/objects/GlowEnderCrystal.java @@ -46,8 +46,9 @@ public EntityType getType() { @Override public List createSpawnMessage() { return Arrays.asList( - new SpawnObjectMessage(id, getUniqueId(), SpawnObjectMessage.ENDER_CRYSTAL, location), - new EntityMetadataMessage(id, metadata.getEntryList()) + new SpawnObjectMessage(entityId, + getUniqueId(), SpawnObjectMessage.ENDER_CRYSTAL, location), + new EntityMetadataMessage(entityId, metadata.getEntryList()) ); } diff --git a/src/main/java/net/glowstone/entity/objects/GlowEnderPearl.java b/src/main/java/net/glowstone/entity/objects/GlowEnderPearl.java index c6a22827dc..53cdcdd901 100644 --- a/src/main/java/net/glowstone/entity/objects/GlowEnderPearl.java +++ b/src/main/java/net/glowstone/entity/objects/GlowEnderPearl.java @@ -3,6 +3,8 @@ import com.flowpowered.network.Message; import java.util.Arrays; import java.util.List; +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.GlowEntity; import net.glowstone.net.message.play.entity.EntityMetadataMessage; import net.glowstone.net.message.play.entity.EntityTeleportMessage; @@ -16,6 +18,8 @@ public class GlowEnderPearl extends GlowEntity implements EnderPearl { + @Getter + @Setter private ProjectileSource shooter; private float speed; @@ -39,21 +43,11 @@ public boolean doesBounce() { return false; } - @Override - public ProjectileSource getShooter() { - return this.shooter; - } - @Override public void setBounce(boolean bounce) { // TODO: Auto-generated method stub } - @Override - public void setShooter(ProjectileSource source) { - this.shooter = source; - } - @Override protected void pulsePhysics() { velocity.setY(airDrag * (velocity.getY() + getGravityAccel().getY())); @@ -75,11 +69,11 @@ protected void pulsePhysics() { public List createSpawnMessage() { return Arrays.asList( new SpawnObjectMessage( - id, getUniqueId(), SpawnObjectMessage.THROWN_ENDERPEARL, location), - new EntityMetadataMessage(id, metadata.getEntryList()), + entityId, getUniqueId(), SpawnObjectMessage.THROWN_ENDERPEARL, location), + new EntityMetadataMessage(entityId, metadata.getEntryList()), // These keep the client from assigning a random velocity - new EntityTeleportMessage(id, location), - new EntityVelocityMessage(id, getVelocity()) + new EntityTeleportMessage(entityId, location), + new EntityVelocityMessage(entityId, getVelocity()) ); } } diff --git a/src/main/java/net/glowstone/entity/objects/GlowEvokerFangs.java b/src/main/java/net/glowstone/entity/objects/GlowEvokerFangs.java index 5ba3d27c48..03dd33596e 100644 --- a/src/main/java/net/glowstone/entity/objects/GlowEvokerFangs.java +++ b/src/main/java/net/glowstone/entity/objects/GlowEvokerFangs.java @@ -4,6 +4,8 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.GlowEntity; import net.glowstone.net.message.play.entity.SpawnObjectMessage; import net.glowstone.util.Position; @@ -14,6 +16,8 @@ public class GlowEvokerFangs extends GlowEntity implements EvokerFangs { + @Getter + @Setter private LivingEntity owner; public GlowEvokerFangs(Location location) { @@ -29,21 +33,11 @@ public List createSpawnMessage() { double z = location.getZ(); int yaw = Position.getIntYaw(location); int pitch = Position.getIntPitch(location); - result.add( - new SpawnObjectMessage(id, UUID.randomUUID(), 79, x, y, z, pitch, yaw, 0, 0, 0, 0)); + result.add(new SpawnObjectMessage( + entityId, UUID.randomUUID(), 79, x, y, z, pitch, yaw, 0, 0, 0, 0)); return result; } - @Override - public LivingEntity getOwner() { - return owner; - } - - @Override - public void setOwner(LivingEntity owner) { - this.owner = owner; - } - @Override public EntityType getType() { return EntityType.EVOKER_FANGS; diff --git a/src/main/java/net/glowstone/entity/objects/GlowExperienceOrb.java b/src/main/java/net/glowstone/entity/objects/GlowExperienceOrb.java index bad68e50fe..e4bbd2be35 100644 --- a/src/main/java/net/glowstone/entity/objects/GlowExperienceOrb.java +++ b/src/main/java/net/glowstone/entity/objects/GlowExperienceOrb.java @@ -5,6 +5,10 @@ import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.UUID; + +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.GlowEntity; import net.glowstone.net.message.play.entity.DestroyEntitiesMessage; import net.glowstone.net.message.play.entity.SpawnXpOrbMessage; @@ -14,13 +18,26 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.ExperienceOrb; import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.EntityDamageEvent; public class GlowExperienceOrb extends GlowEntity implements ExperienceOrb { private static final int LIFETIME = 5 * 60 * 20; + @Getter + @Setter private boolean fromBottle; + @Getter + @Setter + private UUID sourceEntityId; + @Getter + @Setter + private UUID triggerEntityId; + @Getter + @Setter + private CreatureSpawnEvent.SpawnReason spawnReason; + @Getter private int experience; private boolean tickSkipped = false; @@ -91,11 +108,6 @@ private void refresh() { .forEach(p -> p.getSession().sendAll(messages)); } - @Override - public int getExperience() { - return experience; - } - @Override public void setExperience(int experience) { Preconditions.checkArgument(experience > 0, "Experience points cannot be negative."); @@ -103,15 +115,6 @@ public void setExperience(int experience) { refresh(); } - @Override - public boolean isFromBottle() { - return fromBottle; - } - - public void setFromBottle(boolean fromBottle) { - this.fromBottle = fromBottle; - } - @Override public EntityType getType() { return EntityType.EXPERIENCE_ORB; diff --git a/src/main/java/net/glowstone/entity/objects/GlowFallingBlock.java b/src/main/java/net/glowstone/entity/objects/GlowFallingBlock.java index 9255b4e216..77c1dac039 100644 --- a/src/main/java/net/glowstone/entity/objects/GlowFallingBlock.java +++ b/src/main/java/net/glowstone/entity/objects/GlowFallingBlock.java @@ -4,6 +4,8 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.ThreadLocalRandom; +import lombok.Getter; +import lombok.Setter; import net.glowstone.block.GlowBlock; import net.glowstone.block.entity.BlockEntity; import net.glowstone.entity.GlowEntity; @@ -19,11 +21,18 @@ public class GlowFallingBlock extends GlowEntity implements FallingBlock { + @Getter + @Setter private Material material; private boolean canHurtEntities; + @Setter private boolean dropItem; + @Getter + @Setter private byte blockData; private Location sourceLocation; + @Getter + @Setter private CompoundTag blockEntityCompoundTag; // todo: implement falling block damage @@ -66,25 +75,6 @@ public GlowFallingBlock(Location location, Material material, byte blockData, this.blockData = blockData; } - @Override - public Material getMaterial() { - return material; - } - - public void setMaterial(Material material) { - this.material = material; - } - - @Override - public boolean getDropItem() { - return dropItem; - } - - @Override - public void setDropItem(boolean dropItem) { - this.dropItem = dropItem; - } - @Override public boolean canHurtEntities() { return canHurtEntities; @@ -96,25 +86,13 @@ public void setHurtEntities(boolean canHurtEntities) { } @Override - public byte getBlockData() { - return blockData; - } - - public void setBlockData(byte blockData) { - this.blockData = blockData; - } - - public CompoundTag getBlockEntityCompoundTag() { - return blockEntityCompoundTag; - } - - public void setBlockEntityCompoundTag(CompoundTag blockEntityCompoundTag) { - this.blockEntityCompoundTag = blockEntityCompoundTag; + public int getBlockId() { + return material.getId(); } @Override - public int getBlockId() { - return material.getId(); + public boolean getDropItem() { + return dropItem; } @Override @@ -125,7 +103,7 @@ public List createSpawnMessage() { int blockIdData = getBlockId() | getBlockData() << 12; return Collections.singletonList( - new SpawnObjectMessage(id, getUniqueId(), 70, location, blockIdData) + new SpawnObjectMessage(entityId, getUniqueId(), 70, location, blockIdData) ); } @@ -168,11 +146,6 @@ protected void pulsePhysics() { remove(); } else { placeFallingBlock(); - if (material == Material.ANVIL) { - ThreadLocalRandom random = ThreadLocalRandom.current(); - world.playSound(location, Sound.BLOCK_ANVIL_FALL, 4, (1.0F - + (random.nextFloat() - random.nextFloat()) * 0.2F) * 0.7F); - } remove(); } } @@ -191,6 +164,11 @@ private void placeFallingBlock() { } } } + if (material == Material.ANVIL) { + ThreadLocalRandom random = ThreadLocalRandom.current(); + world.playSound(location, Sound.BLOCK_ANVIL_FALL, 4, (1.0F + + (random.nextFloat() - random.nextFloat()) * 0.2F) * 0.7F); + } } diff --git a/src/main/java/net/glowstone/entity/objects/GlowItem.java b/src/main/java/net/glowstone/entity/objects/GlowItem.java index 04e85abafc..de25eba14d 100644 --- a/src/main/java/net/glowstone/entity/objects/GlowItem.java +++ b/src/main/java/net/glowstone/entity/objects/GlowItem.java @@ -161,11 +161,11 @@ protected void pulsePhysics() { @Override public List createSpawnMessage() { return Arrays.asList( - new SpawnObjectMessage(id, getUniqueId(), SpawnObjectMessage.ITEM, location), - new EntityMetadataMessage(id, metadata.getEntryList()), + new SpawnObjectMessage(entityId, getUniqueId(), SpawnObjectMessage.ITEM, location), + new EntityMetadataMessage(entityId, metadata.getEntryList()), // these keep the client from assigning a random velocity - new EntityTeleportMessage(id, location), - new EntityVelocityMessage(id, getVelocity()) + new EntityTeleportMessage(entityId, location), + new EntityVelocityMessage(entityId, getVelocity()) ); } diff --git a/src/main/java/net/glowstone/entity/objects/GlowItemFrame.java b/src/main/java/net/glowstone/entity/objects/GlowItemFrame.java index 1eca2ecdf1..97ede6e577 100644 --- a/src/main/java/net/glowstone/entity/objects/GlowItemFrame.java +++ b/src/main/java/net/glowstone/entity/objects/GlowItemFrame.java @@ -139,10 +139,10 @@ public List createSpawnMessage() { int yaw = getYaw(); return Arrays.asList( - new SpawnObjectMessage(id, getUniqueId(), SpawnObjectMessage.ITEM_FRAME, + new SpawnObjectMessage(entityId, getUniqueId(), SpawnObjectMessage.ITEM_FRAME, location.getBlockX(), location.getBlockY(), location.getBlockZ(), 0, yaw, HangingFace.getByBlockFace(getFacing()).ordinal()), - new EntityMetadataMessage(id, metadata.getEntryList()) + new EntityMetadataMessage(entityId, metadata.getEntryList()) ); } @@ -180,7 +180,7 @@ private void createTeleportMessage(BlockFace face) { double y = location.getY(); double z = location.getZ(); player.getSession() - .send(new EntityTeleportMessage(id, x + xoffset, y, z + zoffset, yaw, 0)); + .send(new EntityTeleportMessage(entityId, x + xoffset, y, z + zoffset, yaw, 0)); } } } diff --git a/src/main/java/net/glowstone/entity/objects/GlowLeashHitch.java b/src/main/java/net/glowstone/entity/objects/GlowLeashHitch.java index 279f7afd84..5775da2163 100644 --- a/src/main/java/net/glowstone/entity/objects/GlowLeashHitch.java +++ b/src/main/java/net/glowstone/entity/objects/GlowLeashHitch.java @@ -107,9 +107,9 @@ public List createSpawnMessage() { int z = location.getBlockZ(); return Lists.newArrayList( - new SpawnObjectMessage(id, getUniqueId(), SpawnObjectMessage.LEASH_HITCH, x, y, z, 0, - 0), - new EntityMetadataMessage(id, metadata.getEntryList()) + new SpawnObjectMessage( + entityId, getUniqueId(), SpawnObjectMessage.LEASH_HITCH, x, y, z, 0, 0), + new EntityMetadataMessage(entityId, metadata.getEntryList()) ); } diff --git a/src/main/java/net/glowstone/entity/objects/GlowMinecart.java b/src/main/java/net/glowstone/entity/objects/GlowMinecart.java index 7d474c38b6..48d2e243a4 100644 --- a/src/main/java/net/glowstone/entity/objects/GlowMinecart.java +++ b/src/main/java/net/glowstone/entity/objects/GlowMinecart.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.function.Function; import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.Setter; import net.glowstone.entity.GlowEntity; import net.glowstone.entity.GlowPlayer; @@ -80,8 +81,8 @@ public static GlowMinecart create(Location location, MinecartType minecartType) @Override public List createSpawnMessage() { - return Collections.singletonList( - new SpawnObjectMessage(id, getUniqueId(), 10, location, minecartType.ordinal())); + return Collections.singletonList(new SpawnObjectMessage( + entityId, getUniqueId(), 10, location, minecartType.ordinal())); } @Override @@ -107,15 +108,17 @@ public boolean entityInteract(GlowPlayer player, InteractEntityMessage message) return true; } + @RequiredArgsConstructor public enum MinecartType { RIDEABLE(Rideable.class, EntityType.MINECART, RideableMinecart.class, Rideable::new), CHEST(Storage.class, EntityType.MINECART_CHEST, StorageMinecart.class, Storage::new), FURNACE(Powered.class, EntityType.MINECART_FURNACE, PoweredMinecart.class, Powered ::new), TNT(Explosive.class, EntityType.MINECART_TNT, ExplosiveMinecart.class, Explosive::new), - SPAWNER(Spawner.class, EntityType.MINECART_MOB_SPAWNER, SpawnerMinecart.class, Spawner::new), + SPAWNER(Spawner.class, EntityType.MINECART_MOB_SPAWNER, SpawnerMinecart.class, + Spawner::new), HOPPER(Hopper.class, EntityType.MINECART_HOPPER, HopperMinecart.class, Hopper::new), - COMMAND(Command.class, EntityType.MINECART_COMMAND, CommandMinecart.class, Command::new); // todo + COMMAND(Command.class, EntityType.MINECART_COMMAND, CommandMinecart.class, Command::new); @Getter private final Class minecartClass; @@ -125,15 +128,6 @@ public enum MinecartType { private final Class entityClass; @Getter private final Function creator; - - MinecartType(Class minecartClass, EntityType entityType, - Class entityClass, - Function creator) { - this.minecartClass = minecartClass; - this.entityType = entityType; - this.entityClass = entityClass; - this.creator = creator; - } } public static class Rideable extends GlowMinecart implements RideableMinecart { @@ -162,8 +156,14 @@ public boolean entityInteract(GlowPlayer player, InteractEntityMessage message) public static class Storage extends GlowMinecart implements StorageMinecart { + @Getter private final Inventory inventory; + /** + * Creates a minecart with a chest. + * + * @param location the location. + */ public Storage(Location location) { super(location, MinecartType.CHEST); inventory = new GlowInventory(this, InventoryType.CHEST, @@ -182,11 +182,6 @@ public boolean entityInteract(GlowPlayer player, InteractEntityMessage message) player.openInventory(inventory); return true; } - - @Override - public Inventory getInventory() { - return inventory; - } } public static class Powered extends GlowMinecart implements PoweredMinecart { @@ -211,6 +206,11 @@ public static class Hopper extends GlowMinecart implements HopperMinecart { @Setter private boolean enabled = true; + /** + * Creates a minecart with a hopper. + * + * @param location the location + */ public Hopper(Location location) { super(location, MinecartType.HOPPER); inventory = new GlowInventory(this, InventoryType.HOPPER, diff --git a/src/main/java/net/glowstone/entity/objects/GlowPainting.java b/src/main/java/net/glowstone/entity/objects/GlowPainting.java index 83032ea38b..31d59469a7 100644 --- a/src/main/java/net/glowstone/entity/objects/GlowPainting.java +++ b/src/main/java/net/glowstone/entity/objects/GlowPainting.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import lombok.Getter; import net.glowstone.EventFactory; import net.glowstone.entity.GlowHangingEntity; import net.glowstone.entity.GlowPlayer; @@ -66,16 +67,24 @@ public class GlowPainting extends GlowHangingEntity implements Painting { TITLE_BY_ART.forEach((art, title) -> ART_BY_TITLE.put(title, art)); } + @Getter private Art art; - private Location center; + @Getter + private Location artCenter; public GlowPainting(Location center) { this(center, BlockFace.SOUTH); } + /** + * Creates a painting with the default art. + * + * @param center the center of the painting + * @param facing the direction for the painting to face + */ public GlowPainting(Location center, BlockFace facing) { super(center, facing); - this.center = center; + this.artCenter = center; setArtInternal(DEFAULT_ART); } @@ -109,9 +118,9 @@ public boolean entityInteract(GlowPlayer player, InteractEntityMessage message) @Override public List createSpawnMessage() { - int x = center.getBlockX(); - int y = center.getBlockY(); - int z = center.getBlockZ(); + int x = artCenter.getBlockX(); + int y = artCenter.getBlockY(); + int z = artCenter.getBlockZ(); String title = getArtTitle(); return Collections.singletonList( @@ -120,11 +129,6 @@ public List createSpawnMessage() { ); } - @Override - public Art getArt() { - return art; - } - @Override public boolean setArt(Art art) { return this.setArt(art, false); @@ -152,7 +156,8 @@ public boolean setArt(Art art, boolean force) { /** * Refreshes the painting for nearby clients. * - *

This will first destroy, and then spawn the painting again using its current art and facing value. + *

This will first destroy, and then spawn the painting again using its current art and + * facing value. */ public void refresh() { DestroyEntitiesMessage destroyMessage = new DestroyEntitiesMessage( @@ -301,7 +306,7 @@ private boolean canHoldPainting(Location where) { private Location getTopLeftCorner() { BlockFace left = getLeftFace(); - Location topLeft = center.clone(); + Location topLeft = artCenter.clone(); int topMod = (int) getArtHeight(); int widthMod = (int) getArtWidth(); @@ -337,10 +342,7 @@ private double getArtHeight() { return art.getBlockHeight() / 2; } - public Location getArtCenter() { - return this.center; - } - + @Override protected void updateBoundingBox() { BlockFace rightFace = getRightFace(); double modX = Math.abs(rightFace.getModX() * art.getBlockWidth()); @@ -370,9 +372,9 @@ protected void updateBoundingBox() { @Override public void setRawLocation(Location location, boolean fall) { // Also try to move the center of the painting along - Location difference = location.subtract(center); + Location difference = location.subtract(artCenter); super.setRawLocation(location, fall); - center = location.clone().subtract(difference); + artCenter = location.clone().subtract(difference); } } diff --git a/src/main/java/net/glowstone/entity/passive/GlowAbstractHorse.java b/src/main/java/net/glowstone/entity/passive/GlowAbstractHorse.java index 917e0f1eb1..f496b92a2c 100644 --- a/src/main/java/net/glowstone/entity/passive/GlowAbstractHorse.java +++ b/src/main/java/net/glowstone/entity/passive/GlowAbstractHorse.java @@ -2,6 +2,8 @@ import com.flowpowered.network.Message; import java.util.List; +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.meta.MetadataIndex; import net.glowstone.entity.meta.MetadataMap; import net.glowstone.net.message.play.entity.EntityMetadataMessage; @@ -14,9 +16,17 @@ public abstract class GlowAbstractHorse extends GlowTameable implements AbstractHorse { + @Getter + @Setter private int domestication; + @Getter + @Setter private int maxDomestication; + @Getter + @Setter private double jumpStrength; + @Getter + @Setter private boolean tamed; public GlowAbstractHorse(Location location, EntityType type, double maxHealth) { @@ -29,7 +39,7 @@ public List createSpawnMessage() { List messages = super.createSpawnMessage(); MetadataMap map = new MetadataMap(GlowHorse.class); map.set(MetadataIndex.ABSTRACT_HORSE_FLAGS, getHorseFlags()); - messages.add(new EntityMetadataMessage(id, map.getEntryList())); + messages.add(new EntityMetadataMessage(entityId, map.getEntryList())); return messages; } @@ -44,46 +54,6 @@ public void setVariant(Horse.Variant variant) { // Field has been removed in 1.11 } - @Override - public int getDomestication() { - return domestication; - } - - @Override - public void setDomestication(int domestication) { - this.domestication = domestication; - } - - @Override - public int getMaxDomestication() { - return maxDomestication; - } - - @Override - public void setMaxDomestication(int maxDomestication) { - this.maxDomestication = maxDomestication; - } - - @Override - public double getJumpStrength() { - return jumpStrength; - } - - @Override - public void setJumpStrength(double jumpStrength) { - this.jumpStrength = jumpStrength; - } - - @Override - public boolean isTamed() { - return tamed; - } - - @Override - public void setTamed(boolean tamed) { - this.tamed = tamed; - } - private int getHorseFlags() { int value = 0; if (isTamed()) { diff --git a/src/main/java/net/glowstone/entity/passive/GlowBat.java b/src/main/java/net/glowstone/entity/passive/GlowBat.java index d328fa4914..a09e15d83b 100644 --- a/src/main/java/net/glowstone/entity/passive/GlowBat.java +++ b/src/main/java/net/glowstone/entity/passive/GlowBat.java @@ -3,7 +3,6 @@ import com.flowpowered.network.Message; import java.util.LinkedList; import java.util.List; -import java.util.UUID; import net.glowstone.entity.GlowAmbient; import net.glowstone.entity.meta.MetadataIndex; import net.glowstone.net.message.play.entity.EntityHeadRotationMessage; @@ -26,22 +25,22 @@ public List createSpawnMessage() { List result = new LinkedList<>(); result.add(new SpawnMobMessage( - id, UUID.randomUUID(), getType().getTypeId(), location, metadata.getEntryList())); - //TODO 1.9 - Real UUID + entityId, getUniqueId(), getType().getTypeId(), location, + metadata.getEntryList())); // head facing - result.add(new EntityHeadRotationMessage(id, Position.getIntYaw(location))); + result.add(new EntityHeadRotationMessage(entityId, Position.getIntYaw(location))); return result; } @Override public boolean isAwake() { - return metadata.getByte(MetadataIndex.BAT_HANGING) == 1; + return !metadata.getBit(MetadataIndex.BAT_FLAGS, MetadataIndex.BatFlags.IS_HANGING); } @Override public void setAwake(boolean isAwake) { - metadata.set(MetadataIndex.BAT_HANGING, (byte) (isAwake ? 1 : 0)); + metadata.setBit(MetadataIndex.BAT_FLAGS, MetadataIndex.BatFlags.IS_HANGING, !isAwake); } @Override @@ -49,46 +48,6 @@ public EntityType getType() { return EntityType.BAT; } - @Override - public boolean isGliding() { - return false; - } - - @Override - public void setGliding(boolean b) { - - } - - @Override - public void setAI(boolean b) { - - } - - @Override - public boolean hasAI() { - return false; - } - - @Override - public boolean isCollidable() { - return false; - } - - @Override - public void setCollidable(boolean b) { - - } - - @Override - public int getArrowsStuck() { - return 0; - } - - @Override - public void setArrowsStuck(int i) { - - } - @Override protected Sound getHurtSound() { return Sound.ENTITY_BAT_HURT; diff --git a/src/main/java/net/glowstone/entity/passive/GlowChicken.java b/src/main/java/net/glowstone/entity/passive/GlowChicken.java index 70b40e7d21..c5a5df5942 100644 --- a/src/main/java/net/glowstone/entity/passive/GlowChicken.java +++ b/src/main/java/net/glowstone/entity/passive/GlowChicken.java @@ -1,6 +1,8 @@ package net.glowstone.entity.passive; import java.util.concurrent.ThreadLocalRandom; +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.GlowAnimal; import org.bukkit.Location; import org.bukkit.Material; @@ -11,7 +13,11 @@ public class GlowChicken extends GlowAnimal implements Chicken { + @Getter + @Setter private boolean chickenJockey; + @Getter + @Setter private int eggLayTime; /** @@ -25,22 +31,6 @@ public GlowChicken(Location location) { generateEggLayDelay(); } - public boolean isChickenJockey() { - return chickenJockey; - } - - public void setChickenJockey(boolean chickenJockey) { - this.chickenJockey = chickenJockey; - } - - public int getEggLayTime() { - return eggLayTime; - } - - public void setEggLayTime(int eggLayTime) { - this.eggLayTime = eggLayTime; - } - private void generateEggLayDelay() { setEggLayTime(ThreadLocalRandom.current().nextInt(20 * 60 * 5) + 20 * 60 * 5); } diff --git a/src/main/java/net/glowstone/entity/passive/GlowFirework.java b/src/main/java/net/glowstone/entity/passive/GlowFirework.java index 7f498b37d5..d15c13bb3c 100644 --- a/src/main/java/net/glowstone/entity/passive/GlowFirework.java +++ b/src/main/java/net/glowstone/entity/passive/GlowFirework.java @@ -84,9 +84,9 @@ public List createSpawnMessage() { double z = location.getZ(); return Arrays.asList( - new SpawnObjectMessage(id, UUID.randomUUID(), SpawnObjectMessage.FIREWORK, x, y, z, 0, - 0), - new EntityMetadataMessage(id, metadata.getEntryList()) + new SpawnObjectMessage( + entityId, UUID.randomUUID(), SpawnObjectMessage.FIREWORK, x, y, z, 0, 0), + new EntityMetadataMessage(entityId, metadata.getEntryList()) ); } diff --git a/src/main/java/net/glowstone/entity/passive/GlowHorse.java b/src/main/java/net/glowstone/entity/passive/GlowHorse.java index 154053192c..91a1a0fe60 100644 --- a/src/main/java/net/glowstone/entity/passive/GlowHorse.java +++ b/src/main/java/net/glowstone/entity/passive/GlowHorse.java @@ -3,6 +3,8 @@ import com.flowpowered.network.Message; import java.util.List; import java.util.Random; +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.meta.MetadataIndex; import net.glowstone.entity.meta.MetadataMap; import net.glowstone.inventory.GlowHorseInventory; @@ -17,12 +19,23 @@ public class GlowHorse extends GlowAbstractHorse implements Horse { + @Getter + @Setter private Variant variant = Variant.values()[new Random().nextInt(2)]; - private Color horseColor = Color.values()[new Random().nextInt(6)]; - private Style horseStyle = Style.values()[new Random().nextInt(3)]; + @Getter + private Color color = Color.values()[new Random().nextInt(6)]; + @Getter + private Style style = Style.values()[new Random().nextInt(3)]; + @Getter + @Setter private boolean eatingHay; + @Setter private boolean hasReproduced; + @Getter + @Setter private int temper; + @Getter + @Setter private HorseInventory inventory = new GlowHorseInventory(this); public GlowHorse(Location location) { @@ -30,35 +43,15 @@ public GlowHorse(Location location) { setSize(1.4F, 1.6F); } - @Override - public Variant getVariant() { - return variant; - } - - @Override - public void setVariant(Variant variant) { - this.variant = variant; - } - - @Override - public Color getColor() { - return horseColor; - } - @Override public void setColor(Color color) { - horseColor = color; + this.color = color; metadata.set(MetadataIndex.HORSE_STYLE, getHorseStyleData()); } - @Override - public Style getStyle() { - return horseStyle; - } - @Override public void setStyle(Style style) { - horseStyle = style; + this.style = style; metadata.set(MetadataIndex.HORSE_STYLE, getHorseStyleData()); } @@ -73,51 +66,22 @@ public void setCarryingChest(boolean b) { // Field has been removed in 1.11 } - @Override - public HorseInventory getInventory() { - return inventory; - } - - public void setInventory(HorseInventory inventory) { - this.inventory = inventory; - } - - public boolean isEatingHay() { - return eatingHay; - } - - public void setEatingHay(boolean eatingHay) { - this.eatingHay = eatingHay; - } - public boolean hasReproduced() { return hasReproduced; } - public void setHasReproduced(boolean hasReproduced) { - this.hasReproduced = hasReproduced; - } - - public int getTemper() { - return temper; - } - - public void setTemper(int temper) { - this.temper = temper; - } - @Override public List createSpawnMessage() { List messages = super.createSpawnMessage(); MetadataMap map = new MetadataMap(GlowHorse.class); map.set(MetadataIndex.HORSE_STYLE, getHorseStyleData()); map.set(MetadataIndex.HORSE_ARMOR, getHorseArmorData()); - messages.add(new EntityMetadataMessage(id, map.getEntryList())); + messages.add(new EntityMetadataMessage(entityId, map.getEntryList())); return messages; } private int getHorseStyleData() { - return horseColor.ordinal() & 0xFF | horseStyle.ordinal() << 8; + return color.ordinal() & 0xFF | style.ordinal() << 8; } private int getHorseArmorData() { diff --git a/src/main/java/net/glowstone/entity/passive/GlowOcelot.java b/src/main/java/net/glowstone/entity/passive/GlowOcelot.java index 2d7750d5b0..f58da57090 100644 --- a/src/main/java/net/glowstone/entity/passive/GlowOcelot.java +++ b/src/main/java/net/glowstone/entity/passive/GlowOcelot.java @@ -1,5 +1,6 @@ package net.glowstone.entity.passive; +import lombok.Getter; import net.glowstone.entity.meta.MetadataIndex; import org.bukkit.Location; import org.bukkit.Sound; @@ -9,19 +10,20 @@ public class GlowOcelot extends GlowTameable implements Ocelot { + @Getter private Type catType; + /** + * Creates a wild ocelot. + * + * @param location the location + */ public GlowOcelot(Location location) { super(location, EntityType.OCELOT, 10); setCatType(Type.WILD_OCELOT); setBoundingBox(0.6, 0.8); } - @Override - public Type getCatType() { - return catType; - } - @Override public void setCatType(Type type) { catType = type; diff --git a/src/main/java/net/glowstone/entity/passive/GlowParrot.java b/src/main/java/net/glowstone/entity/passive/GlowParrot.java index 377db0847b..093e765d28 100644 --- a/src/main/java/net/glowstone/entity/passive/GlowParrot.java +++ b/src/main/java/net/glowstone/entity/passive/GlowParrot.java @@ -26,6 +26,11 @@ public class GlowParrot extends GlowTameable implements Parrot { public static final Variant[] VARIANTS = Variant.values(); private int endOfLife = 0; + /** + * Creates a parrot of a random variant. + * + * @param location the initial location + */ public GlowParrot(Location location) { super(location, EntityType.PARROT, 6); setBoundingBox(0.5, 1.0); @@ -60,6 +65,11 @@ public void setImitatedEntity(LivingEntity livingEntity) { } + /** + * Returns the owner, if this parrot is sitting on its owner's shoulder. + * + * @return the owner, if this parrot is sitting on its owner's shoulder, or null otherwise + */ public Player getSittingOn() { Player player = ((Player) getOwner()); if (Objects.equals(this, player.getShoulderEntityRight()) || Objects @@ -69,6 +79,12 @@ public Player getSittingOn() { return null; } + /** + * Sits on the given player's shoulder. + * + * @param player the player whose shoulder to sit on + * @param shoulder which shoulder to sit on + */ public void setSittingOn(Player player, Shoulder shoulder) { if (shoulder == LEFT) { player.setShoulderEntityLeft(this); @@ -118,7 +134,7 @@ public boolean entityInteract(GlowPlayer player, InteractEntityMessage message) return true; } // TODO: sitting only happens on crouch - if (isTamed() && getOwnerUUID() != null && getOwnerUUID() + if (isTamed() && getOwnerUuid() != null && getOwnerUuid() .equals(player.getUniqueId())) { if (!player.getLeftShoulderTag().isEmpty() && !player.getRightShoulderTag() .isEmpty()) { diff --git a/src/main/java/net/glowstone/entity/passive/GlowRabbit.java b/src/main/java/net/glowstone/entity/passive/GlowRabbit.java index dac47d5cc3..42ff09d548 100644 --- a/src/main/java/net/glowstone/entity/passive/GlowRabbit.java +++ b/src/main/java/net/glowstone/entity/passive/GlowRabbit.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableBiMap; import java.util.concurrent.ThreadLocalRandom; +import lombok.Getter; import net.glowstone.entity.GlowAnimal; import net.glowstone.entity.meta.MetadataIndex; import org.bukkit.Location; @@ -13,18 +14,25 @@ public class GlowRabbit extends GlowAnimal implements Rabbit { - private static final ImmutableBiMap rabbitTypeIntegerMap = ImmutableBiMap.builder() - .put(Type.BROWN, 0) - .put(Type.WHITE, 1) - .put(Type.BLACK, 2) - .put(Type.BLACK_AND_WHITE, 3) - .put(Type.GOLD, 4) - .put(Type.SALT_AND_PEPPER, 5) - .put(Type.THE_KILLER_BUNNY, 99) - .build(); + private static final ImmutableBiMap rabbitTypeIntegerMap = ImmutableBiMap + .builder() + .put(Type.BROWN, 0) + .put(Type.WHITE, 1) + .put(Type.BLACK, 2) + .put(Type.BLACK_AND_WHITE, 3) + .put(Type.GOLD, 4) + .put(Type.SALT_AND_PEPPER, 5) + .put(Type.THE_KILLER_BUNNY, 99) + .build(); + @Getter private Type rabbitType; + /** + * Creates a rabbit of a random type. + * + * @param location the location + */ public GlowRabbit(Location location) { super(location, EntityType.RABBIT, 3); setSize(0.4F, 0.5F); @@ -32,11 +40,6 @@ public GlowRabbit(Location location) { Type.values()[ThreadLocalRandom.current().nextInt(rabbitTypeIntegerMap.size())]); } - @Override - public Type getRabbitType() { - return rabbitType; - } - @Override public void setRabbitType(Type type) { checkNotNull(type, "Cannot set a null rabbit type!"); diff --git a/src/main/java/net/glowstone/entity/passive/GlowSheep.java b/src/main/java/net/glowstone/entity/passive/GlowSheep.java index 61f5eeeeef..7b79204543 100644 --- a/src/main/java/net/glowstone/entity/passive/GlowSheep.java +++ b/src/main/java/net/glowstone/entity/passive/GlowSheep.java @@ -1,6 +1,7 @@ package net.glowstone.entity.passive; import java.util.concurrent.ThreadLocalRandom; +import lombok.Getter; import net.glowstone.entity.GlowAnimal; import net.glowstone.entity.GlowPlayer; import net.glowstone.entity.meta.MetadataIndex; @@ -19,22 +20,29 @@ public class GlowSheep extends GlowAnimal implements Sheep { + @Getter private boolean sheared; + @Getter private DyeColor color; + /** + * Creates a sheep with a random color. + * + * @param location the location + */ public GlowSheep(Location location) { super(location, EntityType.SHEEP, 8); setSize(0.9F, 1.3F); int colorpc = ThreadLocalRandom.current().nextInt(10000); - if (colorpc < 8184) { + if (8184 > colorpc) { setColor(DyeColor.WHITE); - } else if (colorpc >= 8184 && 8684 > colorpc) { + } else if (8684 > colorpc) { setColor(DyeColor.BLACK); - } else if (colorpc >= 8684 && 9184 > colorpc) { + } else if (9184 > colorpc) { setColor(DyeColor.SILVER); - } else if (colorpc >= 9184 && 9684 > colorpc) { + } else if (9684 > colorpc) { setColor(DyeColor.GRAY); - } else if (colorpc >= 9684 && 9984 > colorpc) { + } else if (9984 > colorpc) { setColor(DyeColor.BROWN); } else { setColor(DyeColor.PINK); @@ -43,22 +51,12 @@ public GlowSheep(Location location) { // todo implement the regrow of wool } - @Override - public boolean isSheared() { - return sheared; - } - @Override public void setSheared(boolean sheared) { this.sheared = sheared; metadata.set(MetadataIndex.SHEEP_DATA, getColorByte()); } - @Override - public DyeColor getColor() { - return color; - } - @Override public void setColor(DyeColor dyeColor) { color = dyeColor; diff --git a/src/main/java/net/glowstone/entity/passive/GlowTameable.java b/src/main/java/net/glowstone/entity/passive/GlowTameable.java index 5256dbd46a..d670685444 100644 --- a/src/main/java/net/glowstone/entity/passive/GlowTameable.java +++ b/src/main/java/net/glowstone/entity/passive/GlowTameable.java @@ -1,6 +1,7 @@ package net.glowstone.entity.passive; import java.util.UUID; +import lombok.Getter; import net.glowstone.entity.GlowAnimal; import net.glowstone.entity.meta.MetadataIndex; import net.glowstone.entity.meta.MetadataIndex.TameableFlags; @@ -14,57 +15,51 @@ public abstract class GlowTameable extends GlowAnimal implements Tameable { - protected boolean tamed; + private static final MetadataIndex META_STATUS = MetadataIndex.TAMEABLEAANIMAL_STATUS; + private static final MetadataIndex META_OWNER = MetadataIndex.TAMEABLEANIMAL_OWNER; + private AnimalTamer owner; - private UUID ownerUUId; - private boolean sitting; - private MetadataIndex status = MetadataIndex.TAMEABLEAANIMAL_STATUS; - private MetadataIndex ownerMetadata = MetadataIndex.TAMEABLEANIMAL_OWNER; + @Getter + private UUID ownerUuid; public GlowTameable(Location location, EntityType type, double maxHealth) { super(location, type, maxHealth); } protected GlowTameable(Location location, EntityType type, double maxHealth, - AnimalTamer owner) { + AnimalTamer owner) { super(location, type, maxHealth); if (owner != null) { this.owner = owner; - metadata.set(ownerMetadata, owner.getUniqueId()); + metadata.set(META_OWNER, owner.getUniqueId()); } } @Override public boolean isTamed() { - return tamed; + return metadata.getBit(META_STATUS, TameableFlags.IS_TAME); } @Override public void setTamed(boolean isTamed) { - metadata - .setBit(status, TameableFlags.IS_TAME, isTamed); //TODO 1.9 The flag might need change - tamed = isTamed; + metadata.setBit(META_STATUS, TameableFlags.IS_TAME, isTamed); } @Override public AnimalTamer getOwner() { - return owner instanceof Player ? owner : Bukkit.getPlayer(ownerUUId); + return owner instanceof Player ? owner : Bukkit.getPlayer(ownerUuid); } @Override public void setOwner(AnimalTamer animalTamer) { if (animalTamer == null) { owner = null; - ownerUUId = null; + ownerUuid = null; return; } owner = animalTamer; - ownerUUId = animalTamer.getUniqueId(); - metadata.set(ownerMetadata, owner.getUniqueId()); - } - - public UUID getOwnerUUID() { - return ownerUUId; + ownerUuid = animalTamer.getUniqueId(); + metadata.set(META_OWNER, owner.getUniqueId()); } /** @@ -72,29 +67,38 @@ public UUID getOwnerUUID() { * *

The UUID's are validated through offline player checking. * - *

If a player with the specified UUID has not played on the server before, the owner is not set. + *

If a player with the specified UUID has not played on the server before, the owner is not + * set. * - * @param ownerUUID The player UUID of the owner. + * @param ownerUuid The player UUID of the owner. */ - public void setOwnerUUID(UUID ownerUUID) { - if (ownerUUID == null) { - ownerUUId = null; + public void setOwnerUuid(UUID ownerUuid) { + if (ownerUuid == null) { + this.ownerUuid = null; return; } - OfflinePlayer player = Bukkit.getOfflinePlayer(ownerUUID); + OfflinePlayer player = Bukkit.getOfflinePlayer(ownerUuid); if (player != null && player.hasPlayedBefore()) { - ownerUUId = ownerUUID; + this.ownerUuid = ownerUuid; } } + /** + * Checks if this animal is sitting. + * + * @return true if sitting + */ public boolean isSitting() { - return sitting; + return metadata.getBit(META_STATUS, TameableFlags.IS_SITTING); } + /** + * Sets if this animal is sitting. Will remove any path that the animal + * was following beforehand. + * + * @param isSitting true if sitting + */ public void setSitting(boolean isSitting) { - metadata.setBit(status, TameableFlags.IS_SITTING, - isSitting); //TODO 1.9 - This flag might need change - sitting = isSitting; + metadata.setBit(META_STATUS, TameableFlags.IS_SITTING, isSitting); } - } diff --git a/src/main/java/net/glowstone/entity/passive/GlowVillager.java b/src/main/java/net/glowstone/entity/passive/GlowVillager.java index bc088c4887..00ae903c87 100644 --- a/src/main/java/net/glowstone/entity/passive/GlowVillager.java +++ b/src/main/java/net/glowstone/entity/passive/GlowVillager.java @@ -1,9 +1,15 @@ package net.glowstone.entity.passive; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Random; import java.util.concurrent.ThreadLocalRandom; +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.GlowAgeable; import net.glowstone.entity.GlowHumanEntity; import net.glowstone.entity.meta.MetadataIndex; @@ -19,70 +25,67 @@ public class GlowVillager extends GlowAgeable implements Villager { - private Profession profession; + private static final Profession[] PROFESSIONS = Profession.values(); + + @Getter private Career career; + @Getter + @Setter private int riches; + /** + * The trader this villager is currently trading with. + * + * @param trader the trader + */ + @Getter + @Setter private GlowHumanEntity trader; private List recipes = new ArrayList<>(); + /** + * Whether or not this villager is willing to mate. + * + * @param willing true if this villager is willing to mate, false otherwise + * @return true if this villager is willing to mate, false otherwise + */ + @Getter + @Setter private boolean willing; - private int careerLevel; - - public GlowVillager(Location location) { - super(location, EntityType.VILLAGER, 20); - setProfession( - Profession.values()[ThreadLocalRandom.current().nextInt(Profession.values().length - 2) - + 1]); - setBoundingBox(0.6, 1.95); - } - /** - * Gets all assignable careers for a given profession. + * Get the current level of this villager's trading options. * - * @param profession the profession - * @return the assignable careers for the given profession + * @return the current level of this villager's trading options */ - public static Career[] getCareersByProfession(Profession profession) { - return Arrays.stream(Career.values()) - .filter(c -> c.getProfession() == profession) - .toArray(Career[]::new); - } + @Getter + @Setter + private int careerLevel; /** - * Gets the career associated with a given ID and profession. + * Creates a villager with a random profession. * - * @param id the id of the career - * @param profession the profession - * @return the career associated with the given ID and profession + * @param location the location */ - public static Career getCareerById(int id, Profession profession) { - if (profession == null || profession.isZombie()) { - return null; - } - return Arrays.stream(Career.values()) - .filter(career -> career.getProfession() == profession) - .filter(career -> career.getId() == id) - .findFirst().orElse(null); + public GlowVillager(Location location) { + super(location, EntityType.VILLAGER, 20); + setProfession(getRandomProfession(ThreadLocalRandom.current())); + setBoundingBox(0.6, 1.95); } @Override public Profession getProfession() { - return profession; + return PROFESSIONS[metadata.getInt(MetadataIndex.VILLAGER_PROFESSION)]; } @Override public void setProfession(Profession profession) { - this.profession = profession; - metadata.set(MetadataIndex.VILLAGER_PROFESSION, profession.ordinal() - 1); - assignCareer(); - } + checkArgument(profession != Profession.HUSK); - @Override - public Career getCareer() { - return career; + metadata.set(MetadataIndex.VILLAGER_PROFESSION, profession.ordinal()); + assignCareer(); } @Override public void setCareer(Career career) { + Profession profession = getProfession(); if (profession == null || profession.isZombie()) { return; } @@ -139,68 +142,6 @@ public boolean isTrading() { return getTrader() != null; } - @Override - public GlowHumanEntity getTrader() { - return trader; - } - - /** - * Sets the trader this villager is currently trading with. - * - * @param trader the trader - */ - public void setTrader(GlowHumanEntity trader) { - this.trader = trader; - } - - @Override - public int getRiches() { - return riches; - } - - @Override - public void setRiches(int riches) { - this.riches = riches; - } - - /** - * Get whether or not this villager is willing to mate. - * - * @return true if this villager is willing to mate, false otherwise - */ - public boolean isWilling() { - return willing; - } - - /** - * Sets whether or not this villager is willing to mate. - * - * @param willing true if this villager is willing to mate, false otherwise - */ - public void setWilling(boolean willing) { - this.willing = willing; - } - - /** - * Get the current level of this villager's trading options. - * - * @return the current level of this villager's trading options - */ - public int getCareerLevel() { - return careerLevel; - } - - /** - * Set the current level of this villager's trading options. - * - *

If 0, the next trade will assign a new career and set the career level to 1. - * - * @param careerLevel the level of this villager's trading options - */ - public void setCareerLevel(int careerLevel) { - this.careerLevel = careerLevel; - } - @Override protected Sound getHurtSound() { return Sound.ENTITY_VILLAGER_HURT; @@ -216,11 +157,6 @@ protected Sound getAmbientSound() { return Sound.ENTITY_VILLAGER_AMBIENT; } - @Override - public boolean isUndead() { - return profession != null && profession.isZombie(); - } - @Override public void damage(double amount, Entity source, DamageCause cause) { if (!DamageCause.LIGHTNING.equals(cause)) { @@ -238,6 +174,7 @@ public void damage(double amount, Entity source, DamageCause cause) { * Assigns a random career to the villager. */ private void assignCareer() { + Profession profession = getProfession(); if (profession == null || profession.isZombie()) { this.career = null; } else { @@ -246,4 +183,68 @@ private void assignCareer() { this.careerLevel = 1; } } + + /** + * Gets all assignable careers for a given profession. + * + * @param profession the profession + * @return the assignable careers for the given profession + */ + public static Career[] getCareersByProfession(Profession profession) { + return Arrays.stream(Career.values()) + .filter(c -> c.getProfession() == profession) + .toArray(Career[]::new); + } + + /** + * Gets the career associated with a given ID and profession. + * + * @param id the id of the career + * @param profession the profession + * @return the career associated with the given ID and profession + */ + public static Career getCareerById(int id, Profession profession) { + if (profession == null || profession.isZombie()) { + return null; + } + return Arrays.stream(Career.values()) + .filter(career -> career.getProfession() == profession) + .filter(career -> career.getId() == id) + .findFirst().orElse(null); + } + + /** + * Gets a random {@link Villager.Profession}. + * + * @param random the random instance + * @return a random {@link Villager.Profession} + */ + public static Profession getRandomProfession(Random random) { + checkNotNull(random); + // Ignore HUSK profession (deprecated) + return PROFESSIONS[random.nextInt(PROFESSIONS.length - 2)]; + } + + /** + * Checks whether or not the given {@link Villager.Profession} ID is valid. + * + * @param professionId the ID of the {@link Villager.Profession} + * @return true if the ID is valid, false otherwise + */ + public static boolean isValidProfession(int professionId) { + return professionId >= 0 && professionId < PROFESSIONS.length - 1; + } + + /** + * Gets the {@link Villager.Profession} corresponding to the given ID. + * + * @param professionId the ID of the {@link Villager.Profession} + * @return the corresponding {@link Villager.Profession}, or null if none exists + */ + public static Profession getProfessionById(int professionId) { + if (!isValidProfession(professionId)) { + return null; + } + return PROFESSIONS[professionId]; + } } diff --git a/src/main/java/net/glowstone/entity/passive/GlowWolf.java b/src/main/java/net/glowstone/entity/passive/GlowWolf.java index 35cd754410..5d3dfb24e2 100644 --- a/src/main/java/net/glowstone/entity/passive/GlowWolf.java +++ b/src/main/java/net/glowstone/entity/passive/GlowWolf.java @@ -1,6 +1,7 @@ package net.glowstone.entity.passive; -import java.util.concurrent.ThreadLocalRandom; +import static com.google.common.base.Preconditions.checkNotNull; + import net.glowstone.entity.meta.MetadataIndex; import org.bukkit.DyeColor; import org.bukkit.Location; @@ -9,53 +10,66 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Wolf; -//import net.glowstone.entity.meta.MetadataIndex.TameableFlags; - public class GlowWolf extends GlowTameable implements Wolf { - private DyeColor collarColor; + private static final DyeColor DEFAULT_COLLAR_COLOR = DyeColor.RED; + /** + * Creates a wolf with a random collar color. + * + * @param location the location + */ public GlowWolf(Location location) { super(location, EntityType.WOLF, 8); - collarColor = DyeColor - .getByDyeData((byte) ThreadLocalRandom.current().nextInt(DyeColor.values().length)); + setCollarColor(DEFAULT_COLLAR_COLOR); setBoundingBox(0.6, 0.85); } @Override public boolean isAngry() { - return false; - //metadata.getBit(MetadataIndex.WOLF_FLAGS, TameableFlags.WOLF_IS_ANGRY); TODO 1.9 - Angry seems missing from the metadata according to wiki.vg + return metadata.getBit(MetadataIndex.TAMEABLEAANIMAL_STATUS, + MetadataIndex.TameableFlags.WOLF_IS_ANGRY); } @Override public void setAngry(boolean angry) { - //metadata.setBit(MetadataIndex.WOLF_FLAGS, TameableFlags.WOLF_IS_ANGRY, angry); TODO 1.9 - Angry seems missing from the metadata according to wiki.vg + metadata.setBit(MetadataIndex.TAMEABLEAANIMAL_STATUS, + MetadataIndex.TameableFlags.WOLF_IS_ANGRY, angry); } @Override public DyeColor getCollarColor() { - return collarColor; + return DyeColor.getByDyeData(metadata.getByte(MetadataIndex.WOLF_COLOR)); } @Override public void setCollarColor(DyeColor color) { + checkNotNull(color); metadata.set(MetadataIndex.WOLF_COLOR, color.getDyeData()); - collarColor = color; } + /** + * Gets whether the wolf is in the 'begging' state. + * + * @return whether the wolf is in the 'begging' state. + */ public boolean isBegging() { return metadata.getBoolean(MetadataIndex.WOLF_BEGGING); } + /** + * Sets whether the wolf is in the 'begging' state. + * + * @param begging whether the wolf is in the 'begging' state. + */ public void setBegging(boolean begging) { metadata.set(MetadataIndex.WOLF_BEGGING, begging); } @Override public void setTamed(boolean isTamed) { - if (tamed != isTamed) { - // Change max health of wolf when he's got tamed. See MinecraftWiki for more information! + if (isTamed() != isTamed) { + // Change max health of wolf when he's got tamed. See MinecraftWiki for more information if (isTamed && getMaxHealth() == 8) { setMaxHealth(20); setHealth(20); diff --git a/src/main/java/net/glowstone/generator/GlowChunkData.java b/src/main/java/net/glowstone/generator/GlowChunkData.java index 559e615d01..8671ee2693 100644 --- a/src/main/java/net/glowstone/generator/GlowChunkData.java +++ b/src/main/java/net/glowstone/generator/GlowChunkData.java @@ -1,5 +1,6 @@ package net.glowstone.generator; +import lombok.Getter; import net.glowstone.chunk.GlowChunk; import org.bukkit.Material; import org.bukkit.World; @@ -9,7 +10,9 @@ @SuppressWarnings("deprecation") public class GlowChunkData implements ChunkData { + @Getter private final int maxHeight; + @Getter private short[][] sections; public GlowChunkData(World world) { @@ -17,10 +20,6 @@ public GlowChunkData(World world) { sections = new short[GlowChunk.SEC_COUNT][]; } - public short[][] getSections() { - return sections; - } - @Override public byte getData(int x, int y, int z) { if (x < 0 || y < 0 || z < 0 || x >= GlowChunk.HEIGHT || y >= GlowChunk.DEPTH @@ -33,11 +32,6 @@ public byte getData(int x, int y, int z) { return (byte) (sections[y >> 4][(y & 0xF) << 8 | z << 4 | x] & 0xF); } - @Override - public int getMaxHeight() { - return maxHeight; - } - @Override public Material getType(int x, int y, int z) { return Material.getMaterial(getTypeId(x, y, z)); diff --git a/src/main/java/net/glowstone/generator/NetherGenerator.java b/src/main/java/net/glowstone/generator/NetherGenerator.java index a5833cb369..78eb409503 100644 --- a/src/main/java/net/glowstone/generator/NetherGenerator.java +++ b/src/main/java/net/glowstone/generator/NetherGenerator.java @@ -26,6 +26,9 @@ public class NetherGenerator extends GlowChunkGenerator { private final double[][][] density = new double[5][5][17]; + /** + * Creates a chunk generator for the Nether. + */ public NetherGenerator() { super(new NetherPopulator()); @@ -43,22 +46,23 @@ public NetherGenerator() { @Override public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, - BiomeGrid biomes) { + BiomeGrid biomes) { ChunkData chunkData = generateRawTerrain(world, chunkX, chunkZ); int cx = chunkX << 4; int cz = chunkZ << 4; double[] surfaceNoise = ((PerlinOctaveGenerator) getWorldOctaves(world).get("surface")) - .getFractalBrownianMotion(cx, cz, 0, 0.5D, 2.0D); + .getFractalBrownianMotion(cx, cz, 0, 0.5D, 2.0D); double[] soulsandNoise = ((PerlinOctaveGenerator) getWorldOctaves(world).get("soulsand")) - .getFractalBrownianMotion(cx, cz, 0, 0.5D, 2.0D); + .getFractalBrownianMotion(cx, cz, 0, 0.5D, 2.0D); double[] gravelNoise = ((PerlinOctaveGenerator) getWorldOctaves(world).get("gravel")) - .getFractalBrownianMotion(cx, 0, cz, 0.5D, 2.0D); + .getFractalBrownianMotion(cx, 0, cz, 0.5D, 2.0D); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { generateTerrainColumn(chunkData, world, random, cx + x, cz + z, - surfaceNoise[x | z << 4], soulsandNoise[x | z << 4], gravelNoise[x | z << 4]); + surfaceNoise[x | z << 4], soulsandNoise[x | z << 4], gravelNoise[x + | z << 4]); } } @@ -152,14 +156,14 @@ private ChunkData generateRawTerrain(World world, int chunkX, int chunkZ) { for (int m = 0; m < 4; m++) { double dens = d9; for (int n = 0; n < 4; n++) { - // any density higher than 0 is ground, any density lower or equal to 0 is air - // (or lava if under the lava level). + // any density higher than 0 is ground, any density lower or equal + // to 0 is air (or lava if under the lava level). if (dens > 0) { chunkData.setBlock(m + (i << 2), l + (k << 3), n + (j << 2), - Material.NETHERRACK); + Material.NETHERRACK); } else if (l + (k << 3) < 32) { chunkData.setBlock(m + (i << 2), l + (k << 3), n + (j << 2), - Material.STATIONARY_LAVA); + Material.STATIONARY_LAVA); } // interpolation along z dens += (d10 - d9) / 4; @@ -185,21 +189,21 @@ private ChunkData generateRawTerrain(World world, int chunkX, int chunkZ) { private void generateTerrainDensity(World world, int x, int z) { Map octaves = getWorldOctaves(world); double[] heightNoise = ((PerlinOctaveGenerator) octaves.get("height")) - .getFractalBrownianMotion(x, z, 0.5D, 2.0D); + .getFractalBrownianMotion(x, z, 0.5D, 2.0D); double[] roughnessNoise = ((PerlinOctaveGenerator) octaves.get("roughness")) - .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); + .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); double[] roughnessNoise2 = ((PerlinOctaveGenerator) octaves.get("roughness2")) - .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); + .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); double[] detailNoise = ((PerlinOctaveGenerator) octaves.get("detail")) - .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); + .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); - double[] nV = new double[17]; + double[] nv = new double[17]; for (int i = 0; i < 17; i++) { - nV[i] = Math.cos(i * Math.PI * 6.0D / 17.0D) * 2.0D; - double nH = i > 17 / 2 ? 17 - 1 - i : i; - if (nH < 4.0D) { - nH = 4.0D - nH; - nV[i] -= nH * nH * nH * 10.0D; + nv[i] = Math.cos(i * Math.PI * 6.0D / 17.0D) * 2.0D; + double nh = i > 17 / 2 ? 17 - 1 - i : i; + if (nh < 4.0D) { + nh = 4.0D - nh; + nv[i] -= nh * nh * nh * 10.0D; } } @@ -225,11 +229,11 @@ private void generateTerrainDensity(World world, int x, int z) { double noiseR = roughnessNoise[index] / 512.0D; double noiseR2 = roughnessNoise2[index] / 512.0D; double noiseD = (detailNoise[index] / 10.0D + 1.0D) / 2.0D; - double nH = nV[k]; + double nh = nv[k]; // linear interpolation double dens = noiseD < 0 ? noiseR - : noiseD > 1 ? noiseR2 : noiseR + (noiseR2 - noiseR) * noiseD; - dens -= nH; + : noiseD > 1 ? noiseR2 : noiseR + (noiseR2 - noiseR) * noiseD; + dens -= nh; index++; if (k > 13) { double lowering = (k - 13) / 3.0D; @@ -241,8 +245,20 @@ private void generateTerrainDensity(World world, int x, int z) { } } + /** + * Generates a terrain column. + * + * @param chunkData the chunk in which to generate + * @param world the world + * @param random the PRNG + * @param x the column x coordinate + * @param z the column z coordinate + * @param surfaceNoise amplitude of surface-height variation + * @param soulsandNoise determines the chance of a soul sand patch + * @param gravelNoise determines the chance of a gravel patch + */ public void generateTerrainColumn(ChunkData chunkData, World world, Random random, int x, int z, - double surfaceNoise, double soulsandNoise, double gravelNoise) { + double surfaceNoise, double soulsandNoise, double gravelNoise) { Material topMat = Material.NETHERRACK; Material groundMat = Material.NETHERRACK; diff --git a/src/main/java/net/glowstone/generator/OverworldGenerator.java b/src/main/java/net/glowstone/generator/OverworldGenerator.java index 75c3b7f45d..75ef1b4110 100644 --- a/src/main/java/net/glowstone/generator/OverworldGenerator.java +++ b/src/main/java/net/glowstone/generator/OverworldGenerator.java @@ -123,6 +123,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Random; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import net.glowstone.GlowServer; import net.glowstone.GlowWorld; import net.glowstone.constants.GlowBiome; @@ -172,21 +174,21 @@ public class OverworldGenerator extends GlowChunkGenerator { static { setBiomeSpecificGround(new SandyGroundGenerator(), BEACHES, COLD_BEACH, DESERT, - DESERT_HILLS, MUTATED_DESERT); + DESERT_HILLS, MUTATED_DESERT); setBiomeSpecificGround(new RockyGroundGenerator(), STONE_BEACH); setBiomeSpecificGround(new SnowyGroundGenerator(), MUTATED_ICE_FLATS); setBiomeSpecificGround(new MycelGroundGenerator(), MUSHROOM_ISLAND, MUSHROOM_ISLAND_SHORE); setBiomeSpecificGround(new StonePatchGroundGenerator(), EXTREME_HILLS); setBiomeSpecificGround(new GravelPatchGroundGenerator(), MUTATED_EXTREME_HILLS, - MUTATED_EXTREME_HILLS_WITH_TREES); + MUTATED_EXTREME_HILLS_WITH_TREES); setBiomeSpecificGround(new DirtAndStonePatchGroundGenerator(), MUTATED_SAVANNA, - MUTATED_SAVANNA_ROCK); + MUTATED_SAVANNA_ROCK); setBiomeSpecificGround(new DirtPatchGroundGenerator(), REDWOOD_TAIGA, REDWOOD_TAIGA_HILLS, - MUTATED_REDWOOD_TAIGA, MUTATED_REDWOOD_TAIGA_HILLS); + MUTATED_REDWOOD_TAIGA, MUTATED_REDWOOD_TAIGA_HILLS); setBiomeSpecificGround(new MesaGroundGenerator(), MESA, MESA_CLEAR_ROCK, MESA_ROCK); setBiomeSpecificGround(new MesaGroundGenerator(MesaType.BRYCE), MUTATED_MESA); setBiomeSpecificGround(new MesaGroundGenerator(MesaType.FOREST), MESA_ROCK, - MUTATED_MESA_ROCK); + MUTATED_MESA_ROCK); setBiomeHeight(BiomeHeight.OCEAN, OCEAN, FROZEN_OCEAN); setBiomeHeight(BiomeHeight.DEEP_OCEAN, DEEP_OCEAN); @@ -195,22 +197,22 @@ public class OverworldGenerator extends GlowChunkGenerator { setBiomeHeight(BiomeHeight.ROCKY_SHORE, STONE_BEACH); setBiomeHeight(BiomeHeight.FLATLANDS, DESERT, ICE_FLATS, SAVANNA); setBiomeHeight(BiomeHeight.EXTREME_HILLS, EXTREME_HILLS, EXTREME_HILLS_WITH_TREES, - MUTATED_EXTREME_HILLS, MUTATED_EXTREME_HILLS_WITH_TREES); + MUTATED_EXTREME_HILLS, MUTATED_EXTREME_HILLS_WITH_TREES); setBiomeHeight(BiomeHeight.MID_PLAINS, TAIGA, TAIGA_COLD, REDWOOD_TAIGA); setBiomeHeight(BiomeHeight.SWAMPLAND, SWAMPLAND); setBiomeHeight(BiomeHeight.LOW_HILLS, MUSHROOM_ISLAND); setBiomeHeight(BiomeHeight.HILLS, ICE_MOUNTAINS, DESERT_HILLS, FOREST_HILLS, TAIGA_HILLS, - SMALLER_EXTREME_HILLS, JUNGLE_HILLS, BIRCH_FOREST_HILLS, TAIGA_COLD_HILLS, - REDWOOD_TAIGA_HILLS, MUTATED_MESA_ROCK, MUTATED_MESA_CLEAR_ROCK); + SMALLER_EXTREME_HILLS, JUNGLE_HILLS, BIRCH_FOREST_HILLS, TAIGA_COLD_HILLS, + REDWOOD_TAIGA_HILLS, MUTATED_MESA_ROCK, MUTATED_MESA_CLEAR_ROCK); setBiomeHeight(BiomeHeight.HIGH_PLATEAU, SAVANNA_ROCK, MESA_ROCK, MESA_CLEAR_ROCK); setBiomeHeight(BiomeHeight.FLATLANDS_HILLS, MUTATED_DESERT); setBiomeHeight(BiomeHeight.BIG_HILLS, MUTATED_ICE_FLATS); setBiomeHeight(BiomeHeight.BIG_HILLS2, MUTATED_BIRCH_FOREST_HILLS); setBiomeHeight(BiomeHeight.SWAMPLAND_HILLS, MUTATED_SWAMPLAND); setBiomeHeight(BiomeHeight.DEFAULT_HILLS, MUTATED_JUNGLE, MUTATED_JUNGLE_EDGE, - MUTATED_BIRCH_FOREST, MUTATED_ROOFED_FOREST); + MUTATED_BIRCH_FOREST, MUTATED_ROOFED_FOREST); setBiomeHeight(BiomeHeight.MID_HILLS, MUTATED_TAIGA, MUTATED_TAIGA_COLD, - MUTATED_REDWOOD_TAIGA, MUTATED_REDWOOD_TAIGA_HILLS); + MUTATED_REDWOOD_TAIGA, MUTATED_REDWOOD_TAIGA_HILLS); setBiomeHeight(BiomeHeight.MID_HILLS2, MUTATED_FOREST); setBiomeHeight(BiomeHeight.LOW_SPIKES, MUTATED_SAVANNA); setBiomeHeight(BiomeHeight.HIGH_SPIKES, MUTATED_SAVANNA_ROCK); @@ -234,10 +236,13 @@ public class OverworldGenerator extends GlowChunkGenerator { private final GroundGenerator groundGen = new GroundGenerator(); private final BiomeHeight defaultHeight = BiomeHeight.DEFAULT; + /** + * Creates the generator for the overworld. + */ public OverworldGenerator() { super(new OverworldPopulator(), - new StructurePopulator(), - new SnowPopulator()); + new StructurePopulator(), + new SnowPopulator()); coordinateScale = getWorldConfig().getDouble(OVERWORLD_COORDINATE_SCALE); heightScale = getWorldConfig().getDouble(OVERWORLD_HEIGHT_SCALE); @@ -269,46 +274,50 @@ private static void setBiomeHeight(BiomeHeight height, Biome... biomes) { @Override public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, - BiomeGrid biomes) { + BiomeGrid biomes) { ChunkData chunkData = generateRawTerrain(world, chunkX, chunkZ); int cx = chunkX << 4; int cz = chunkZ << 4; SimplexOctaveGenerator octaveGenerator = ((SimplexOctaveGenerator) getWorldOctaves(world) - .get("surface")); - int sizeX = octaveGenerator.getXSize(); - int sizeZ = octaveGenerator.getZSize(); + .get("surface")); + int sizeX = octaveGenerator.getSizeX(); + int sizeZ = octaveGenerator.getSizeZ(); if (((GlowServer) Bukkit.getServer()).doesUseGraphicsCompute()) { CLKernel noiseGen = null; CLBuffer noise = null; try { // Initialize OpenCL stuff and put args CLProgram program = OpenCompute.getProgram("net/glowstone/CLRandom.cl"); - int workSize = sizeX * octaveGenerator.getYSize() * sizeZ; - noise = OpenCompute.getContext().createFloatBuffer(workSize, CLMemory.Mem.WRITE_ONLY); + int workSize = sizeX * octaveGenerator.getSizeY() * sizeZ; + noise = OpenCompute.getContext() + .createFloatBuffer(workSize, CLMemory.Mem.WRITE_ONLY); noiseGen = OpenCompute.getKernel(program, "GenerateNoise"); noiseGen.putArg(random.nextFloat()) - .putArg(random.nextFloat()) - .putArg(noise) - .putArg(workSize); + .putArg(random.nextFloat()) + .putArg(noise) + .putArg(workSize); // Calculate noise on GPU - OpenCompute.getQueue().put1DRangeKernel(noiseGen, 0, OpenCompute.getGlobalSize(workSize), - OpenCompute.getLocalSize()) - .putReadBuffer(noise, true); + OpenCompute.getQueue() + .put1DRangeKernel(noiseGen, 0, OpenCompute.getGlobalSize(workSize), + OpenCompute.getLocalSize()) + .putReadBuffer(noise, true); // Use noise for (int x = 0; x < sizeX; x++) { for (int z = 0; z < sizeZ; z++) { if (GROUND_MAP.containsKey(biomes.getBiome(x, z))) { GROUND_MAP.get(biomes.getBiome(x, z)) - .generateTerrainColumn(chunkData, world, random, cx + x, cz + z, - biomes.getBiome(x, z), noise.getBuffer().get(x | z << 4)); + .generateTerrainColumn(chunkData, world, random, cx + x, cz + z, + biomes.getBiome(x, z), noise.getBuffer() + .get(x | z << 4)); } else { groundGen - .generateTerrainColumn(chunkData, world, random, cx + x, cz + z, - biomes.getBiome(x, z), noise.getBuffer().get(x | z << 4)); + .generateTerrainColumn(chunkData, world, random, cx + x, cz + z, + biomes.getBiome(x, z), noise.getBuffer() + .get(x | z << 4)); } } } @@ -327,11 +336,11 @@ public ChunkData generateChunkData(World world, Random random, int chunkX, int c for (int z = 0; z < sizeZ; z++) { if (GROUND_MAP.containsKey(biomes.getBiome(x, z))) { GROUND_MAP.get(biomes.getBiome(x, z)) - .generateTerrainColumn(chunkData, world, random, cx + x, cz + z, - biomes.getBiome(x, z), surfaceNoise[x | z << 4]); + .generateTerrainColumn(chunkData, world, random, cx + x, cz + z, + biomes.getBiome(x, z), surfaceNoise[x | z << 4]); } else { groundGen.generateTerrainColumn(chunkData, world, random, cx + x, cz + z, - biomes.getBiome(x, z), surfaceNoise[x | z << 4]); + biomes.getBiome(x, z), surfaceNoise[x | z << 4]); } } } @@ -378,7 +387,8 @@ private ChunkData generateRawTerrain(World world, int chunkX, int chunkZ) { ChunkData chunkData = createChunkData(world); - // Terrain densities are sampled at different resolutions (1/4x on x,z and 1/8x on y by default) + // Terrain densities are sampled at different resolutions (1/4x on x,z and 1/8x on y by + // default) // so it's needed to re-scale it. Linear interpolation is used to fill in the gaps. int fill = getWorldConfig().getInt(OVERWORLD_DENSITY_FILL_MODE); @@ -406,40 +416,44 @@ private ChunkData generateRawTerrain(World world, int chunkX, int chunkZ) { for (int m = 0; m < 4; m++) { double dens = d9; for (int n = 0; n < 4; n++) { - // any density higher than density offset is ground, any density lower or equal to the density offset is air + // any density higher than density offset is ground, any density + // lower or equal to the density offset is air // (or water if under the sea level). - // this can be flipped if the mode is negative, so lower or equal to is ground, and higher is air/water - // and, then data can be shifted by afill the order is air by default, ground, then water. they can shift places + // this can be flipped if the mode is negative, so lower or equal + // to is ground, and higher is air/water + // and, then data can be shifted by afill the order is air by + // default, ground, then water. they can shift places // within each if statement - // the target is densityOffset + 0, since the default target is 0, so don't get too confused by the naming :) + // the target is densityOffset + 0, since the default target is + // 0, so don't get too confused by the naming :) if (afill == 1 || afill == 10 || afill == 13 || afill == 16) { chunkData.setBlock(m + (i << 2), l + (k << 3), n + (j << 2), - Material.STATIONARY_WATER); + Material.STATIONARY_WATER); } else if (afill == 2 || afill == 9 || afill == 12 || afill == 15) { chunkData.setBlock(m + (i << 2), l + (k << 3), n + (j << 2), - Material.STONE); + Material.STONE); } if (dens > densityOffset && fill > -1 - || dens <= densityOffset && fill < 0) { + || dens <= densityOffset && fill < 0) { if (afill == 0 || afill == 3 || afill == 6 || afill == 9 - || afill == 12) { + || afill == 12) { chunkData.setBlock(m + (i << 2), l + (k << 3), n + (j << 2), - Material.STONE); + Material.STONE); } else if (afill == 2 || afill == 7 || afill == 10 - || afill == 16) { + || afill == 16) { chunkData.setBlock(m + (i << 2), l + (k << 3), n + (j << 2), - Material.STATIONARY_WATER); + Material.STATIONARY_WATER); } } else if (l + (k << 3) < seaLevel - 1 && seaFill == 0 - || l + (k << 3) >= seaLevel - 1 && seaFill == 1) { + || l + (k << 3) >= seaLevel - 1 && seaFill == 1) { if (afill == 0 || afill == 3 || afill == 7 || afill == 10 - || afill == 13) { + || afill == 13) { chunkData.setBlock(m + (i << 2), l + (k << 3), n + (j << 2), - Material.STATIONARY_WATER); + Material.STATIONARY_WATER); } else if (afill == 1 || afill == 6 || afill == 9 - || afill == 15) { + || afill == 15) { chunkData.setBlock(m + (i << 2), l + (k << 3), n + (j << 2), - Material.STONE); + Material.STONE); } } // interpolation along z @@ -471,25 +485,29 @@ private void generateTerrainDensity(World world, int x, int z) { x <<= 2; z <<= 2; - // Get biome grid data at lower res (scaled 4x, at this scale a chunk is 4x4 columns of the biome grid), + // Get biome grid data at lower res (scaled 4x, at this scale a chunk is 4x4 columns of + // the biome grid), // we are loosing biome detail but saving huge amount of computation. - // We need 1 chunk (4 columns) + 1 column for later needed outer edges (1 column) and at least 2 columns + // We need 1 chunk (4 columns) + 1 column for later needed outer edges (1 column) and at + // least 2 columns // on each side to be able to cover every value. - // 4 + 1 + 2 + 2 = 9 columns but the biomegrid generator needs a multiple of 2 so we ask 10 columns wide + // 4 + 1 + 2 + 2 = 9 columns but the biomegrid generator needs a multiple of 2 so we ask + // 10 columns wide // to the biomegrid generator. - // This gives a total of 81 biome grid columns to work with, and this includes the chunk neighborhood. + // This gives a total of 81 biome grid columns to work with, and this includes the chunk + // neighborhood. int[] biomeGrid = ((GlowWorld) world).getChunkManager() - .getBiomeGridAtLowerRes(x - 2, z - 2, 10, 10); + .getBiomeGridAtLowerRes(x - 2, z - 2, 10, 10); Map octaves = getWorldOctaves(world); double[] heightNoise = ((PerlinOctaveGenerator) octaves.get("height")) - .getFractalBrownianMotion(x, z, 0.5D, 2.0D); + .getFractalBrownianMotion(x, z, 0.5D, 2.0D); double[] roughnessNoise = ((PerlinOctaveGenerator) octaves.get("roughness")) - .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); + .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); double[] roughnessNoise2 = ((PerlinOctaveGenerator) octaves.get("roughness2")) - .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); + .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); double[] detailNoise = ((PerlinOctaveGenerator) octaves.get("detail")) - .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); + .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); int index = 0; int indexHeight = 0; @@ -498,11 +516,15 @@ private void generateTerrainDensity(World world, int x, int z) { // Ideally we would sample 512 (4x4x32) values but in reality we need 825 values (5x5x33). // This is because linear interpolation is done later to re-scale so we need right and // bottom edge values if we want it to be "seamless". - // You can check this picture to have a visualization of how the biomegrid is traversed (2D plan): + // You can check this picture to have a visualization of how the biomegrid is traversed + // (2D plan): // http://i.imgur.com/s4whlZE.png - // The big square grid represents our lower res biomegrid columns, and the very small square grid - // represents the normal biome grid columns (at block level) and the reason why it's required to - // re-scale it and do linear interpolation before densities can be used to generate raw terrain. + // The big square grid represents our lower res biomegrid columns, and the very small + // square grid + // represents the normal biome grid columns (at block level) and the reason why it's + // required to + // re-scale it and do linear interpolation before densities can be used to generate raw + // terrain. for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { @@ -517,11 +539,11 @@ private void generateTerrainDensity(World world, int x, int z) { for (int n = 0; n < 5; n++) { Biome nearBiome = GlowBiome.getBiome(biomeGrid[i + m + (j + n) * 10]); BiomeHeight nearBiomeHeight = HEIGHT_MAP - .getOrDefault(nearBiome, defaultHeight); + .getOrDefault(nearBiome, defaultHeight); double heightBase = - biomeHeightOffset + nearBiomeHeight.getHeight() * biomeHeightWeight; + biomeHeightOffset + nearBiomeHeight.getHeight() * biomeHeightWeight; double heightScale = - biomeScaleOffset + nearBiomeHeight.getScale() * biomeScaleWeight; + biomeScaleOffset + nearBiomeHeight.getScale() * biomeScaleWeight; if (type == WorldType.AMPLIFIED && heightBase > 0) { heightBase = 1.0D + heightBase * 2.0D; heightScale = 1.0D + heightScale * 4.0D; @@ -555,17 +577,17 @@ private void generateTerrainDensity(World world, int x, int z) { for (int k = 0; k < 33; k++) { // density should be lower and lower as we climb up, this gets a height value to // subtract from the noise. - double nH = (k - noiseH) * stretchY * 128.0D / 256.0D / avgHeightScale; - if (nH < 0.0D) { - nH *= 4.0D; + double nh = (k - noiseH) * stretchY * 128.0D / 256.0D / avgHeightScale; + if (nh < 0.0D) { + nh *= 4.0D; } double noiseR = roughnessNoise[index] / 512.0D; double noiseR2 = roughnessNoise2[index] / 512.0D; double noiseD = (detailNoise[index] / 10.0D + 1.0D) / 2.0D; // linear interpolation double dens = noiseD < 0 ? noiseR - : noiseD > 1 ? noiseR2 : noiseR + (noiseR2 - noiseR) * noiseD; - dens -= nH; + : noiseD > 1 ? noiseR2 : noiseR + (noiseR2 - noiseR) * noiseD; + dens -= nh; index++; if (k > 29) { double lowering = (k - 29) / 3.0D; @@ -578,89 +600,79 @@ private void generateTerrainDensity(World world, int x, int z) { } } + @RequiredArgsConstructor private static class BiomeHeight { public static final BiomeHeight DEFAULT = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_DEFAULT), - getWorldConfig().getDouble(BIOME_SCALE_DEFAULT)); + getWorldConfig().getDouble(BIOME_HEIGHT_DEFAULT), + getWorldConfig().getDouble(BIOME_SCALE_DEFAULT)); public static final BiomeHeight FLAT_SHORE = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_FLAT_SHORE), - getWorldConfig().getDouble(BIOME_SCALE_FLAT_SHORE)); + getWorldConfig().getDouble(BIOME_HEIGHT_FLAT_SHORE), + getWorldConfig().getDouble(BIOME_SCALE_FLAT_SHORE)); public static final BiomeHeight HIGH_PLATEAU = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_HIGH_PLATEAU), - getWorldConfig().getDouble(BIOME_SCALE_HIGH_PLATEAU)); + getWorldConfig().getDouble(BIOME_HEIGHT_HIGH_PLATEAU), + getWorldConfig().getDouble(BIOME_SCALE_HIGH_PLATEAU)); public static final BiomeHeight FLATLANDS = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_FLATLANDS), - getWorldConfig().getDouble(BIOME_SCALE_FLATLANDS)); + getWorldConfig().getDouble(BIOME_HEIGHT_FLATLANDS), + getWorldConfig().getDouble(BIOME_SCALE_FLATLANDS)); public static final BiomeHeight SWAMPLAND = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_SWAMPLAND), - getWorldConfig().getDouble(BIOME_SCALE_SWAMPLAND)); + getWorldConfig().getDouble(BIOME_HEIGHT_SWAMPLAND), + getWorldConfig().getDouble(BIOME_SCALE_SWAMPLAND)); public static final BiomeHeight MID_PLAINS = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_MID_PLAINS), - getWorldConfig().getDouble(BIOME_SCALE_MID_PLAINS)); + getWorldConfig().getDouble(BIOME_HEIGHT_MID_PLAINS), + getWorldConfig().getDouble(BIOME_SCALE_MID_PLAINS)); public static final BiomeHeight FLATLANDS_HILLS = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_FLATLANDS_HILLS), - getWorldConfig().getDouble(BIOME_SCALE_FLATLANDS_HILLS)); + getWorldConfig().getDouble(BIOME_HEIGHT_FLATLANDS_HILLS), + getWorldConfig().getDouble(BIOME_SCALE_FLATLANDS_HILLS)); public static final BiomeHeight SWAMPLAND_HILLS = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_SWAMPLAND_HILLS), - getWorldConfig().getDouble(BIOME_SCALE_SWAMPLAND_HILLS)); + getWorldConfig().getDouble(BIOME_HEIGHT_SWAMPLAND_HILLS), + getWorldConfig().getDouble(BIOME_SCALE_SWAMPLAND_HILLS)); public static final BiomeHeight LOW_HILLS = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_LOW_HILLS), - getWorldConfig().getDouble(BIOME_SCALE_LOW_HILLS)); + getWorldConfig().getDouble(BIOME_HEIGHT_LOW_HILLS), + getWorldConfig().getDouble(BIOME_SCALE_LOW_HILLS)); public static final BiomeHeight HILLS = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_HILLS), - getWorldConfig().getDouble(BIOME_SCALE_HILLS)); + getWorldConfig().getDouble(BIOME_HEIGHT_HILLS), + getWorldConfig().getDouble(BIOME_SCALE_HILLS)); public static final BiomeHeight MID_HILLS2 = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_MID_HILLS2), - getWorldConfig().getDouble(BIOME_SCALE_MID_HILLS2)); + getWorldConfig().getDouble(BIOME_HEIGHT_MID_HILLS2), + getWorldConfig().getDouble(BIOME_SCALE_MID_HILLS2)); public static final BiomeHeight DEFAULT_HILLS = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_DEFAULT_HILLS), - getWorldConfig().getDouble(BIOME_SCALE_DEFAULT_HILLS)); + getWorldConfig().getDouble(BIOME_HEIGHT_DEFAULT_HILLS), + getWorldConfig().getDouble(BIOME_SCALE_DEFAULT_HILLS)); public static final BiomeHeight MID_HILLS = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_MID_HILLS), - getWorldConfig().getDouble(BIOME_SCALE_MID_HILLS)); + getWorldConfig().getDouble(BIOME_HEIGHT_MID_HILLS), + getWorldConfig().getDouble(BIOME_SCALE_MID_HILLS)); public static final BiomeHeight BIG_HILLS = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_BIG_HILLS), - getWorldConfig().getDouble(BIOME_SCALE_BIG_HILLS)); + getWorldConfig().getDouble(BIOME_HEIGHT_BIG_HILLS), + getWorldConfig().getDouble(BIOME_SCALE_BIG_HILLS)); public static final BiomeHeight BIG_HILLS2 = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_BIG_HILLS2), - getWorldConfig().getDouble(BIOME_SCALE_BIG_HILLS2)); + getWorldConfig().getDouble(BIOME_HEIGHT_BIG_HILLS2), + getWorldConfig().getDouble(BIOME_SCALE_BIG_HILLS2)); public static final BiomeHeight EXTREME_HILLS = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_EXTREME_HILLS), - getWorldConfig().getDouble(BIOME_SCALE_EXTREME_HILLS)); + getWorldConfig().getDouble(BIOME_HEIGHT_EXTREME_HILLS), + getWorldConfig().getDouble(BIOME_SCALE_EXTREME_HILLS)); public static final BiomeHeight ROCKY_SHORE = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_ROCKY_SHORE), - getWorldConfig().getDouble(BIOME_SCALE_ROCKY_SHORE)); + getWorldConfig().getDouble(BIOME_HEIGHT_ROCKY_SHORE), + getWorldConfig().getDouble(BIOME_SCALE_ROCKY_SHORE)); public static final BiomeHeight LOW_SPIKES = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_LOW_SPIKES), - getWorldConfig().getDouble(BIOME_SCALE_LOW_SPIKES)); + getWorldConfig().getDouble(BIOME_HEIGHT_LOW_SPIKES), + getWorldConfig().getDouble(BIOME_SCALE_LOW_SPIKES)); public static final BiomeHeight HIGH_SPIKES = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_HIGH_SPIKES), - getWorldConfig().getDouble(BIOME_SCALE_HIGH_SPIKES)); + getWorldConfig().getDouble(BIOME_HEIGHT_HIGH_SPIKES), + getWorldConfig().getDouble(BIOME_SCALE_HIGH_SPIKES)); public static final BiomeHeight RIVER = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_RIVER), - getWorldConfig().getDouble(BIOME_SCALE_RIVER)); + getWorldConfig().getDouble(BIOME_HEIGHT_RIVER), + getWorldConfig().getDouble(BIOME_SCALE_RIVER)); public static final BiomeHeight OCEAN = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_OCEAN), - getWorldConfig().getDouble(BIOME_SCALE_OCEAN)); + getWorldConfig().getDouble(BIOME_HEIGHT_OCEAN), + getWorldConfig().getDouble(BIOME_SCALE_OCEAN)); public static final BiomeHeight DEEP_OCEAN = new BiomeHeight( - getWorldConfig().getDouble(BIOME_HEIGHT_DEEP_OCEAN), - getWorldConfig().getDouble(BIOME_SCALE_DEEP_OCEAN)); + getWorldConfig().getDouble(BIOME_HEIGHT_DEEP_OCEAN), + getWorldConfig().getDouble(BIOME_SCALE_DEEP_OCEAN)); + @Getter private final double height; + @Getter private final double scale; - - public BiomeHeight(double height, double scale) { - this.height = height; - this.scale = scale; - } - - public double getHeight() { - return height; - } - - public double getScale() { - return scale; - } } } diff --git a/src/main/java/net/glowstone/generator/SuperflatGenerator.java b/src/main/java/net/glowstone/generator/SuperflatGenerator.java index d72bca0d2a..13a29e5e0b 100644 --- a/src/main/java/net/glowstone/generator/SuperflatGenerator.java +++ b/src/main/java/net/glowstone/generator/SuperflatGenerator.java @@ -28,8 +28,18 @@ public ChunkData generateChunkData(World world, Random random, int chunkX, int c return chunkData; } + /** + * Generates a terrain column. + * + * @param chunkData the chunk in which to generate + * @param world the world (ignored) + * @param random the PRNG (ignored) + * @param x the column x coordinate + * @param z the column z coordinate + */ public void generateTerrainColumn(ChunkData chunkData, World world, Random random, int x, int z) { + // TODO: Handle superflat configurations. x = x & 0xF; z = z & 0xF; diff --git a/src/main/java/net/glowstone/generator/TheEndGenerator.java b/src/main/java/net/glowstone/generator/TheEndGenerator.java index 8ea7b57fb0..f0f0c4045f 100644 --- a/src/main/java/net/glowstone/generator/TheEndGenerator.java +++ b/src/main/java/net/glowstone/generator/TheEndGenerator.java @@ -22,6 +22,9 @@ public class TheEndGenerator extends GlowChunkGenerator { private final double[][][] density = new double[3][3][33]; + /** + * Creates a chunk generator for the End. + */ public TheEndGenerator() { super(new TheEndPopulator()); @@ -36,7 +39,7 @@ public TheEndGenerator() { @Override public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, - BiomeGrid biomes) { + BiomeGrid biomes) { return generateRawTerrain(world, chunkX, chunkZ); } @@ -92,10 +95,11 @@ private ChunkData generateRawTerrain(World world, int chunkX, int chunkZ) { for (int m = 0; m < 8; m++) { double dens = d9; for (int n = 0; n < 8; n++) { - // any density higher than 0 is ground, any density lower or equal to 0 is air. + // any density higher than 0 is ground, any density lower or + // equal to 0 is air. if (dens > 0) { chunkData.setBlock(m + (i << 3), l + (k << 2), n + (j << 3), - Material.ENDER_STONE); + Material.ENDER_STONE); } // interpolation along z dens += (d10 - d9) / 8; @@ -121,26 +125,27 @@ private ChunkData generateRawTerrain(World world, int chunkX, int chunkZ) { private void generateTerrainDensity(World world, int x, int z) { Map octaves = getWorldOctaves(world); double[] roughnessNoise = ((PerlinOctaveGenerator) octaves.get("roughness")) - .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); + .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); double[] roughnessNoise2 = ((PerlinOctaveGenerator) octaves.get("roughness2")) - .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); + .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); double[] detailNoise = ((PerlinOctaveGenerator) octaves.get("detail")) - .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); + .getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D); int index = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - double nH = 100.0D - Math.sqrt((x + i) * (x + i) + (z + j) * (z + j)) * 8.0D; - nH = Math.max(-100.0D, Math.min(80.0D, nH)); + double noiseHeight = + 100.0D - Math.sqrt((x + i) * (x + i) + (z + j) * (z + j)) * 8.0D; + noiseHeight = Math.max(-100.0D, Math.min(80.0D, noiseHeight)); for (int k = 0; k < 33; k++) { double noiseR = roughnessNoise[index] / 512.0D; double noiseR2 = roughnessNoise2[index] / 512.0D; double noiseD = (detailNoise[index] / 10.0D + 1.0D) / 2.0D; // linear interpolation double dens = noiseD < 0 ? noiseR - : noiseD > 1 ? noiseR2 : noiseR + (noiseR2 - noiseR) * noiseD; - dens = dens - 8.0D + nH; + : noiseD > 1 ? noiseR2 : noiseR + (noiseR2 - noiseR) * noiseD; + dens = dens - 8.0D + noiseHeight; index++; if (k < 8) { double lowering = (8 - k) / 7; diff --git a/src/main/java/net/glowstone/generator/biomegrid/MapLayer.java b/src/main/java/net/glowstone/generator/biomegrid/MapLayer.java index eaf0b6155e..6cf997f9f0 100644 --- a/src/main/java/net/glowstone/generator/biomegrid/MapLayer.java +++ b/src/main/java/net/glowstone/generator/biomegrid/MapLayer.java @@ -16,6 +16,13 @@ public MapLayer(long seed) { this.seed = seed; } + /** + * Creates the instances for the given map. + * @param seed the world seed + * @param environment the type of dimension + * @param worldType the world generator + * @return an array of all map layers this dimension needs + */ public static MapLayer[] initialize(long seed, Environment environment, WorldType worldType) { if (environment == Environment.NORMAL && worldType == WorldType.FLAT) { return new MapLayer[]{new ConstantBiomeMapLayer(seed, Biome.PLAINS), null}; diff --git a/src/main/java/net/glowstone/generator/biomegrid/NoiseMapLayer.java b/src/main/java/net/glowstone/generator/biomegrid/NoiseMapLayer.java index 05eceaedc3..3973c6aa62 100644 --- a/src/main/java/net/glowstone/generator/biomegrid/NoiseMapLayer.java +++ b/src/main/java/net/glowstone/generator/biomegrid/NoiseMapLayer.java @@ -25,7 +25,16 @@ public int[] generateValues(int x, int z, int sizeX, int sizeZ) { val = nextInt(2) == 0 ? 3 : 0; } values[j + i * sizeX] = val; - //values[j + i * sizeX] = noise >= -0.5D ? (double) noise >= 0.57D ? 2 : noise <= 0.2D ? 3 : 2 : nextInt(2) == 0 ? 3 : 0; + //values[j + i * sizeX] = + // noise >= -0.5D + // ? (double) noise >= 0.57D + // ? 2 + // : noise <= 0.2D + // ? 3 + // : 2 + // : nextInt(2) == 0 + // ? 3 + // : 0; } } return values; diff --git a/src/main/java/net/glowstone/generator/biomegrid/RiverMapLayer.java b/src/main/java/net/glowstone/generator/biomegrid/RiverMapLayer.java index cb036a032e..635affcfca 100644 --- a/src/main/java/net/glowstone/generator/biomegrid/RiverMapLayer.java +++ b/src/main/java/net/glowstone/generator/biomegrid/RiverMapLayer.java @@ -39,6 +39,13 @@ public RiverMapLayer(long seed, MapLayer belowLayer) { this(seed, belowLayer, null); } + /** + * Creates a map layer that generates rivers. + * + * @param seed the layer's PRNG seed + * @param belowLayer the layer to apply before this one + * @param mergeLayer TODO: document this parameter + */ public RiverMapLayer(long seed, MapLayer belowLayer, MapLayer mergeLayer) { super(seed); this.belowLayer = belowLayer; @@ -82,16 +89,16 @@ private int[] generateRivers(int x, int z, int sizeX, int sizeZ) { private int[] mergeRivers(int x, int z, int sizeX, int sizeZ) { int[] values = belowLayer.generateValues(x, z, sizeX, sizeZ); - int[] mValues = mergeLayer.generateValues(x, z, sizeX, sizeZ); + int[] mergeValues = mergeLayer.generateValues(x, z, sizeX, sizeZ); int[] finalValues = new int[sizeX * sizeZ]; for (int i = 0; i < sizeX * sizeZ; i++) { - int val = mValues[i]; - if (OCEANS.contains(mValues[i])) { - val = mValues[i]; + int val = mergeValues[i]; + if (OCEANS.contains(mergeValues[i])) { + val = mergeValues[i]; } else if (values[i] == RIVER_VALUE) { - if (SPECIAL_RIVERS.containsKey(mValues[i])) { - val = SPECIAL_RIVERS.get(mValues[i]); + if (SPECIAL_RIVERS.containsKey(mergeValues[i])) { + val = SPECIAL_RIVERS.get(mergeValues[i]); } else { val = GlowBiome.getId(RIVER); } diff --git a/src/main/java/net/glowstone/generator/biomegrid/ShoreMapLayer.java b/src/main/java/net/glowstone/generator/biomegrid/ShoreMapLayer.java index b968c7ec35..aa48a40d91 100644 --- a/src/main/java/net/glowstone/generator/biomegrid/ShoreMapLayer.java +++ b/src/main/java/net/glowstone/generator/biomegrid/ShoreMapLayer.java @@ -94,12 +94,13 @@ public int[] generateValues(int x, int z, int sizeX, int sizeZ) { int leftVal = values[j + (i + 1) * gridSizeX]; int rightVal = values[j + 2 + (i + 1) * gridSizeX]; int centerVal = values[j + 1 + (i + 1) * gridSizeX]; - if (!OCEANS.contains(centerVal) && (OCEANS.contains(upperVal) || OCEANS - .contains(lowerVal) || - OCEANS.contains(leftVal) || OCEANS.contains(rightVal))) { + if (!OCEANS.contains(centerVal) && ( + OCEANS.contains(upperVal) || OCEANS.contains(lowerVal) + || OCEANS.contains(leftVal) || OCEANS.contains(rightVal))) { finalValues[j + i * sizeX] = - SPECIAL_SHORES.containsKey(centerVal) ? SPECIAL_SHORES.get(centerVal) - : GlowBiome.getId(BEACHES); + SPECIAL_SHORES.containsKey(centerVal) + ? SPECIAL_SHORES.get(centerVal) + : GlowBiome.getId(BEACHES); } else { finalValues[j + i * sizeX] = centerVal; } diff --git a/src/main/java/net/glowstone/generator/biomegrid/WhittakerMapLayer.java b/src/main/java/net/glowstone/generator/biomegrid/WhittakerMapLayer.java index 27539568f4..7d283d8df9 100644 --- a/src/main/java/net/glowstone/generator/biomegrid/WhittakerMapLayer.java +++ b/src/main/java/net/glowstone/generator/biomegrid/WhittakerMapLayer.java @@ -15,6 +15,13 @@ public class WhittakerMapLayer extends MapLayer { private final MapLayer belowLayer; private final ClimateType type; + /** + * Creates a map layer. TODO: improve documentation + * + * @param seed the layer random seed + * @param belowLayer the layer generated before this one + * @param type the climate-type parameter + */ public WhittakerMapLayer(long seed, MapLayer belowLayer, ClimateType type) { super(seed); this.belowLayer = belowLayer; diff --git a/src/main/java/net/glowstone/generator/biomegrid/ZoomMapLayer.java b/src/main/java/net/glowstone/generator/biomegrid/ZoomMapLayer.java index f4c00aeb9c..fadf6d44bc 100644 --- a/src/main/java/net/glowstone/generator/biomegrid/ZoomMapLayer.java +++ b/src/main/java/net/glowstone/generator/biomegrid/ZoomMapLayer.java @@ -9,6 +9,13 @@ public ZoomMapLayer(long seed, MapLayer belowLayer) { this(seed, belowLayer, ZoomType.NORMAL); } + /** + * Creates a map layer. TODO: improve documentation + * + * @param seed the layer random seed + * @param belowLayer the layer generated before this one + * @param zoomType the zoom-type parameter + */ public ZoomMapLayer(long seed, MapLayer belowLayer, ZoomType zoomType) { super(seed); this.belowLayer = belowLayer; @@ -31,12 +38,11 @@ public int[] generateValues(int x, int z, int sizeX, int sizeZ) { int upperLeftVal = values[i * gridSizeX]; int lowerLeftVal = values[(i + 1) * gridSizeX]; for (int j = 0; j < gridSizeX - 1; j++) { - int upperRightVal = values[j + 1 + i * gridSizeX]; - int lowerRightVal = values[j + 1 + (i + 1) * gridSizeX]; - setCoordsSeed(gridX + j << 1, gridZ + i << 1); tmpValues[n] = upperLeftVal; tmpValues[n + zoomSizeX] = nextInt(2) > 0 ? upperLeftVal : lowerLeftVal; + int upperRightVal = values[j + 1 + i * gridSizeX]; + int lowerRightVal = values[j + 1 + (i + 1) * gridSizeX]; tmpValues[n + 1] = nextInt(2) > 0 ? upperLeftVal : upperRightVal; tmpValues[n + 1 + zoomSizeX] = getNearest(upperLeftVal, upperRightVal, lowerLeftVal, lowerRightVal); diff --git a/src/main/java/net/glowstone/generator/decorators/nether/LavaDecorator.java b/src/main/java/net/glowstone/generator/decorators/nether/LavaDecorator.java index a9fce9c0bc..29c013d8fd 100644 --- a/src/main/java/net/glowstone/generator/decorators/nether/LavaDecorator.java +++ b/src/main/java/net/glowstone/generator/decorators/nether/LavaDecorator.java @@ -33,28 +33,27 @@ public void decorate(World world, Random random, Chunk source) { int sourceY = flowing ? 4 + random.nextInt(120) : 10 + random.nextInt(108); Block block = world.getBlockAt(sourceX, sourceY, sourceZ); - if ((block.getType() == Material.NETHERRACK || block.isEmpty()) && - block.getRelative(BlockFace.UP).getType() == Material.NETHERRACK) { - int netherrackBlockCount = 0; - for (BlockFace face : SIDES) { - if (block.getRelative(face).getType() == Material.NETHERRACK) { - netherrackBlockCount++; - } - } - int airBlockCount = 0; - for (BlockFace face : SIDES) { - if (block.getRelative(face).isEmpty()) { - airBlockCount++; - } + if ((block.getType() != Material.NETHERRACK && !block.isEmpty()) + || block.getRelative(BlockFace.UP).getType() != Material.NETHERRACK) { + return; + } + int netherrackBlockCount = 0; + int airBlockCount = 0; + for (BlockFace face : SIDES) { + Block neighbor = block.getRelative(face); + if (neighbor.getType() == Material.NETHERRACK) { + netherrackBlockCount++; + } else if (neighbor.isEmpty()) { + airBlockCount++; } + } - if (netherrackBlockCount == 5 - || flowing && airBlockCount == 1 && netherrackBlockCount == 4) { - BlockState state = block.getState(); - state.setType(Material.LAVA); - state.update(true); - new PulseTask((GlowBlock) block, true, 1, true).startPulseTask(); - } + if (netherrackBlockCount == 5 + || flowing && airBlockCount == 1 && netherrackBlockCount == 4) { + BlockState state = block.getState(); + state.setType(Material.LAVA); + state.update(true); + new PulseTask((GlowBlock) block, true, 1, true).startPulseTask(); } } } diff --git a/src/main/java/net/glowstone/generator/decorators/nether/MushroomDecorator.java b/src/main/java/net/glowstone/generator/decorators/nether/MushroomDecorator.java index 58e9cdf6dd..e40485cbff 100644 --- a/src/main/java/net/glowstone/generator/decorators/nether/MushroomDecorator.java +++ b/src/main/java/net/glowstone/generator/decorators/nether/MushroomDecorator.java @@ -17,6 +17,11 @@ public class MushroomDecorator extends BlockDecorator { private final Material type; + /** + * Creates a mushroom decorator for the nether. + * + * @param type {@link Material#BROWN_MUSHROOM} or {@link Material#RED_MUSHROOM} + */ public MushroomDecorator(Material type) { if (type != Material.BROWN_MUSHROOM && type != Material.RED_MUSHROOM) { throw new IllegalArgumentException( diff --git a/src/main/java/net/glowstone/generator/decorators/overworld/DoublePlantDecorator.java b/src/main/java/net/glowstone/generator/decorators/overworld/DoublePlantDecorator.java index 4e1780f048..33cdc7e1c4 100644 --- a/src/main/java/net/glowstone/generator/decorators/overworld/DoublePlantDecorator.java +++ b/src/main/java/net/glowstone/generator/decorators/overworld/DoublePlantDecorator.java @@ -3,6 +3,7 @@ import java.util.Arrays; import java.util.List; import java.util.Random; +import lombok.Data; import net.glowstone.generator.decorators.BlockDecorator; import net.glowstone.generator.objects.DoubleTallPlant; import org.bukkit.Chunk; @@ -43,22 +44,9 @@ private DoublePlantSpecies getRandomDoublePlant(Random random, return null; } - public static class DoublePlantDecoration { - + @Data + public static final class DoublePlantDecoration { private final DoublePlantSpecies species; private final int weight; - - public DoublePlantDecoration(DoublePlantSpecies species, int weight) { - this.species = species; - this.weight = weight; - } - - public DoublePlantSpecies getSpecies() { - return species; - } - - public int getWeight() { - return weight; - } } } diff --git a/src/main/java/net/glowstone/generator/decorators/overworld/FlowerDecorator.java b/src/main/java/net/glowstone/generator/decorators/overworld/FlowerDecorator.java index 2674339522..8c9e6ef81d 100644 --- a/src/main/java/net/glowstone/generator/decorators/overworld/FlowerDecorator.java +++ b/src/main/java/net/glowstone/generator/decorators/overworld/FlowerDecorator.java @@ -3,6 +3,7 @@ import java.util.Arrays; import java.util.List; import java.util.Random; +import lombok.Data; import net.glowstone.generator.decorators.BlockDecorator; import net.glowstone.generator.objects.Flower; import net.glowstone.generator.objects.FlowerType; @@ -45,22 +46,9 @@ private FlowerType getRandomFlower(Random random, List decorat return null; } - public static class FlowerDecoration { - + @Data + public static final class FlowerDecoration { private final FlowerType flower; private final int weight; - - public FlowerDecoration(FlowerType flower, int weight) { - this.flower = flower; - this.weight = weight; - } - - public FlowerType getFlower() { - return flower; - } - - public int getWeight() { - return weight; - } } } diff --git a/src/main/java/net/glowstone/generator/decorators/overworld/InfestedStoneDecorator.java b/src/main/java/net/glowstone/generator/decorators/overworld/InfestedStoneDecorator.java index f77e87a727..1acf75c534 100644 --- a/src/main/java/net/glowstone/generator/decorators/overworld/InfestedStoneDecorator.java +++ b/src/main/java/net/glowstone/generator/decorators/overworld/InfestedStoneDecorator.java @@ -25,9 +25,11 @@ public void decorate(World world, Random random, Chunk chunk) { for (int n = 0; n < 7; n++) { int sourceX = cx + random.nextInt(16); int sourceZ = cz + random.nextInt(16); - int sourceY = oreType.getMinY() == oreType.getMaxY() ? - random.nextInt(oreType.getMinY()) + random.nextInt(oreType.getMinY()) : - random.nextInt(oreType.getMaxY() - oreType.getMinY()) + oreType.getMinY(); + int minY = oreType.getMinY(); + int maxY = oreType.getMaxY(); + int sourceY = minY == maxY + ? random.nextInt(minY) + random.nextInt(minY) + : random.nextInt(maxY - minY) + minY; new OreVein(oreType).generate(world, random, sourceX, sourceY, sourceZ); } diff --git a/src/main/java/net/glowstone/generator/decorators/overworld/LakeDecorator.java b/src/main/java/net/glowstone/generator/decorators/overworld/LakeDecorator.java index 439c84fcc8..f1a42fee96 100644 --- a/src/main/java/net/glowstone/generator/decorators/overworld/LakeDecorator.java +++ b/src/main/java/net/glowstone/generator/decorators/overworld/LakeDecorator.java @@ -11,6 +11,11 @@ public class LakeDecorator extends BlockDecorator { private final Material type; + /** + * Creates a lake decorator. + * + * @param type {@link Material#STATIONARY_WATER} or {@link Material#STATIONARY_LAVA} + */ public LakeDecorator(Material type) { if (type != Material.STATIONARY_WATER && type != Material.STATIONARY_LAVA) { throw new IllegalArgumentException( diff --git a/src/main/java/net/glowstone/generator/decorators/overworld/MelonDecorator.java b/src/main/java/net/glowstone/generator/decorators/overworld/MelonDecorator.java index 6fc376aa8f..58cdd1e864 100644 --- a/src/main/java/net/glowstone/generator/decorators/overworld/MelonDecorator.java +++ b/src/main/java/net/glowstone/generator/decorators/overworld/MelonDecorator.java @@ -21,8 +21,8 @@ public void populate(World world, Random random, Chunk source) { int z = sourceZ + random.nextInt(8) - random.nextInt(8); int y = sourceY + random.nextInt(4) - random.nextInt(4); - if (world.getBlockAt(x, y, z).getType() == Material.AIR && - world.getBlockAt(x, y - 1, z).getType() == Material.GRASS) { + if (world.getBlockAt(x, y, z).getType() == Material.AIR + && world.getBlockAt(x, y - 1, z).getType() == Material.GRASS) { BlockState state = world.getBlockAt(x, y, z).getState(); state.setType(Material.MELON_BLOCK); state.setData(new MaterialData(Material.MELON_BLOCK)); diff --git a/src/main/java/net/glowstone/generator/decorators/overworld/MushroomDecorator.java b/src/main/java/net/glowstone/generator/decorators/overworld/MushroomDecorator.java index b597e91b59..dbb020853d 100644 --- a/src/main/java/net/glowstone/generator/decorators/overworld/MushroomDecorator.java +++ b/src/main/java/net/glowstone/generator/decorators/overworld/MushroomDecorator.java @@ -17,6 +17,11 @@ public class MushroomDecorator extends BlockDecorator { private boolean fixedHeightRange; private double density; + /** + * Creates a mushroom decorator for the overworld. + * + * @param type {@link Material#BROWN_MUSHROOM} or {@link Material#RED_MUSHROOM} + */ public MushroomDecorator(Material type) { if (type != Material.BROWN_MUSHROOM && type != Material.RED_MUSHROOM) { throw new IllegalArgumentException( @@ -51,18 +56,33 @@ public void decorate(World world, Random random, Chunk source) { Block block = world.getBlockAt(x, y, z); Block blockBelow = world.getBlockAt(x, y - 1, z); - if (y < 255 && block.getType() == Material.AIR && - ((blockBelow.getType() == Material.GRASS - || blockBelow.getState().getData() instanceof Dirt && - ((Dirt) blockBelow.getState().getData()).getType() != DirtType.PODZOL) - && block.getLightLevel() < 13 || - blockBelow.getType() == Material.MYCEL - || blockBelow.getState().getData() instanceof Dirt && - ((Dirt) blockBelow.getState().getData()).getType() == DirtType.PODZOL)) { - BlockState state = block.getState(); - state.setType(type); - state.setData(new MaterialData(type)); - state.update(true); + if (y < 255 && block.getType() == Material.AIR) { + boolean canPlaceShroom; + switch (blockBelow.getType()) { + case MYCEL: + canPlaceShroom = true; + break; + case GRASS: + canPlaceShroom = (block.getLightLevel() < 13); + break; + case DIRT: + MaterialData data = blockBelow.getState().getData(); + if (data instanceof Dirt) { + canPlaceShroom = (((Dirt) data).getType() == DirtType.PODZOL + || block.getLightLevel() < 13); + } else { + canPlaceShroom = false; + } + break; + default: + canPlaceShroom = false; + } + if (canPlaceShroom) { + BlockState state = block.getState(); + state.setType(type); + state.setData(new MaterialData(type)); + state.update(true); + } } } } diff --git a/src/main/java/net/glowstone/generator/decorators/overworld/PumpkinDecorator.java b/src/main/java/net/glowstone/generator/decorators/overworld/PumpkinDecorator.java index 2f0366238a..5c1719ca08 100644 --- a/src/main/java/net/glowstone/generator/decorators/overworld/PumpkinDecorator.java +++ b/src/main/java/net/glowstone/generator/decorators/overworld/PumpkinDecorator.java @@ -26,8 +26,8 @@ public void populate(World world, Random random, Chunk source) { int z = sourceZ + random.nextInt(8) - random.nextInt(8); int y = sourceY + random.nextInt(4) - random.nextInt(4); - if (world.getBlockAt(x, y, z).getType() == Material.AIR && - world.getBlockAt(x, y - 1, z).getType() == Material.GRASS) { + if (world.getBlockAt(x, y, z).getType() == Material.AIR + && world.getBlockAt(x, y - 1, z).getType() == Material.GRASS) { BlockState state = world.getBlockAt(x, y, z).getState(); state.setType(Material.PUMPKIN); // random facing diff --git a/src/main/java/net/glowstone/generator/decorators/overworld/SurfaceCaveDecorator.java b/src/main/java/net/glowstone/generator/decorators/overworld/SurfaceCaveDecorator.java index da6272828a..28e5ac8e6d 100644 --- a/src/main/java/net/glowstone/generator/decorators/overworld/SurfaceCaveDecorator.java +++ b/src/main/java/net/glowstone/generator/decorators/overworld/SurfaceCaveDecorator.java @@ -22,15 +22,17 @@ public void decorate(World world, Random random, Chunk c) { return; } GlowChunk chunk = (GlowChunk) c; - final int startCx = random.nextInt(16), startCz = random.nextInt(16), startY = chunk - .getHeight(startCx, startCz); + final int startCx = random.nextInt(16); + final int startCz = random.nextInt(16); + final int startY = chunk.getHeight(startCx, startCz); final GlowBlock startBlock = chunk.getBlock(startCx, startY, startCz); if (startY > 128) { return; } PerlinOctaveGenerator octaves = new PerlinOctaveGenerator(random, 3, 4, 2, 4); - int cX = c.getX() << 4, cZ = c.getZ() << 4; - double[] noise = octaves.getFractalBrownianMotion(cX, cZ, 0, 0.5D, 0.2D); + int cx = c.getX() << 4; + int cz = c.getZ() << 4; + double[] noise = octaves.getFractalBrownianMotion(cx, cz, 0, 0.5D, 0.2D); double[] angles = new double[noise.length]; for (int i = 0; i < noise.length; i++) { angles[i] = 360.0 * noise[i]; @@ -62,13 +64,16 @@ public void decorate(World world, Random random, Chunk c) { private void caveAroundRay(GlowBlock block, Random random) { int radius = random.nextInt(2) + 2; - final int bX = block.getX(), bY = block.getY(), bZ = block.getZ(); - for (int x = bX - radius; x <= bX + radius; x++) { - for (int y = bY - radius; y <= bY + radius; y++) { - for (int z = bZ - radius; z <= bZ + radius; z++) { - double distance = - (bX - x) * (bX - x) + (bY - y) * (bY - y) + (bZ - z) * (bZ - z); - if (distance < radius * radius) { + final int blockX = block.getX(); + final int blockY = block.getY(); + final int blockZ = block.getZ(); + for (int x = blockX - radius; x <= blockX + radius; x++) { + for (int y = blockY - radius; y <= blockY + radius; y++) { + for (int z = blockZ - radius; z <= blockZ + radius; z++) { + double distanceSquared = + (blockX - x) * (blockX - x) + (blockY - y) * (blockY - y) + + (blockZ - z) * (blockZ - z); + if (distanceSquared < radius * radius) { GlowBlock pocket = block.getWorld().getBlockAt(x, y, z); pocket.setType(Material.AIR); } diff --git a/src/main/java/net/glowstone/generator/decorators/overworld/TreeDecorator.java b/src/main/java/net/glowstone/generator/decorators/overworld/TreeDecorator.java index 4e1e1616a5..8b2732996e 100644 --- a/src/main/java/net/glowstone/generator/decorators/overworld/TreeDecorator.java +++ b/src/main/java/net/glowstone/generator/decorators/overworld/TreeDecorator.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.List; import java.util.Random; +import lombok.Data; import net.glowstone.generator.decorators.BlockDecorator; import net.glowstone.generator.objects.trees.GenericTree; import net.glowstone.util.BlockStateDelegate; @@ -47,9 +48,9 @@ public void decorate(World world, Random random, Chunk source) { .getConstructor(Random.class, Location.class, BlockStateDelegate.class); tree = c.newInstance(random, sourceBlock.getLocation(), delegate); } catch (Exception ex) { - tree = new GenericTree(random, sourceBlock.getLocation(), delegate); + tree = new GenericTree(random, delegate); } - if (tree.generate()) { + if (tree.generate(sourceBlock.getLocation())) { delegate.updateBlockStates(); } } @@ -71,22 +72,9 @@ private Class getRandomTree(Random random, return null; } - public static class TreeDecoration { - + @Data + public static final class TreeDecoration { private final Class tree; private final int weight; - - public TreeDecoration(Class tree, int weight) { - this.tree = tree; - this.weight = weight; - } - - public Class getTree() { - return tree; - } - - public int getWeight() { - return weight; - } } } diff --git a/src/main/java/net/glowstone/generator/decorators/overworld/UnderwaterDecorator.java b/src/main/java/net/glowstone/generator/decorators/overworld/UnderwaterDecorator.java index ca665562a4..9fe4c38aa3 100644 --- a/src/main/java/net/glowstone/generator/decorators/overworld/UnderwaterDecorator.java +++ b/src/main/java/net/glowstone/generator/decorators/overworld/UnderwaterDecorator.java @@ -10,17 +10,24 @@ public class UnderwaterDecorator extends BlockDecorator { private final Material type; - private int hRadius; - private int vRadius; + private int horizRadius; + private int vertRadius; private Material[] overridables; public UnderwaterDecorator(Material type) { this.type = type; } - public final UnderwaterDecorator setRadii(int hRadius, int vRadius) { - this.hRadius = hRadius; - this.vRadius = vRadius; + /** + * Updates the size of this decorator. + * + * @param horizRadius the maximum radius on the horizontal plane + * @param vertRadius the depth above and below the center + * @return this, updated + */ + public final UnderwaterDecorator setRadii(int horizRadius, int vertRadius) { + this.horizRadius = horizRadius; + this.vertRadius = vertRadius; return this; } @@ -43,7 +50,7 @@ public void decorate(World world, Random random, Chunk source) { } Material material = world.getBlockAt(sourceX, sourceY, sourceZ).getType(); if (material == Material.STATIONARY_WATER || material == Material.WATER) { - new BlockPatch(type, hRadius, vRadius, overridables) + new BlockPatch(type, horizRadius, vertRadius, overridables) .generate(world, random, sourceX, sourceY, sourceZ); } } diff --git a/src/main/java/net/glowstone/generator/ground/GroundGenerator.java b/src/main/java/net/glowstone/generator/ground/GroundGenerator.java index 6a6793cc90..1e021cf120 100644 --- a/src/main/java/net/glowstone/generator/ground/GroundGenerator.java +++ b/src/main/java/net/glowstone/generator/ground/GroundGenerator.java @@ -30,6 +30,17 @@ public GroundGenerator() { setGroundMaterial(DIRT); } + /** + * Generates a terrain column. + * + * @param chunkData the affected chunk + * @param world the affected world + * @param random the PRNG to use + * @param x the chunk X coordinate + * @param z the chunk Z coordinate + * @param biome the biome this column is in + * @param surfaceNoise the amplitude of random variation in surface height + */ public void generateTerrainColumn(ChunkData chunkData, World world, Random random, int x, int z, Biome biome, double surfaceNoise) { @@ -79,8 +90,8 @@ public void generateTerrainColumn(ChunkData chunkData, World world, Random rando groundMat = SANDSTONE; } } - } else if (mat == Material.STATIONARY_WATER && y == seaLevel - 2 && - GlowBiomeClimate.isCold(biome, chunkX, y, chunkZ)) { + } else if (mat == Material.STATIONARY_WATER && y == seaLevel - 2 + && GlowBiomeClimate.isCold(biome, chunkX, y, chunkZ)) { chunkData.setBlock(x, y, z, Material.ICE); } } diff --git a/src/main/java/net/glowstone/generator/ground/MesaGroundGenerator.java b/src/main/java/net/glowstone/generator/ground/MesaGroundGenerator.java index abacf5c35f..202bb7d191 100644 --- a/src/main/java/net/glowstone/generator/ground/MesaGroundGenerator.java +++ b/src/main/java/net/glowstone/generator/ground/MesaGroundGenerator.java @@ -28,6 +28,11 @@ public MesaGroundGenerator() { this(MesaType.NORMAL); } + /** + * Creates a ground generator for mesa biomes. + * + * @param type the type of mesa biome to generate + */ public MesaGroundGenerator(MesaType type) { this.type = type; topMaterial = RED_SAND; @@ -66,12 +71,12 @@ public void generateTerrainColumn(ChunkData chunkData, World world, Random rando boolean colored = Math.cos(surfaceNoise / 3.0D * Math.PI) <= 0; double bryceCanyonHeight = 0; if (type == MesaType.BRYCE) { - int nX = (x & 0xFFFFFFF0) + (z & 0xF); - int nZ = (z & 0xFFFFFFF0) + (x & 0xF); + int noiseX = (x & 0xFFFFFFF0) + (z & 0xF); + int noiseZ = (z & 0xFFFFFFF0) + (x & 0xF); double noiseCanyonHeight = Math - .min(Math.abs(surfaceNoise), canyonHeightNoise.noise(nX, nZ, 0.5D, 2.0D)); + .min(Math.abs(surfaceNoise), canyonHeightNoise.noise(noiseX, noiseZ, 0.5D, 2.0D)); if (noiseCanyonHeight > 0) { - double heightScale = Math.abs(canyonScaleNoise.noise(nX, nZ, 0.5D, 2.0D)); + double heightScale = Math.abs(canyonScaleNoise.noise(noiseX, noiseZ, 0.5D, 2.0D)); bryceCanyonHeight = Math.pow(noiseCanyonHeight, 2) * 2.5D; double maxHeight = Math.ceil(50 * heightScale) + 14; if (bryceCanyonHeight > maxHeight) { diff --git a/src/main/java/net/glowstone/generator/objects/FlowerType.java b/src/main/java/net/glowstone/generator/objects/FlowerType.java index 4b30915611..b693653022 100644 --- a/src/main/java/net/glowstone/generator/objects/FlowerType.java +++ b/src/main/java/net/glowstone/generator/objects/FlowerType.java @@ -1,7 +1,10 @@ package net.glowstone.generator.objects; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.bukkit.Material; +@RequiredArgsConstructor public enum FlowerType { DANDELION(Material.YELLOW_FLOWER, 0), POPPY(Material.RED_ROSE, 0), @@ -14,20 +17,9 @@ public enum FlowerType { TULIP_PINK(Material.RED_ROSE, 7), OXEYE_DAISY(Material.RED_ROSE, 8); + @Getter private final Material type; + @Getter private final int data; - - FlowerType(Material type, int data) { - this.type = type; - this.data = data; - } - - public Material getType() { - return type; - } - - public int getData() { - return data; - } } diff --git a/src/main/java/net/glowstone/generator/objects/ObsidianPillar.java b/src/main/java/net/glowstone/generator/objects/ObsidianPillar.java index c3f895813d..81172719c7 100644 --- a/src/main/java/net/glowstone/generator/objects/ObsidianPillar.java +++ b/src/main/java/net/glowstone/generator/objects/ObsidianPillar.java @@ -9,6 +9,7 @@ public class ObsidianPillar implements TerrainObject { + @Override public boolean generate(World world, Random random, int sourceX, int sourceY, int sourceZ) { if (!world.getBlockAt(sourceX, sourceY, sourceZ).isEmpty() || world.getBlockAt(sourceX, sourceY - 1, sourceZ).getType() diff --git a/src/main/java/net/glowstone/generator/objects/OreType.java b/src/main/java/net/glowstone/generator/objects/OreType.java index 01f3e0deef..0a1523a581 100644 --- a/src/main/java/net/glowstone/generator/objects/OreType.java +++ b/src/main/java/net/glowstone/generator/objects/OreType.java @@ -1,15 +1,23 @@ package net.glowstone.generator.objects; +import java.util.Random; +import lombok.Getter; import org.bukkit.Material; import org.bukkit.material.MaterialData; public class OreType { + @Getter private final Material type; + @Getter private final MaterialData data; + @Getter private final int minY; + @Getter private final int maxY; + @Getter private final int amount; + @Getter private final Material targetType; public OreType(Material type, int minY, int maxY, int amount) { @@ -24,6 +32,18 @@ public OreType(Material type, MaterialData data, int minY, int maxY, int amount) this(type, data, minY, maxY, amount, Material.STONE); } + /** + * Creates an ore type. If {@code minY} and {@code maxY} are equal, then the height range is + * 0 to {@code minY}*2, with greatest density around {@code minY}. Otherwise, density is uniform + * over the height range. + * + * @param type the block type + * @param data the block data value + * @param minY the minimum height + * @param maxY the maximum height + * @param amount the size of a vein + * @param targetType the block this can replace + */ public OreType(Material type, MaterialData data, int minY, int maxY, int amount, Material targetType) { this.type = type; @@ -34,27 +54,15 @@ public OreType(Material type, MaterialData data, int minY, int maxY, int amount, this.targetType = targetType; } - public Material getType() { - return type; - } - - public MaterialData getData() { - return data; - } - - public int getMinY() { - return minY; - } - - public int getMaxY() { - return maxY; - } - - public int getAmount() { - return amount; - } - - public Material getTargetType() { - return targetType; + /** + * Generates a random height at which a vein of this ore can spawn. + * + * @param random the PRNG to use + * @return a random height for this ore + */ + public int getRandomHeight(Random random) { + return getMinY() == getMaxY() + ? random.nextInt(getMinY()) + random.nextInt(getMinY()) + : random.nextInt(getMaxY() - getMinY()) + getMinY(); } } diff --git a/src/main/java/net/glowstone/generator/objects/OreVein.java b/src/main/java/net/glowstone/generator/objects/OreVein.java index 2d077375fc..e157697507 100644 --- a/src/main/java/net/glowstone/generator/objects/OreVein.java +++ b/src/main/java/net/glowstone/generator/objects/OreVein.java @@ -13,6 +13,11 @@ public class OreVein implements TerrainObject { private final int amount; private final Material targetType; + /** + * Creates the instance for a given ore type. + * + * @param oreType the ore type + */ public OreVein(OreType oreType) { type = oreType.getType(); data = oreType.getData(); @@ -20,6 +25,7 @@ public OreVein(OreType oreType) { targetType = oreType.getTargetType(); } + @Override public boolean generate(World world, Random random, int sourceX, int sourceY, int sourceZ) { float angle = random.nextFloat() * (float) Math.PI; double dx1 = sourceX + Math.sin(angle) * amount / 8.0F; @@ -34,25 +40,25 @@ public boolean generate(World world, Random random, int sourceX, int sourceY, in double originY = dy1 + (dy2 - dy1) * i / amount; double originZ = dz1 + (dz2 - dz1) * i / amount; double q = random.nextDouble() * amount / 16.0D; - double hRadius = (Math.sin(i * (float) Math.PI / amount) + 1 * q + 1) / 2.0D; - double vRadius = (Math.sin(i * (float) Math.PI / amount) + 1 * q + 1) / 2.0D; - for (int x = (int) (originX - hRadius); x <= (int) (originX - hRadius); x++) { - double pX = (x + 0.5D - originX) / hRadius; - pX *= pX; - if (pX >= 1) { + double radiusH = (Math.sin(i * (float) Math.PI / amount) + 1 * q + 1) / 2.0D; + double radiusV = (Math.sin(i * (float) Math.PI / amount) + 1 * q + 1) / 2.0D; + for (int x = (int) (originX - radiusH); x <= (int) (originX - radiusH); x++) { + + // scale the center of x to the range [-1, 1] within the circle + double squaredNormalizedX = normalizedSquaredCoordinate(originX, radiusH, x); + if (squaredNormalizedX >= 1) { continue; } - for (int y = (int) (originY - vRadius); y <= (int) (originY + vRadius); y++) { - double pY = (y + 0.5D - originY) / vRadius; - pY *= pY; - if (pX + pY >= 1) { + for (int y = (int) (originY - radiusV); y <= (int) (originY + radiusV); y++) { + double squaredNormalizedY = normalizedSquaredCoordinate(originY, radiusV, y); + if (squaredNormalizedX + squaredNormalizedY >= 1) { continue; } - for (int z = (int) (originZ - hRadius); z <= (int) (originZ + hRadius); + for (int z = (int) (originZ - radiusH); z <= (int) (originZ + radiusH); z++) { - double pZ = (z + 0.5D - originZ) / hRadius; - pZ *= pZ; - if (pX + pY + pZ < 1 + double squaredNormalizedZ + = normalizedSquaredCoordinate(originZ, radiusH, z); + if (squaredNormalizedX + squaredNormalizedY + squaredNormalizedZ < 1 && world.getBlockAt(x, y, z).getType() == targetType) { BlockState state = world.getBlockAt(x, y, z).getState(); state.setType(type); @@ -66,4 +72,20 @@ public boolean generate(World world, Random random, int sourceX, int sourceY, in } return succeeded; } + + /** + * The square of the percentage of the radius that is the distance between the given block's + * center and the center of an orthogonal ellipsoid. A block's center is inside the ellipsoid + * if and only if its normalizedSquaredCoordinate values add up to less than 1. + * + * @param origin the center of the spheroid + * @param radius the spheroid's radius on this axis + * @param x the raw coordinate + * @return the square of the normalized coordinate + */ + protected static double normalizedSquaredCoordinate(double origin, double radius, int x) { + double squaredNormalizedX = (x + 0.5D - origin) / radius; + squaredNormalizedX *= squaredNormalizedX; + return squaredNormalizedX; + } } diff --git a/src/main/java/net/glowstone/generator/objects/RandomItemsContent.java b/src/main/java/net/glowstone/generator/objects/RandomItemsContent.java index ed063da779..b82544264f 100644 --- a/src/main/java/net/glowstone/generator/objects/RandomItemsContent.java +++ b/src/main/java/net/glowstone/generator/objects/RandomItemsContent.java @@ -12,7 +12,6 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; -import org.bukkit.material.DirectionalContainer; public class RandomItemsContent { @@ -22,8 +21,15 @@ public void addItem(RandomAmountItem item, int weight) { content.put(item, weight); } - public boolean fillContainer(Random random, DirectionalContainer container, BlockState state, - int maxStacks) { + /** + * Populates a container with random items. + * + * @param random the PRNG to use + * @param state the block state for a container block + * @param maxStacks the maximum number of slots to fill + * @return true if successful (currently always true) + */ + public boolean fillContainer(Random random, BlockState state, int maxStacks) { if (state.getBlock().getState() instanceof InventoryHolder) { Inventory inventory = ((InventoryHolder) state.getBlock().getState()).getInventory(); int size = inventory.getSize(); @@ -43,6 +49,12 @@ public boolean fillContainer(Random random, DirectionalContainer container, Bloc return true; } + /** + * Choose a random {@link RandomAmountItem}. + * + * @param random the PRNG to use + * @return the random item + */ public RandomAmountItem getRandomItem(Random random) { int totalWeight = 0; for (int i : content.values()) { @@ -75,6 +87,12 @@ public RandomAmountItem(Material type, int data, int minAmount, int maxAmount) { this.maxAmount = maxAmount; } + /** + * Generate a random set of items. + * + * @param random the PRNG to use + * @return an immutable collection of randomly-generated items + */ public Collection getItemStacks(Random random) { int minAmount = stack.getAmount(); int amount = random.nextInt(maxAmount - minAmount + 1) + minAmount; diff --git a/src/main/java/net/glowstone/generator/objects/StoneBoulder.java b/src/main/java/net/glowstone/generator/objects/StoneBoulder.java index 7f4482b6ef..ec73dc5ec1 100644 --- a/src/main/java/net/glowstone/generator/objects/StoneBoulder.java +++ b/src/main/java/net/glowstone/generator/objects/StoneBoulder.java @@ -1,6 +1,8 @@ package net.glowstone.generator.objects; +import com.google.common.collect.ImmutableSortedSet; import java.util.Random; +import java.util.SortedSet; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; @@ -13,8 +15,9 @@ public class StoneBoulder implements TerrainObject { private static final Material[] GROUND_TYPES = {Material.GRASS, Material.DIRT, Material.STONE}; - private static final Material[] PLANT_TYPES = {Material.LONG_GRASS, Material.YELLOW_FLOWER, - Material.RED_ROSE, Material.DOUBLE_PLANT, Material.BROWN_MUSHROOM, Material.RED_MUSHROOM}; + private static final SortedSet PLANT_TYPES = ImmutableSortedSet + .of(Material.LONG_GRASS, Material.YELLOW_FLOWER, Material.RED_ROSE, + Material.DOUBLE_PLANT, Material.BROWN_MUSHROOM, Material.RED_MUSHROOM); @Override public boolean generate(World world, Random random, int sourceX, int sourceY, int sourceZ) { @@ -43,28 +46,29 @@ public boolean generate(World world, Random random, int sourceX, int sourceY, in for (int x = -radiusX; x <= radiusX; x++) { for (int z = -radiusZ; z <= radiusZ; z++) { for (int y = -radiusY; y <= radiusY; y++) { - if (x * x + z * z + y * y <= f * f) { - BlockState state = world - .getBlockAt(sourceX + x, sourceY + y, sourceZ + z).getState(); - Block blockAbove = state.getBlock().getRelative(BlockFace.UP); - for (Material mat : PLANT_TYPES) { - if (blockAbove.getType() == mat) { - if (mat == Material.DOUBLE_PLANT && blockAbove.getState() - .getData() instanceof DoublePlant && - ((DoublePlant) blockAbove.getState().getData()) - .getSpecies() - == DoublePlantSpecies.PLANT_APEX) { - blockAbove.getRelative(BlockFace.UP) - .setType(Material.AIR); - } - blockAbove.setType(Material.AIR); - break; + if (x * x + z * z + y * y > f * f) { + continue; + } + BlockState state = world + .getBlockAt(sourceX + x, sourceY + y, sourceZ + z).getState(); + Block blockAbove = state.getBlock().getRelative(BlockFace.UP); + Material mat = blockAbove.getType(); + if (PLANT_TYPES.contains(mat)) { + if (mat == Material.DOUBLE_PLANT) { + MaterialData dataAbove = blockAbove.getState().getData(); + if (dataAbove instanceof DoublePlant + && ((DoublePlant) dataAbove).getSpecies() + == DoublePlantSpecies.PLANT_APEX) { + blockAbove.getRelative(BlockFace.UP) + .setType(Material.AIR); } } - state.setType(Material.MOSSY_COBBLESTONE); - state.setData(new MaterialData(Material.MOSSY_COBBLESTONE)); - state.update(true); + blockAbove.setType(Material.AIR); + break; } + state.setType(Material.MOSSY_COBBLESTONE); + state.setData(new MaterialData(Material.MOSSY_COBBLESTONE)); + state.update(true); } } } diff --git a/src/main/java/net/glowstone/generator/objects/SugarCane.java b/src/main/java/net/glowstone/generator/objects/SugarCane.java index ee7d28986c..0175b9db5a 100644 --- a/src/main/java/net/glowstone/generator/objects/SugarCane.java +++ b/src/main/java/net/glowstone/generator/objects/SugarCane.java @@ -24,8 +24,8 @@ public boolean generate(World world, Random random, int x, int y, int z) { boolean adjacentWater = false; for (BlockFace face : FACES) { // needs a directly adjacent water block - if (block.getRelative(face).getType() == Material.STATIONARY_WATER || - block.getRelative(face).getType() == Material.WATER) { + Material blockType = block.getRelative(face).getType(); + if (blockType == Material.STATIONARY_WATER || blockType == Material.WATER) { adjacentWater = true; break; } diff --git a/src/main/java/net/glowstone/generator/objects/TallGrass.java b/src/main/java/net/glowstone/generator/objects/TallGrass.java index 35c8eed62e..981bbe7fea 100644 --- a/src/main/java/net/glowstone/generator/objects/TallGrass.java +++ b/src/main/java/net/glowstone/generator/objects/TallGrass.java @@ -16,12 +16,14 @@ public TallGrass(LongGrass grassType) { this.grassType = grassType; } + @Override public boolean generate(World world, Random random, int sourceX, int sourceY, int sourceZ) { - while ((world.getBlockAt(sourceX, sourceY, sourceZ).isEmpty() || - world.getBlockAt(sourceX, sourceY, sourceZ).getType() == Material.LEAVES) && - sourceY > 0) { + Block thisBlock; + do { + thisBlock = world.getBlockAt(sourceX, sourceY, sourceZ); sourceY--; - } + } while ((thisBlock.isEmpty() || thisBlock.getType() == Material.LEAVES) && sourceY > 0); + sourceY++; boolean succeeded = false; for (int i = 0; i < 128; i++) { int x = sourceX + random.nextInt(8) - random.nextInt(8); @@ -29,9 +31,9 @@ public boolean generate(World world, Random random, int sourceX, int sourceY, in int y = sourceY + random.nextInt(4) - random.nextInt(4); Block block = world.getBlockAt(x, y, z); + Material blockTypeBelow = block.getRelative(BlockFace.DOWN).getType(); if (y < 255 && block.getType() == Material.AIR && ( - block.getRelative(BlockFace.DOWN).getType() == Material.GRASS || - block.getRelative(BlockFace.DOWN).getType() == Material.DIRT)) { + blockTypeBelow == Material.GRASS || blockTypeBelow == Material.DIRT)) { BlockState state = block.getState(); state.setType(Material.LONG_GRASS); state.setData(grassType); diff --git a/src/main/java/net/glowstone/generator/objects/trees/AcaciaTree.java b/src/main/java/net/glowstone/generator/objects/trees/AcaciaTree.java index 80026d56f7..3967e3eccd 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/AcaciaTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/AcaciaTree.java @@ -2,9 +2,8 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.block.BlockFace; +import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.material.Dirt; import org.bukkit.material.types.DirtType; @@ -13,28 +12,23 @@ public class AcaciaTree extends GenericTree { /** * Initializes this tree with a random height, preparing it to attempt to generate. - * - * @param random the PRNG - * @param location the base of the trunk + * @param random the PRNG * @param delegate the BlockStateDelegate used to check for space and to fill wood and leaf - * blocks */ - public AcaciaTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public AcaciaTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); setHeight(random.nextInt(3) + random.nextInt(3) + 5); } @Override - public boolean canPlaceOn() { - BlockState state = delegate - .getBlockState(loc.getBlock().getRelative(BlockFace.DOWN).getLocation()); - return state.getType() == Material.GRASS || state.getType() == Material.DIRT; + public boolean canPlaceOn(BlockState soil) { + return soil.getType() == Material.GRASS || soil.getType() == Material.DIRT; } @Override - public boolean generate() { + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { - if (!canHeightFit() || !canPlaceOn() || !canPlace()) { + if (cannotGenerateAt(blockX, blockY, blockZ, world)) { return false; } @@ -50,10 +44,9 @@ public boolean generate() { } int twistHeight = height - 1 - random.nextInt(4); int twistCount = random.nextInt(3) + 1; - int centerX = loc.getBlockX(); - int centerZ = loc.getBlockZ(); + int centerX = blockX; + int centerZ = blockZ; int trunkTopY = 0; - // generates the trunk for (int y = 0; y < height; y++) { @@ -64,10 +57,10 @@ public boolean generate() { twistCount--; } - Material material = blockTypeAt(centerX, loc.getBlockY() + y, centerZ); + Material material = blockTypeAt(centerX, blockY + y, centerZ, world); if (material == Material.AIR || material == Material.LEAVES) { - trunkTopY = loc.getBlockY() + y; - delegate.setTypeAndRawData(loc.getWorld(), centerX, loc.getBlockY() + y, centerZ, + trunkTopY = blockY + y; + delegate.setTypeAndRawData(world, centerX, blockY + y, centerZ, Material.LOG_2, 0); } } @@ -76,13 +69,13 @@ public boolean generate() { for (int x = -3; x <= 3; x++) { for (int z = -3; z <= 3; z++) { if (Math.abs(x) < 3 || Math.abs(z) < 3) { - setLeaves(centerX + x, trunkTopY, centerZ + z); + setLeaves(centerX + x, trunkTopY, centerZ + z, world); } if (Math.abs(x) < 2 && Math.abs(z) < 2) { - setLeaves(centerX + x, trunkTopY + 1, centerZ + z); + setLeaves(centerX + x, trunkTopY + 1, centerZ + z, world); } if (Math.abs(x) == 2 && Math.abs(z) == 0 || Math.abs(x) == 0 && Math.abs(z) == 2) { - setLeaves(centerX + x, trunkTopY + 1, centerZ + z); + setLeaves(centerX + x, trunkTopY + 1, centerZ + z, world); } } } @@ -99,8 +92,8 @@ public boolean generate() { } } if (dx != dxB || dz != dzB) { - centerX = loc.getBlockX(); - centerZ = loc.getBlockZ(); + centerX = blockX; + centerZ = blockZ; int branchHeight = twistHeight - 1 - random.nextInt(2); twistCount = random.nextInt(3) + 1; trunkTopY = 0; @@ -110,10 +103,10 @@ public boolean generate() { if (twistCount > 0) { centerX += dxB; centerZ += dzB; - Material material = blockTypeAt(centerX, loc.getBlockY() + y, centerZ); + Material material = blockTypeAt(centerX, blockY + y, centerZ, world); if (material == Material.AIR || material == Material.LEAVES) { - trunkTopY = loc.getBlockY() + y; - delegate.setTypeAndRawData(loc.getWorld(), centerX, loc.getBlockY() + y, + trunkTopY = blockY + y; + delegate.setTypeAndRawData(world, centerX, blockY + y, centerZ, Material.LOG_2, 0); } twistCount--; @@ -125,13 +118,13 @@ public boolean generate() { for (int x = -2; x <= 2; x++) { for (int z = -2; z <= 2; z++) { if (Math.abs(x) < 2 || Math.abs(z) < 2) { - setLeaves(centerX + x, trunkTopY, centerZ + z); + setLeaves(centerX + x, trunkTopY, centerZ + z, world); } } } for (int x = -1; x <= 1; x++) { for (int z = -1; z <= 1; z++) { - setLeaves(centerX + x, trunkTopY + 1, centerZ + z); + setLeaves(centerX + x, trunkTopY + 1, centerZ + z, world); } } } @@ -139,16 +132,14 @@ public boolean generate() { // block below trunk is always dirt Dirt dirt = new Dirt(DirtType.NORMAL); - delegate - .setTypeAndData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() - 1, loc.getBlockZ(), - Material.DIRT, dirt); + delegate.setTypeAndData(world, blockX, blockY - 1, blockZ, Material.DIRT, dirt); return true; } - private void setLeaves(int x, int y, int z) { - if (blockTypeAt(x, y, z) == Material.AIR) { - delegate.setTypeAndRawData(loc.getWorld(), x, y, z, Material.LEAVES_2, 0); + private void setLeaves(int x, int y, int z, World world) { + if (blockTypeAt(x, y, z, world) == Material.AIR) { + delegate.setTypeAndRawData(world, x, y, z, Material.LEAVES_2, 0); } } } diff --git a/src/main/java/net/glowstone/generator/objects/trees/BigOakTree.java b/src/main/java/net/glowstone/generator/objects/trees/BigOakTree.java index 1d57dbf1f4..2552449bfb 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/BigOakTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/BigOakTree.java @@ -3,9 +3,10 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Random; +import lombok.Data; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.util.Vector; public class BigOakTree extends GenericTree { @@ -14,9 +15,9 @@ public class BigOakTree extends GenericTree { private int maxLeafDistance = 5; private int trunkHeight; - public BigOakTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); - setHeight(this.random.nextInt(12) + 5); + public BigOakTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); + setHeight(random.nextInt(12) + 5); } public final void setMaxLeafDistance(int distance) { @@ -24,10 +25,10 @@ public final void setMaxLeafDistance(int distance) { } @Override - public boolean canPlace() { - Vector from = new Vector(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); - Vector to = new Vector(loc.getBlockX(), loc.getBlockY() + height - 1, loc.getBlockZ()); - int blocks = countAvailableBlocks(from, to); + public boolean canPlace(int baseX, int baseY, int baseZ, World world) { + Vector from = new Vector(baseX, baseY, baseZ); + Vector to = new Vector(baseX, baseY + height - 1, baseZ); + int blocks = countAvailableBlocks(from, to, world); if (blocks == -1) { return true; } else if (blocks > 5) { @@ -38,8 +39,9 @@ public boolean canPlace() { } @Override - public boolean generate() { - if (!canPlaceOn() || !canPlace()) { + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { + if (!canPlaceOn(world.getBlockAt(blockX, blockY - 1, blockZ).getState()) + || !canPlace(blockX, blockY, blockZ, world)) { return false; } @@ -48,7 +50,7 @@ public boolean generate() { trunkHeight = height - 1; } - Collection leafNodes = generateLeafNodes(); + Collection leafNodes = generateLeafNodes(blockX, blockY, blockZ, world, random); // generate the leaves for (LeafNode node : leafNodes) { @@ -61,8 +63,8 @@ public boolean generate() { double sizeZ = Math.abs(z) + 0.5D; if (sizeX * sizeX + sizeZ * sizeZ <= size * size) { if (overridables.contains(blockTypeAt( - node.getX() + x, node.getY() + y, node.getZ() + z))) { - delegate.setTypeAndRawData(loc.getWorld(), node.getX() + x, + node.getX() + x, node.getY() + y, node.getZ() + z, world))) { + delegate.setTypeAndRawData(world, node.getX() + x, node.getY() + y, node.getZ() + z, Material.LEAVES, leavesType); } @@ -74,14 +76,14 @@ public boolean generate() { // generate the trunk for (int y = 0; y < trunkHeight; y++) { - delegate.setTypeAndRawData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() + y, - loc.getBlockZ(), Material.LOG, logType); + delegate.setTypeAndRawData(world, blockX, blockY + y, + blockZ, Material.LOG, logType); } // generate the branches for (LeafNode node : leafNodes) { - if ((double) node.getBranchY() - loc.getBlockY() >= height * 0.2D) { - Vector base = new Vector(loc.getBlockX(), node.getBranchY(), loc.getBlockZ()); + if ((double) node.getBranchY() - blockY >= height * 0.2D) { + Vector base = new Vector(blockX, node.getBranchY(), blockZ); Vector leafNode = new Vector(node.getX(), node.getY(), node.getZ()); Vector branch = leafNode.subtract(base); int maxDistance = Math.max(Math.abs(branch.getBlockY()), @@ -96,7 +98,7 @@ public boolean generate() { int z = Math.abs(branch.getBlockZ() - base.getBlockZ()); int max = Math.max(x, z); int direction = max > 0 ? max == x ? 4 : 8 : 0; // EAST / SOUTH - delegate.setTypeAndRawData(loc.getWorld(), + delegate.setTypeAndRawData(world, branch.getBlockX(), branch.getBlockY(), branch.getBlockZ(), Material.LOG, logType | direction); } @@ -106,7 +108,7 @@ public boolean generate() { return true; } - private int countAvailableBlocks(Vector from, Vector to) { + private int countAvailableBlocks(Vector from, Vector to, World world) { int n = 0; Vector target = to.subtract(from); int maxDistance = Math.max(Math.abs(target.getBlockY()), @@ -118,23 +120,25 @@ private int countAvailableBlocks(Vector from, Vector to) { target = from.clone() .add(new Vector((double) (0.5F + i * dx), 0.5F + i * dy, 0.5F + i * dz)); if (target.getBlockY() < 0 || target.getBlockY() > 255 - || !overridables.contains(blockTypeAt(target.getBlockX(), target.getBlockY(), target.getBlockZ()))) { + || !overridables.contains(blockTypeAt( + target.getBlockX(), target.getBlockY(), target.getBlockZ(), world))) { return n; } } return -1; } - private Collection generateLeafNodes() { + private Collection generateLeafNodes(int blockX, int blockY, int blockZ, + World world, Random random) { Collection leafNodes = new ArrayList<>(); - int y = loc.getBlockY() + height - maxLeafDistance; - int trunkTopY = loc.getBlockY() + trunkHeight; - leafNodes.add(new LeafNode(loc.getBlockX(), y, loc.getBlockZ(), trunkTopY)); + int y = blockY + height - maxLeafDistance; + int trunkTopY = blockY + trunkHeight; + leafNodes.add(new LeafNode(blockX, y, blockZ, trunkTopY)); int nodeCount = (int) (1.382D + Math.pow(LEAF_DENSITY * (double) height / 13.0D, 2.0D)); nodeCount = nodeCount < 1 ? 1 : nodeCount; - for (int l = --y - loc.getBlockY(); l >= 0; l--, y--) { + for (int l = --y - blockY; l >= 0; l--, y--) { float h = height / 2.0F; float v = h - l; float f = l < (float) height * 0.3D ? -1.0F : @@ -144,16 +148,16 @@ private Collection generateLeafNodes() { for (int i = 0; i < nodeCount; i++) { double d1 = f * (random.nextFloat() + 0.328D); double d2 = random.nextFloat() * Math.PI * 2.0D; - int x = (int) (d1 * Math.sin(d2) + loc.getBlockX() + 0.5D); - int z = (int) (d1 * Math.cos(d2) + loc.getBlockZ() + 0.5D); + int x = (int) (d1 * Math.sin(d2) + blockX + 0.5D); + int z = (int) (d1 * Math.cos(d2) + blockZ + 0.5D); if (countAvailableBlocks(new Vector(x, y, z), - new Vector(x, y + maxLeafDistance, z)) == -1) { - int offX = loc.getBlockX() - x; - int offZ = loc.getBlockZ() - z; + new Vector(x, y + maxLeafDistance, z), world) == -1) { + int offX = blockX - x; + int offZ = blockZ - z; double distance = 0.381D * Math.sqrt(offX * offX + offZ * offZ); int branchBaseY = Math.min(trunkTopY, (int) (y - distance)); - if (countAvailableBlocks(new Vector(x, branchBaseY, z), new Vector(x, y, z)) - == -1) { + if (countAvailableBlocks( + new Vector(x, branchBaseY, z), new Vector(x, y, z), world) == -1) { leafNodes.add(new LeafNode(x, y, z, branchBaseY)); } } @@ -163,34 +167,11 @@ private Collection generateLeafNodes() { return leafNodes; } - private static class LeafNode { - + @Data + private static final class LeafNode { private final int x; private final int y; private final int z; private final int branchY; - - public LeafNode(int x, int y, int z, int branchY) { - this.x = x; - this.y = y; - this.z = z; - this.branchY = branchY; - } - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public int getZ() { - return z; - } - - public int getBranchY() { - return branchY; - } } } diff --git a/src/main/java/net/glowstone/generator/objects/trees/BigTree.java b/src/main/java/net/glowstone/generator/objects/trees/BigTree.java index e13a1fbb65..2f180057fb 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/BigTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/BigTree.java @@ -2,7 +2,6 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; public class BigTree extends BigOakTree { @@ -10,12 +9,11 @@ public class BigTree extends BigOakTree { * Initializes this tree with a random height, preparing it to attempt to generate. * * @param random the PRNG - * @param location the base of the trunk * @param delegate the BlockStateDelegate used to check for space and to fill wood and leaf * blocks */ - public BigTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public BigTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); setMaxLeafDistance(4); } } diff --git a/src/main/java/net/glowstone/generator/objects/trees/BirchTree.java b/src/main/java/net/glowstone/generator/objects/trees/BirchTree.java index 53ad2f200f..e7cc2b8348 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/BirchTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/BirchTree.java @@ -2,7 +2,6 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; public class BirchTree extends GenericTree { @@ -10,12 +9,10 @@ public class BirchTree extends GenericTree { * Initializes this tree with a random height, preparing it to attempt to generate. * * @param random the PRNG - * @param location the base of the trunk * @param delegate the BlockStateDelegate used to check for space and to fill wood and leaf - * blocks */ - public BirchTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public BirchTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); setHeight(random.nextInt(3) + 5); setTypes(2, 2); } diff --git a/src/main/java/net/glowstone/generator/objects/trees/BrownMushroomTree.java b/src/main/java/net/glowstone/generator/objects/trees/BrownMushroomTree.java index 796d426b6d..67d5d809e1 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/BrownMushroomTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/BrownMushroomTree.java @@ -2,9 +2,8 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.block.BlockFace; +import org.bukkit.World; import org.bukkit.block.BlockState; public class BrownMushroomTree extends GenericTree { @@ -15,12 +14,10 @@ public class BrownMushroomTree extends GenericTree { * Initializes this mushroom with a random height, preparing it to attempt to generate. * * @param random the PRNG - * @param location the base of the trunk * @param delegate the BlockStateDelegate used to check for space and to fill wood and leaf - * blocks */ - public BrownMushroomTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public BrownMushroomTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); type = Material.HUGE_MUSHROOM_1; setOverridables( Material.AIR, @@ -31,33 +28,31 @@ public BrownMushroomTree(Random random, Location location, BlockStateDelegate de } @Override - public boolean canPlaceOn() { - BlockState state = delegate - .getBlockState(loc.getBlock().getRelative(BlockFace.DOWN).getLocation()); - return state.getType() == Material.GRASS || state.getType() == Material.DIRT - || state.getType() == Material.MYCEL; + public boolean canPlaceOn(BlockState soil) { + return soil.getType() == Material.GRASS || soil.getType() == Material.DIRT + || soil.getType() == Material.MYCEL; } @Override - public boolean canPlace() { - for (int y = loc.getBlockY(); y <= loc.getBlockY() + 1 + height; y++) { + public boolean canPlace(int baseX, int baseY, int baseZ, World world) { + for (int y = baseY; y <= baseY + 1 + height; y++) { // Space requirement is 7x7 blocks, so brown mushroom's cap // can be directly touching a mushroom next to it. // Since red mushrooms fits in 5x5 blocks it will never // touch another huge mushroom. int radius = 3; - if (y <= loc.getBlockY() + 3) { + if (y <= baseY + 3) { radius = 0; // radius is 0 below 4 blocks tall (only the stem to take in account) } // check for block collision on horizontal slices - for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius; x++) { - for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius; z++) { + for (int x = baseX - radius; x <= baseX + radius; x++) { + for (int z = baseZ - radius; z <= baseZ + radius; z++) { if (y >= 0 && y < 256) { // skip source block check - if (y != loc.getBlockY() || x != loc.getBlockX() || z != loc.getBlockZ()) { + if (y != baseY || x != baseX || z != baseZ) { // we can overlap leaves around - Material type = blockTypeAt(x, y, z); + Material type = blockTypeAt(x, y, z, world); if (!overridables.contains(type)) { return false; } @@ -72,89 +67,89 @@ public boolean canPlace() { } @Override - public boolean generate() { - if (!canHeightFit() || !canPlaceOn() || !canPlace()) { + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { + if (cannotGenerateAt(blockX, blockY, blockZ, world)) { return false; } // generate the stem for (int y = 0; y < height; y++) { - delegate.setTypeAndRawData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() + y, - loc.getBlockZ(), type, 10); // stem texture + delegate.setTypeAndRawData(world, blockX, blockY + y, + blockZ, type, 10); // stem texture } // get the mushroom's cap Y start - int capY = loc.getBlockY() + height; // for brown mushroom it starts on top directly + int capY = blockY + height; // for brown mushroom it starts on top directly if (type == Material.HUGE_MUSHROOM_2) { - capY = loc.getBlockY() + height - 3; // for red mushroom, cap's thickness is 4 blocks + capY = blockY + height - 3; // for red mushroom, cap's thickness is 4 blocks } // generate mushroom's cap - for (int y = capY; y <= loc.getBlockY() + height; y++) { // from bottom to top of mushroom + for (int y = capY; y <= blockY + height; y++) { // from bottom to top of mushroom int radius = 1; // radius for the top of red mushroom - if (y < loc.getBlockY() + height) { + if (y < blockY + height) { radius = 2; // radius for red mushroom cap is 2 } if (type == Material.HUGE_MUSHROOM_1) { radius = 3; // radius always 3 for a brown mushroom } // loop over horizontal slice - for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius; x++) { - for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius; z++) { + for (int x = blockX - radius; x <= blockX + radius; x++) { + for (int z = blockZ - radius; z <= blockZ + radius; z++) { int data = 5; // cap texture on top // cap's borders/corners treatment - if (x == loc.getBlockX() - radius) { + if (x == blockX - radius) { data = 4; // cap texture on top and west - } else if (x == loc.getBlockX() + radius) { + } else if (x == blockX + radius) { data = 6; // cap texture on top and east } - if (z == loc.getBlockZ() - radius) { + if (z == blockZ - radius) { data -= 3; - } else if (z == loc.getBlockZ() + radius) { + } else if (z == blockZ + radius) { data += 3; } // corners shrink treatment // if it's a brown mushroom we need it always // it's a red mushroom, it's only applied below the top - if (type == Material.HUGE_MUSHROOM_1 || y < loc.getBlockY() + height) { + if (type == Material.HUGE_MUSHROOM_1 || y < blockY + height) { // excludes the real corners of the cap structure - if ((x == loc.getBlockX() - radius || x == loc.getBlockX() + radius) - && (z == loc.getBlockZ() - radius || z == loc.getBlockZ() + radius)) { + if ((x == blockX - radius || x == blockX + radius) + && (z == blockZ - radius || z == blockZ + radius)) { continue; } // mushroom's cap corners treatment - if (x == loc.getBlockX() - (radius - 1) && z == loc.getBlockZ() - radius) { + if (x == blockX - (radius - 1) && z == blockZ - radius) { data = 1; // cap texture on top, west and north - } else if (x == loc.getBlockX() - radius && z == loc.getBlockZ() - (radius + } else if (x == blockX - radius && z == blockZ - (radius - 1)) { data = 1; // cap texture on top, west and north - } else if (x == loc.getBlockX() + radius - 1 - && z == loc.getBlockZ() - radius) { + } else if (x == blockX + radius - 1 + && z == blockZ - radius) { data = 3; // cap texture on top, north and east - } else if (x == loc.getBlockX() + radius && z == loc.getBlockZ() - (radius + } else if (x == blockX + radius && z == blockZ - (radius - 1)) { data = 3; // cap texture on top, north and east - } else if (x == loc.getBlockX() - (radius - 1) - && z == loc.getBlockZ() + radius) { + } else if (x == blockX - (radius - 1) + && z == blockZ + radius) { data = 7; // cap texture on top, south and west - } else if (x == loc.getBlockX() - radius - && z == loc.getBlockZ() + radius - 1) { + } else if (x == blockX - radius + && z == blockZ + radius - 1) { data = 7; // cap texture on top, south and west - } else if (x == loc.getBlockX() + radius - 1 - && z == loc.getBlockZ() + radius) { + } else if (x == blockX + radius - 1 + && z == blockZ + radius) { data = 9; // cap texture on top, east and south - } else if (x == loc.getBlockX() + radius - && z == loc.getBlockZ() + radius - 1) { + } else if (x == blockX + radius + && z == blockZ + radius - 1) { data = 9; // cap texture on top, east and south } } // a data of 5 below the top layer means air - if (data != 5 || y >= loc.getBlockY() + height) { - delegate.setTypeAndRawData(loc.getWorld(), x, y, z, type, data); + if (data != 5 || y >= blockY + height) { + delegate.setTypeAndRawData(world, x, y, z, type, data); } } } diff --git a/src/main/java/net/glowstone/generator/objects/trees/CocoaTree.java b/src/main/java/net/glowstone/generator/objects/trees/CocoaTree.java index 0886c636e0..6c28cf7632 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/CocoaTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/CocoaTree.java @@ -2,8 +2,8 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.material.CocoaPlant; @@ -21,57 +21,55 @@ public class CocoaTree extends JungleTree { * Initializes this tree, preparing it to attempt to generate. * * @param random the PRNG - * @param location the base of the trunk - * @param delegate the BlockStateDelegate used to check for space and to fill wood and leaf - * blocks + * @param delegate the BlockStateDelegate used to check for space and to fill wood and */ - public CocoaTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public CocoaTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); } @Override - public boolean generate() { - if (!super.generate()) { + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { + if (!super.generate(world, random, blockX, blockY, blockZ)) { return false; } // places some vines on the trunk - addVinesOnTrunk(); + addVinesOnTrunk(blockX, blockY, blockZ, world, random); // search for air around leaves to grow hanging vines - addVinesOnLeaves(); + addVinesOnLeaves(blockX, blockY, blockZ, world, random); // and maybe place some cocoa - addCocoa(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + addCocoa(blockX, blockY, blockZ, world, random); return true; } - protected void addVinesOnLeaves() { - for (int y = loc.getBlockY() - 3 + height; y <= loc.getBlockY() + height; y++) { - int ny = y - (loc.getBlockY() + height); + protected void addVinesOnLeaves(int baseX, int baseY, int baseZ, World world, Random random) { + for (int y = baseY - 3 + height; y <= baseY + height; y++) { + int ny = y - (baseY + height); int radius = 2 - ny / 2; - for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius; x++) { - for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius; z++) { - if (blockTypeAt(x, y, z) - == Material.LEAVES) { + for (int x = baseX - radius; x <= baseX + radius; x++) { + for (int z = baseZ - radius; z <= baseZ + radius; z++) { + if (blockTypeAt(x, y, z, world) + == Material.LEAVES) { if (random.nextInt(4) == 0 - && blockTypeAt(x - 1, y, z) - == Material.AIR) { - addHangingVine(x - 1, y, z, BlockFace.EAST); + && blockTypeAt(x - 1, y, z, world) + == Material.AIR) { + addHangingVine(x - 1, y, z, BlockFace.EAST, world); } if (random.nextInt(4) == 0 - && blockTypeAt(x + 1, y, z) - == Material.AIR) { - addHangingVine(x + 1, y, z, BlockFace.WEST); + && blockTypeAt(x + 1, y, z, world) + == Material.AIR) { + addHangingVine(x + 1, y, z, BlockFace.WEST, world); } if (random.nextInt(4) == 0 - && blockTypeAt(x, y, z - 1) - == Material.AIR) { - addHangingVine(x, y, z - 1, BlockFace.SOUTH); + && blockTypeAt(x, y, z - 1, world) + == Material.AIR) { + addHangingVine(x, y, z - 1, BlockFace.SOUTH, world); } if (random.nextInt(4) == 0 - && blockTypeAt(x, y, z + 1) - == Material.AIR) { - addHangingVine(x, y, z + 1, BlockFace.NORTH); + && blockTypeAt(x, y, z + 1, world) + == Material.AIR) { + addHangingVine(x, y, z + 1, BlockFace.NORTH, world); } } } @@ -79,54 +77,58 @@ && blockTypeAt(x, y, z + 1) } } - private void addVinesOnTrunk() { + private void addVinesOnTrunk(int trunkX, int trunkY, int trunkZ, World world, Random random) { for (int y = 1; y < height; y++) { if (random.nextInt(3) != 0 - && blockTypeAt(loc.getBlockX() - 1, loc.getBlockY() + y, loc.getBlockZ()) == Material.AIR) { - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX() - 1, loc.getBlockY() + y, - loc.getBlockZ(), Material.VINE, new Vine(BlockFace.EAST)); + && blockTypeAt(trunkX - 1, trunkY + y, trunkZ, world) + == Material.AIR) { + delegate.setTypeAndData(world, trunkX - 1, trunkY + y, + trunkZ, Material.VINE, new Vine(BlockFace.EAST)); } if (random.nextInt(3) != 0 - && blockTypeAt(loc.getBlockX() + 1, loc.getBlockY() + y, loc.getBlockZ()) == Material.AIR) { - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX() + 1, loc.getBlockY() + y, - loc.getBlockZ(), Material.VINE, new Vine(BlockFace.WEST)); + && blockTypeAt(trunkX + 1, trunkY + y, trunkZ, world) + == Material.AIR) { + delegate.setTypeAndData(world, trunkX + 1, trunkY + y, + trunkZ, Material.VINE, new Vine(BlockFace.WEST)); } if (random.nextInt(3) != 0 - && blockTypeAt(loc.getBlockX(), loc.getBlockY() + y, loc.getBlockZ() - 1) == Material.AIR) { - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() + y, - loc.getBlockZ() - 1, Material.VINE, new Vine(BlockFace.SOUTH)); + && blockTypeAt(trunkX, trunkY + y, trunkZ - 1, world) + == Material.AIR) { + delegate.setTypeAndData(world, trunkX, trunkY + y, + trunkZ - 1, Material.VINE, new Vine(BlockFace.SOUTH)); } if (random.nextInt(3) != 0 - && blockTypeAt(loc.getBlockX(), loc.getBlockY() + y, loc.getBlockZ() + 1) == Material.AIR) { - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() + y, - loc.getBlockZ() + 1, Material.VINE, new Vine(BlockFace.NORTH)); + && blockTypeAt(trunkX, trunkY + y, trunkZ + 1, world) + == Material.AIR) { + delegate.setTypeAndData(world, trunkX, trunkY + y, + trunkZ + 1, Material.VINE, new Vine(BlockFace.NORTH)); } } } - private void addHangingVine(int x, int y, int z, BlockFace face) { + private void addHangingVine(int x, int y, int z, BlockFace face, World world) { for (int i = 0; i < 5; i++) { - if (blockTypeAt(x, y - i, z) != Material.AIR) { + if (blockTypeAt(x, y - i, z, world) != Material.AIR) { break; } - delegate.setTypeAndData(loc.getWorld(), x, y - i, z, Material.VINE, new Vine(face)); + delegate.setTypeAndData(world, x, y - i, z, Material.VINE, new Vine(face)); } } - private void addCocoa(int sourceX, int sourceY, int sourceZ) { + private void addCocoa(int sourceX, int sourceY, int sourceZ, World world, Random random) { if (height > 5 && random.nextInt(5) == 0) { for (int y = 0; y < 2; y++) { for (BlockFace cocoaFace : COCOA_FACES) { // rotate the 4 trunk faces if (random.nextInt(COCOA_FACES.length - y) - == 0) { // higher it is, more chances there is + == 0) { // higher it is, more chances there is CocoaPlantSize size = COCOA_SIZE[random.nextInt(COCOA_SIZE.length)]; Block block = delegate - .getBlockState(loc.getWorld(), sourceX, sourceY + height - 5 + y, - sourceZ) - .getBlock().getRelative(cocoaFace); - delegate.setTypeAndData(loc.getWorld(), block.getX(), block.getY(), - block.getZ(), - Material.COCOA, new CocoaPlant(size, cocoaFace.getOppositeFace())); + .getBlockState(world, sourceX, sourceY + height - 5 + y, + sourceZ) + .getBlock().getRelative(cocoaFace); + delegate.setTypeAndData(world, block.getX(), block.getY(), + block.getZ(), + Material.COCOA, new CocoaPlant(size, cocoaFace.getOppositeFace())); } } } diff --git a/src/main/java/net/glowstone/generator/objects/trees/DarkOakTree.java b/src/main/java/net/glowstone/generator/objects/trees/DarkOakTree.java index f2e73500d8..6a11f5be2d 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/DarkOakTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/DarkOakTree.java @@ -2,9 +2,8 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.block.BlockFace; +import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.material.Dirt; import org.bukkit.material.types.DirtType; @@ -13,14 +12,11 @@ public class DarkOakTree extends GenericTree { /** * Initializes this tree with a random height, preparing it to attempt to generate. - * - * @param random the PRNG - * @param location the base of the trunk + * @param random the PRNG * @param delegate the BlockStateDelegate used to check for space and to fill wood and leaf - * blocks */ - public DarkOakTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public DarkOakTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); setOverridables( Material.AIR, Material.LEAVES, @@ -36,15 +32,13 @@ public DarkOakTree(Random random, Location location, BlockStateDelegate delegate } @Override - public boolean canPlaceOn() { - BlockState state = delegate - .getBlockState(loc.getBlock().getRelative(BlockFace.DOWN).getLocation()); - return state.getType() == Material.GRASS || state.getType() == Material.DIRT; + public boolean canPlaceOn(BlockState soil) { + return soil.getType() == Material.GRASS || soil.getType() == Material.DIRT; } @Override - public boolean generate() { - if (!canHeightFit() || !canPlaceOn() || !canPlace()) { + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { + if (cannotGenerateAt(blockX, blockY, blockZ, world)) { return false; } @@ -60,8 +54,8 @@ public boolean generate() { } int twistHeight = height - random.nextInt(4); int twistCount = random.nextInt(3); - int centerX = loc.getBlockX(); - int centerZ = loc.getBlockZ(); + int centerX = blockX; + int centerZ = blockZ; int trunkTopY = 0; // generates the trunk @@ -74,19 +68,19 @@ public boolean generate() { twistCount--; } - Material material = blockTypeAt(centerX, loc.getBlockY() + y, centerZ); + Material material = blockTypeAt(centerX, blockY + y, centerZ, world); if (material == Material.AIR || material == Material.LEAVES) { - trunkTopY = loc.getBlockY() + y; + trunkTopY = blockY + y; // SELF, SOUTH, EAST, SOUTH EAST - delegate.setTypeAndRawData(loc.getWorld(), centerX, loc.getBlockY() + y, centerZ, + delegate.setTypeAndRawData(world, centerX, blockY + y, centerZ, Material.LOG_2, 1); delegate - .setTypeAndRawData(loc.getWorld(), centerX, loc.getBlockY() + y, centerZ + 1, + .setTypeAndRawData(world, centerX, blockY + y, centerZ + 1, Material.LOG_2, 1); delegate - .setTypeAndRawData(loc.getWorld(), centerX + 1, loc.getBlockY() + y, centerZ, + .setTypeAndRawData(world, centerX + 1, blockY + y, centerZ, Material.LOG_2, 1); - delegate.setTypeAndRawData(loc.getWorld(), centerX + 1, loc.getBlockY() + y, + delegate.setTypeAndRawData(world, centerX + 1, blockY + y, centerZ + 1, Material.LOG_2, 1); } } @@ -95,15 +89,15 @@ public boolean generate() { for (int x = -2; x <= 0; x++) { for (int z = -2; z <= 0; z++) { if ((x != -1 || z != -2) && (x > -2 || z > -1)) { - setLeaves(centerX + x, trunkTopY + 1, centerZ + z); - setLeaves(1 + centerX - x, trunkTopY + 1, centerZ + z); - setLeaves(centerX + x, trunkTopY + 1, 1 + centerZ - z); - setLeaves(1 + centerX - x, trunkTopY + 1, 1 + centerZ - z); + setLeaves(centerX + x, trunkTopY + 1, centerZ + z, world); + setLeaves(1 + centerX - x, trunkTopY + 1, centerZ + z, world); + setLeaves(centerX + x, trunkTopY + 1, 1 + centerZ - z, world); + setLeaves(1 + centerX - x, trunkTopY + 1, 1 + centerZ - z, world); } - setLeaves(centerX + x, trunkTopY - 1, centerZ + z); - setLeaves(1 + centerX - x, trunkTopY - 1, centerZ + z); - setLeaves(centerX + x, trunkTopY - 1, 1 + centerZ - z); - setLeaves(1 + centerX - x, trunkTopY - 1, 1 + centerZ - z); + setLeaves(centerX + x, trunkTopY - 1, centerZ + z, world); + setLeaves(1 + centerX - x, trunkTopY - 1, centerZ + z, world); + setLeaves(centerX + x, trunkTopY - 1, 1 + centerZ - z, world); + setLeaves(1 + centerX - x, trunkTopY - 1, 1 + centerZ - z, world); } } @@ -111,7 +105,7 @@ public boolean generate() { for (int x = -3; x <= 4; x++) { for (int z = -3; z <= 4; z++) { if (Math.abs(x) < 3 || Math.abs(z) < 3) { - setLeaves(centerX + x, trunkTopY, centerZ + z); + setLeaves(centerX + x, trunkTopY, centerZ + z, world); } } } @@ -122,23 +116,23 @@ public boolean generate() { if ((x == -1 || z == -1 || x == 2 || z == 2) && random.nextInt(3) == 0) { for (int y = 0; y < random.nextInt(3) + 2; y++) { Material material = blockTypeAt( - loc.getBlockX() + x, trunkTopY - y - 1, loc.getBlockZ() + z); + blockX + x, trunkTopY - y - 1, blockZ + z, world); if (material == Material.AIR || material == Material.LEAVES) { - delegate.setTypeAndRawData(loc.getWorld(), loc.getBlockX() + x, - trunkTopY - y - 1, loc.getBlockZ() + z, Material.LOG_2, 1); + delegate.setTypeAndRawData(world, blockX + x, + trunkTopY - y - 1, blockZ + z, Material.LOG_2, 1); } } // leaves below the canopy for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - setLeaves(centerX + x + i, trunkTopY, centerZ + z + j); + setLeaves(centerX + x + i, trunkTopY, centerZ + z + j, world); } } for (int i = -2; i <= 2; i++) { for (int j = -2; j <= 2; j++) { if (Math.abs(i) < 2 || Math.abs(j) < 2) { - setLeaves(centerX + x + i, trunkTopY - 1, centerZ + z + j); + setLeaves(centerX + x + i, trunkTopY - 1, centerZ + z + j, world); } } } @@ -148,30 +142,30 @@ public boolean generate() { // 50% chance to have a 4 leaves cap on the center of the canopy if (random.nextInt(2) == 0) { - setLeaves(centerX, trunkTopY + 2, centerZ); - setLeaves(centerX + 1, trunkTopY + 2, centerZ); - setLeaves(centerX + 1, trunkTopY + 2, centerZ + 1); - setLeaves(centerX, trunkTopY + 2, centerZ + 1); + setLeaves(centerX, trunkTopY + 2, centerZ, world); + setLeaves(centerX + 1, trunkTopY + 2, centerZ, world); + setLeaves(centerX + 1, trunkTopY + 2, centerZ + 1, world); + setLeaves(centerX, trunkTopY + 2, centerZ + 1, world); } // block below trunk is always dirt (SELF, SOUTH, EAST, SOUTH EAST) Dirt dirt = new Dirt(DirtType.NORMAL); delegate - .setTypeAndData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() - 1, loc.getBlockZ(), + .setTypeAndData(world, blockX, blockY - 1, blockZ, Material.DIRT, dirt); - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() - 1, - loc.getBlockZ() + 1, Material.DIRT, dirt); - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX() + 1, loc.getBlockY() - 1, - loc.getBlockZ(), Material.DIRT, dirt); - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX() + 1, loc.getBlockY() - 1, - loc.getBlockZ() + 1, Material.DIRT, dirt); + delegate.setTypeAndData(world, blockX, blockY - 1, + blockZ + 1, Material.DIRT, dirt); + delegate.setTypeAndData(world, blockX + 1, blockY - 1, + blockZ, Material.DIRT, dirt); + delegate.setTypeAndData(world, blockX + 1, blockY - 1, + blockZ + 1, Material.DIRT, dirt); return true; } - private void setLeaves(int x, int y, int z) { - if (blockTypeAt(x, y, z) == Material.AIR) { - delegate.setTypeAndRawData(loc.getWorld(), x, y, z, Material.LEAVES_2, 1); + private void setLeaves(int x, int y, int z, World world) { + if (blockTypeAt(x, y, z, world) == Material.AIR) { + delegate.setTypeAndRawData(world, x, y, z, Material.LEAVES_2, 1); } } } diff --git a/src/main/java/net/glowstone/generator/objects/trees/GenericTree.java b/src/main/java/net/glowstone/generator/objects/trees/GenericTree.java index aa0ab92d71..be8ed192f4 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/GenericTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/GenericTree.java @@ -1,21 +1,21 @@ package net.glowstone.generator.objects.trees; +import io.netty.util.internal.ThreadLocalRandom; import java.util.Arrays; import java.util.Collection; import java.util.Random; +import net.glowstone.generator.objects.TerrainObject; import net.glowstone.util.BlockStateDelegate; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.block.BlockFace; +import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.material.Dirt; import org.bukkit.material.types.DirtType; /** Oak tree, and superclass for other types. */ -public class GenericTree { +public class GenericTree implements TerrainObject { - protected final Random random; - protected final Location loc; protected final BlockStateDelegate delegate; protected int height; protected int logType; @@ -26,13 +26,9 @@ public class GenericTree { * Initializes this tree with a random height, preparing it to attempt to generate. * * @param random the PRNG - * @param location the base of the trunk - * @param delegate the BlockStateDelegate used to check for space and to fill wood and leaf - * blocks + * @param delegate the BlockStateDelegate used to check for space and to fill in wood and leaves */ - public GenericTree(Random random, Location location, BlockStateDelegate delegate) { - this.random = random; - loc = location; + public GenericTree(Random random, BlockStateDelegate delegate) { this.delegate = delegate; setOverridables( Material.AIR, @@ -69,42 +65,48 @@ protected final void setTypes(int logType, int leavesType) { /** * Checks whether this tree fits under the upper world limit. + * @param baseHeight the height of the base of the trunk + * * @return true if this tree can grow without exceeding block height 255; false otherwise. */ - public boolean canHeightFit() { - return loc.getBlockY() >= 1 && loc.getBlockY() + height + 1 <= 255; + public boolean canHeightFit(int baseHeight) { + return baseHeight >= 1 && baseHeight + height + 1 <= 255; } /** - * Checks whether this tree is on fertile ground. + * Checks whether this tree can grow on top of the given block. + * @param soil the block we're growing on * @return true if this tree can grow on the type of block below it; false otherwise */ - public boolean canPlaceOn() { - BlockState state = delegate - .getBlockState(loc.getBlock().getRelative(BlockFace.DOWN).getLocation()); - return state.getType() == Material.GRASS || state.getType() == Material.DIRT - || state.getType() == Material.SOIL; + public boolean canPlaceOn(BlockState soil) { + return soil.getType() == Material.GRASS || soil.getType() == Material.DIRT + || soil.getType() == Material.SOIL; } /** * Checks whether this tree has enough space to grow. + * + * @param baseX the X coordinate of the base of the trunk + * @param baseY the Y coordinate of the base of the trunk + * @param baseZ the Z coordinate of the base of the trunk + * @param world the world to grow in * @return true if this tree has space to grow; false otherwise */ - public boolean canPlace() { - for (int y = loc.getBlockY(); y <= loc.getBlockY() + 1 + height; y++) { + public boolean canPlace(int baseX, int baseY, int baseZ, World world) { + for (int y = baseY; y <= baseY + 1 + height; y++) { // Space requirement int radius = 1; // default radius if above first block - if (y == loc.getBlockY()) { + if (y == baseY) { radius = 0; // radius at source block y is 0 (only trunk) - } else if (y >= loc.getBlockY() + 1 + height - 2) { + } else if (y >= baseY + 1 + height - 2) { radius = 2; // max radius starting at leaves bottom } // check for block collision on horizontal slices - for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius; x++) { - for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius; z++) { + for (int x = baseX - radius; x <= baseX + radius; x++) { + for (int z = baseZ - radius; z <= baseZ + radius; z++) { if (y >= 0 && y < 256) { // we can overlap some blocks around - Material type = delegate.getBlockState(loc.getWorld(), x, y, z).getType(); + Material type = blockTypeAt(x, y, z, world); if (!overridables.contains(type)) { return false; } @@ -121,23 +123,32 @@ public boolean canPlace() { * Attempts to grow this tree at its current location. If successful, the associated {@link * BlockStateDelegate} is instructed to set blocks to wood and leaves. * + * @param loc the base of the trunk * @return true if successfully grown; false otherwise + * @deprecated use {@link #generate(World, Random, int, int, int)} */ - public boolean generate() { - if (!canHeightFit() || !canPlaceOn() || !canPlace()) { + @Deprecated + public boolean generate(Location loc) { + return generate(loc.getWorld(), ThreadLocalRandom.current(), + loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + } + + @Override + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { + if (cannotGenerateAt(blockX, blockY, blockZ, world)) { return false; } // generate the leaves - for (int y = loc.getBlockY() + height - 3; y <= loc.getBlockY() + height; y++) { - int n = y - (loc.getBlockY() + height); + for (int y = blockY + height - 3; y <= blockY + height; y++) { + int n = y - (blockY + height); int radius = 1 - n / 2; - for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius; x++) { - for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius; z++) { - if (Math.abs(x - loc.getBlockX()) != radius - || Math.abs(z - loc.getBlockZ()) != radius + for (int x = blockX - radius; x <= blockX + radius; x++) { + for (int z = blockZ - radius; z <= blockZ + radius; z++) { + if (Math.abs(x - blockX) != radius + || Math.abs(z - blockZ) != radius || random.nextBoolean() && n != 0) { - replaceIfAirOrLeaves(x, y, z, Material.LEAVES, leavesType); + replaceIfAirOrLeaves(x, y, z, Material.LEAVES, leavesType, world); } } } @@ -145,24 +156,36 @@ public boolean generate() { // generate the trunk for (int y = 0; y < height; y++) { - Material material = delegate - .getBlockState(loc.getWorld(), loc.getBlockX(), loc.getBlockY() + y, - loc.getBlockZ()).getType(); - if (material == Material.AIR || material == Material.LEAVES) { - delegate.setTypeAndRawData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() + y, - loc.getBlockZ(), Material.LOG, logType); - } + replaceIfAirOrLeaves(blockX, + blockY + y, blockZ, Material.LOG, logType, world); } // block below trunk is always dirt Dirt dirt = new Dirt(DirtType.NORMAL); delegate - .setTypeAndData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() - 1, loc.getBlockZ(), + .setTypeAndData(world, blockX, blockY - 1, blockZ, Material.DIRT, dirt); return true; } + /** + * Returns whether any of {@link #canHeightFit(int)}, {@link #canPlace(int, int, int, World)} or + * {@link #canPlaceOn(BlockState)} prevent this tree from generating. + * + * @param baseX the X coordinate of the base of the trunk + * @param baseY the Y coordinate of the base of the trunk + * @param baseZ the Z coordinate of the base of the trunk + * @param world the world to grow in + * @return true if any of the checks prevent us from generating, false otherwise + */ + protected boolean cannotGenerateAt(int baseX, int baseY, int baseZ, + World world) { + return !canHeightFit(baseY) + || !canPlaceOn(world.getBlockAt(baseX, baseY - 1, baseZ).getState()) + || !canPlace(baseX, baseY, baseZ, world); + } + /** * Replaces the block at a location with the given new one, if it is air or leaves. * @@ -171,11 +194,13 @@ public boolean generate() { * @param z the z coordinate * @param newMaterial the new block type * @param data the new block data + * @param world the world we are generating in */ - protected void replaceIfAirOrLeaves(int x, int y, int z, Material newMaterial, int data) { - Material oldMaterial = blockTypeAt(x, y, z); + protected void replaceIfAirOrLeaves(int x, int y, int z, Material newMaterial, int data, + World world) { + Material oldMaterial = blockTypeAt(x, y, z, world); if (oldMaterial == Material.AIR || oldMaterial == Material.LEAVES) { - delegate.setTypeAndRawData(loc.getWorld(), x, y, z, newMaterial, data); + delegate.setTypeAndRawData(world, x, y, z, newMaterial, data); } } @@ -184,11 +209,10 @@ protected void replaceIfAirOrLeaves(int x, int y, int z, Material newMaterial, i * @param x the x coordinate * @param y the y coordinate * @param z the z coordinate + * @param world the world we are generating in * @return the block type */ - protected Material blockTypeAt(int x, int y, int z) { - return delegate.getBlockState( - loc.getWorld(), x, y, - z).getType(); + protected Material blockTypeAt(int x, int y, int z, World world) { + return delegate.getBlockState(world, x, y, z).getType(); } } diff --git a/src/main/java/net/glowstone/generator/objects/trees/JungleBush.java b/src/main/java/net/glowstone/generator/objects/trees/JungleBush.java index 7bd3f757cd..ea3c572613 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/JungleBush.java +++ b/src/main/java/net/glowstone/generator/objects/trees/JungleBush.java @@ -4,6 +4,7 @@ import net.glowstone.util.BlockStateDelegate; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; @@ -11,52 +12,48 @@ public class JungleBush extends GenericTree { /** * Initializes this bush, preparing it to attempt to generate. - * - * @param random the PRNG - * @param location the base of the trunk + * @param random the PRNG * @param delegate the BlockStateDelegate used to check for space and to fill wood and leaf - * blocks */ - public JungleBush(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public JungleBush(Random random, BlockStateDelegate delegate) { + super(random, delegate); setTypes(3, 0); } @Override - public boolean canPlaceOn() { - BlockState state = delegate - .getBlockState(loc.getBlock().getRelative(BlockFace.DOWN).getLocation()); - return state.getType() == Material.GRASS || state.getType() == Material.DIRT; + public boolean canPlaceOn(BlockState soil) { + return soil.getType() == Material.GRASS || soil.getType() == Material.DIRT; } @Override - public boolean generate() { - Location l = loc.clone(); + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { + Location l = new Location(world, blockX, blockY, blockZ); while ((l.getBlock().getType() == Material.AIR || l.getBlock().getType() == Material.LEAVES) - && l.getBlockY() > 0) { + && blockY > 0) { l.subtract(0, 1, 0); } // check only below block - if (!canPlaceOn()) { + if (!canPlaceOn(l.getBlock().getRelative(BlockFace.DOWN).getState())) { return false; } // generates the trunk - delegate.setTypeAndRawData(l.getWorld(), l.getBlockX(), l.getBlockY() + 1, l.getBlockZ(), + final int adjustedY = l.getBlockY(); + delegate.setTypeAndRawData(world, blockX, adjustedY + 1, blockZ, Material.LOG, logType); // generates the leaves - for (int y = l.getBlockY() + 1; y <= l.getBlockY() + 3; y++) { - int radius = 3 - (y - l.getBlockY()); + for (int y = adjustedY + 1; y <= adjustedY + 3; y++) { + int radius = 3 - (y - adjustedY); - for (int x = l.getBlockX() - radius; x <= l.getBlockX() + radius; x++) { - for (int z = l.getBlockZ() - radius; z <= l.getBlockZ() + radius; z++) { + for (int x = blockX - radius; x <= blockX + radius; x++) { + for (int z = blockZ - radius; z <= blockZ + radius; z++) { if ((Math.abs(x - l.getBlockX()) != radius || Math.abs(z - l.getBlockZ()) != radius || random.nextBoolean()) - && !delegate.getBlockState(l.getWorld(), x, y, z).getType().isSolid()) { + && !delegate.getBlockState(world, x, y, z).getType().isSolid()) { delegate - .setTypeAndRawData(l.getWorld(), x, y, z, Material.LEAVES, leavesType); + .setTypeAndRawData(world, x, y, z, Material.LEAVES, leavesType); } } } diff --git a/src/main/java/net/glowstone/generator/objects/trees/JungleTree.java b/src/main/java/net/glowstone/generator/objects/trees/JungleTree.java index dec0f79517..67492fab38 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/JungleTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/JungleTree.java @@ -2,20 +2,16 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; public class JungleTree extends GenericTree { /** * Initializes this tree with a random height, preparing it to attempt to generate. - * - * @param random the PRNG - * @param location the base of the trunk + * @param random the PRNG * @param delegate the BlockStateDelegate used to check for space and to fill wood and leaf - * blocks */ - public JungleTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public JungleTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); setHeight(random.nextInt(7) + 4); setTypes(3, 3); } diff --git a/src/main/java/net/glowstone/generator/objects/trees/MegaJungleTree.java b/src/main/java/net/glowstone/generator/objects/trees/MegaJungleTree.java index 97eb9f6dbd..811e27d267 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/MegaJungleTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/MegaJungleTree.java @@ -2,8 +2,8 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.material.Dirt; @@ -14,41 +14,36 @@ public class MegaJungleTree extends GenericTree { /** * Initializes this tree with a random height, preparing it to attempt to generate. - * - * @param random the PRNG - * @param location the base of the trunk + * @param random the PRNG * @param delegate the BlockStateDelegate used to check for space and to fill wood and - * leaf blocks */ - public MegaJungleTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public MegaJungleTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); setHeight(random.nextInt(20) + random.nextInt(3) + 10); setTypes(3, 3); } @Override - public boolean canPlaceOn() { - BlockState state = delegate - .getBlockState(loc.getBlock().getRelative(BlockFace.DOWN).getLocation()); - return state.getType() == Material.GRASS || state.getType() == Material.DIRT; + public boolean canPlaceOn(BlockState soil) { + return soil.getType() == Material.GRASS || soil.getType() == Material.DIRT; } @Override - public boolean canPlace() { - for (int y = loc.getBlockY(); y <= loc.getBlockY() + 1 + height; y++) { + public boolean canPlace(int baseX, int baseY, int baseZ, World world) { + for (int y = baseY; y <= baseY + 1 + height; y++) { // Space requirement int radius = 2; // default radius if above first block - if (y == loc.getBlockY()) { + if (y == baseY) { radius = 1; // radius at source block y is 1 (only trunk) - } else if (y >= loc.getBlockY() + 1 + height - 2) { + } else if (y >= baseY + 1 + height - 2) { radius = 2; // max radius starting at leaves bottom } // check for block collision on horizontal slices - for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius; x++) { - for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius; z++) { + for (int x = baseX - radius; x <= baseX + radius; x++) { + for (int z = baseZ - radius; z <= baseZ + radius; z++) { if (y >= 0 && y < 256) { // we can overlap some blocks around - Material type = blockTypeAt(x, y, z); + Material type = blockTypeAt(x, y, z, world); if (!overridables.contains(type)) { return false; } @@ -62,54 +57,57 @@ public boolean canPlace() { } @Override - public boolean generate() { - if (!canHeightFit() || !canPlaceOn() || !canPlace()) { + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { + if (cannotGenerateAt(blockX, blockY, blockZ, world)) { return false; } // generates the canopy leaves for (int y = -2; y <= 0; y++) { generateLeaves( - loc.getBlockX() + 0, loc.getBlockY() + height + y, loc.getBlockZ(), 3 - y, - false); + blockX + 0, blockY + height + y, blockZ, 3 - y, + false, world); } // generates the branches int branchHeight = height - 2 - random.nextInt(4); while (branchHeight > height / 2) { // branching start at least at middle height - int x = 0, z = 0; + int x = 0; + int z = 0; // generates a branch float d = (float) (random.nextFloat() * Math.PI * 2.0F); // random direction for (int i = 0; i < 5; i++) { // branches are always longer when facing south or east (positive X or positive Z) x = (int) (Math.cos(d) * i + 1.5F); z = (int) (Math.sin(d) * i + 1.5F); - delegate.setTypeAndRawData(loc.getWorld(), loc.getBlockX() + x, - loc.getBlockY() + branchHeight - 3 + i / 2, - loc.getBlockZ() + z, Material.LOG, + delegate.setTypeAndRawData(world, blockX + x, + blockY + branchHeight - 3 + i / 2, + blockZ + z, Material.LOG, logType); } // generates leaves for this branch for (int y = branchHeight - (random.nextInt(2) + 1); y <= branchHeight; y++) { - generateLeaves(loc.getBlockX() + x, loc.getBlockY() + y, loc.getBlockZ() + z, - 1 - (y - branchHeight), true); + generateLeaves( + blockX + x, blockY + y, blockZ + z, + 1 - (y - branchHeight), true, world); } branchHeight -= random.nextInt(4) + 2; } // generates the trunk - generateTrunk(); + generateTrunk(world, blockX, blockY, blockZ); // add some vines on the trunk - addVinesOnTrunk(); + addVinesOnTrunk(world, blockX, blockY, blockZ, random); // blocks below trunk are always dirt - generateDirtBelowTrunk(); + generateDirtBelowTrunk(world, blockX, blockY, blockZ); return true; } - protected void generateLeaves(int sourceX, int sourceY, int sourceZ, int radius, boolean odd) { + protected void generateLeaves(int sourceX, int sourceY, int sourceZ, int radius, boolean odd, + World world) { int n = 1; if (odd) { n = 0; @@ -127,82 +125,97 @@ protected void generateLeaves(int sourceX, int sourceY, int sourceZ, int radius, if (sqX + sqZ <= sqR || sqXb + sqZb <= sqR || sqX + sqZb <= sqR || sqXb + sqZ <= sqR) { - replaceIfAirOrLeaves(x, sourceY, z, Material.LEAVES, leavesType); + replaceIfAirOrLeaves(x, sourceY, z, Material.LEAVES, leavesType, world); } } } } - protected void generateTrunk() { + protected void generateTrunk(World world, int blockX, int blockY, int blockZ) { // SELF, SOUTH, EAST, SOUTH EAST for (int y = 0; y < height + -1; y++) { - Material type = loc.getWorld() - .getBlockAt(loc.getBlockX() + 0, loc.getBlockY() + y, loc.getBlockZ() + 0) + Material type = world + .getBlockAt(blockX + 0, blockY + y, blockZ + 0) .getType(); if (type == Material.AIR || type == Material.LEAVES) { - delegate.setTypeAndRawData(loc.getWorld(), loc.getBlockX() + 0, loc.getBlockY() + y, - loc.getBlockZ(), Material.LOG, logType); + delegate.setTypeAndRawData(world, blockX + 0, blockY + y, + blockZ, Material.LOG, logType); } - type = loc.getWorld() - .getBlockAt(loc.getBlockX() + 0, loc.getBlockY() + y, loc.getBlockZ() + 1) + type = world + .getBlockAt(blockX + 0, blockY + y, blockZ + 1) .getType(); if (type == Material.AIR || type == Material.LEAVES) { - delegate.setTypeAndRawData(loc.getWorld(), loc.getBlockX() + 0, loc.getBlockY() + y, - loc.getBlockZ() + 1, Material.LOG, logType); + delegate.setTypeAndRawData(world, blockX + 0, blockY + y, + blockZ + 1, Material.LOG, logType); } - type = loc.getWorld() - .getBlockAt(loc.getBlockX() + 1, loc.getBlockY() + y, loc.getBlockZ() + 0) + type = world + .getBlockAt(blockX + 1, blockY + y, blockZ + 0) .getType(); if (type == Material.AIR || type == Material.LEAVES) { - delegate.setTypeAndRawData(loc.getWorld(), loc.getBlockX() + 1, loc.getBlockY() + y, - loc.getBlockZ(), Material.LOG, logType); + delegate.setTypeAndRawData(world, blockX + 1, blockY + y, + blockZ, Material.LOG, logType); } - type = loc.getWorld() - .getBlockAt(loc.getBlockX() + 1, loc.getBlockY() + y, loc.getBlockZ() + 1) + type = world + .getBlockAt(blockX + 1, blockY + y, blockZ + 1) .getType(); if (type == Material.AIR || type == Material.LEAVES) { - delegate.setTypeAndRawData(loc.getWorld(), loc.getBlockX() + 1, loc.getBlockY() + y, - loc.getBlockZ() + 1, Material.LOG, logType); + delegate.setTypeAndRawData(world, blockX + 1, blockY + y, + blockZ + 1, Material.LOG, logType); } } } - protected void generateDirtBelowTrunk() { + protected void generateDirtBelowTrunk(World world, int blockX, int blockY, int blockZ) { // SELF, SOUTH, EAST, SOUTH EAST Dirt dirt = new Dirt(DirtType.NORMAL); delegate - .setTypeAndData(loc.getWorld(), loc.getBlockX() + 0, - loc.getBlockY() + -1, loc.getBlockZ(), + .setTypeAndData(world, blockX + 0, + blockY + -1, blockZ, Material.DIRT, dirt); - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX() + 0, loc.getBlockY() + -1, - loc.getBlockZ() + 1, Material.DIRT, dirt); - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX() + 1, loc.getBlockY() + -1, - loc.getBlockZ(), Material.DIRT, dirt); - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX() + 1, loc.getBlockY() + -1, - loc.getBlockZ() + 1, Material.DIRT, dirt); + delegate.setTypeAndData(world, blockX + 0, blockY + -1, + blockZ + 1, Material.DIRT, dirt); + delegate.setTypeAndData(world, blockX + 1, blockY + -1, + blockZ, Material.DIRT, dirt); + delegate.setTypeAndData(world, blockX + 1, blockY + -1, + blockZ + 1, Material.DIRT, dirt); } - private void addVinesOnTrunk() { + private void addVinesOnTrunk(World world, int blockX, int blockY, int blockZ, Random random) { for (int y = 1; y < height; y++) { - maybePlaceVine(-1, y, 0, BlockFace.EAST); - maybePlaceVine(0, y, -1, BlockFace.SOUTH); - maybePlaceVine(2, y, 0, BlockFace.WEST); - maybePlaceVine(1, y, -1, BlockFace.SOUTH); - maybePlaceVine(2, y, 1, BlockFace.WEST); - maybePlaceVine(1, y, 2, BlockFace.NORTH); - maybePlaceVine(-1, y, 1, BlockFace.EAST); - maybePlaceVine(0, y, 2, BlockFace.NORTH); + maybePlaceVine(world, + blockX + -1, blockY + y, blockZ + 0, BlockFace.EAST, random + ); + maybePlaceVine(world, + blockX + 0, blockY + y, blockZ + -1, BlockFace.SOUTH, random + ); + maybePlaceVine(world, + blockX + 2, blockY + y, blockZ + 0, BlockFace.WEST, random + ); + maybePlaceVine(world, + blockX + 1, blockY + y, blockZ + -1, BlockFace.SOUTH, random + ); + maybePlaceVine(world, + blockX + 2, blockY + y, blockZ + 1, BlockFace.WEST, random + ); + maybePlaceVine(world, + blockX + 1, blockY + y, blockZ + 2, BlockFace.NORTH, random + ); + maybePlaceVine(world, + blockX + -1, blockY + y, blockZ + 1, BlockFace.EAST, random + ); + maybePlaceVine(world, + blockX + 0, blockY + y, blockZ + 2, BlockFace.NORTH, random + ); } } - private void maybePlaceVine(int x, int y, int z, BlockFace east) { - int absoluteX = loc.getBlockX() + x; - int absoluteY = loc.getBlockY() + y; - int absoluteZ = loc.getBlockZ() + z; + private void maybePlaceVine(World world, int absoluteX, int absoluteY, + int absoluteZ, BlockFace facingDirection, Random random) { if (random.nextInt(3) != 0 - && blockTypeAt(absoluteX, absoluteY, absoluteZ) == Material.AIR) { - delegate.setTypeAndData(loc.getWorld(), absoluteX, absoluteY, - absoluteZ, Material.VINE, new Vine(east)); + && blockTypeAt(absoluteX, absoluteY, absoluteZ, world) + == Material.AIR) { + delegate.setTypeAndData(world, absoluteX, absoluteY, + absoluteZ, Material.VINE, new Vine(facingDirection)); } } diff --git a/src/main/java/net/glowstone/generator/objects/trees/MegaPineTree.java b/src/main/java/net/glowstone/generator/objects/trees/MegaPineTree.java index 814d9b9f51..9a8eb49683 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/MegaPineTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/MegaPineTree.java @@ -4,6 +4,7 @@ import net.glowstone.util.BlockStateDelegate; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.material.Dirt; @@ -20,62 +21,60 @@ public class MegaPineTree extends MegaRedwoodTree { * blocks */ public MegaPineTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + super(random, delegate); setLeavesHeight(random.nextInt(5) + 3); } @Override - public boolean generate() { - boolean generated = super.generate(); + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { + boolean generated = super.generate(world, random, blockX, blockY, blockZ); if (generated) { - generatePodzol(); + generatePodzol(blockX, blockY, blockZ, world, random); } return generated; } @Override - protected void generateDirtBelowTrunk() { + protected void generateDirtBelowTrunk(World world, int blockX, int blockY, + int blockZ) { // SELF, SOUTH, EAST, SOUTH EAST Dirt dirt = new Dirt(DirtType.PODZOL); delegate - .setTypeAndData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() - 1, loc.getBlockZ(), + .setTypeAndData(world, blockX, blockY - 1, blockZ, Material.DIRT, dirt); - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() - 1, - loc.getBlockZ() + 1, Material.DIRT, dirt); - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX() + 1, loc.getBlockY() - 1, - loc.getBlockZ(), Material.DIRT, dirt); - delegate.setTypeAndData(loc.getWorld(), loc.getBlockX() + 1, loc.getBlockY() - 1, - loc.getBlockZ() + 1, Material.DIRT, dirt); + delegate.setTypeAndData(world, blockX, blockY - 1, + blockZ + 1, Material.DIRT, dirt); + delegate.setTypeAndData(world, blockX + 1, blockY - 1, + blockZ, Material.DIRT, dirt); + delegate.setTypeAndData(world, blockX + 1, blockY - 1, + blockZ + 1, Material.DIRT, dirt); } - private void generatePodzol() { - int sourceX = loc.getBlockX(); - int sourceY = loc.getBlockY(); - int sourceZ = loc.getBlockZ(); - generatePodzolPatch(sourceX - 1, sourceY, sourceZ - 1); - generatePodzolPatch(sourceX + 2, sourceY, sourceZ - 1); - generatePodzolPatch(sourceX - 1, sourceY, sourceZ + 2); - generatePodzolPatch(sourceX + 2, sourceY, sourceZ + 2); + private void generatePodzol(int sourceX, int sourceY, int sourceZ, World world, Random random) { + generatePodzolPatch(sourceX - 1, sourceY, sourceZ - 1, world); + generatePodzolPatch(sourceX + 2, sourceY, sourceZ - 1, world); + generatePodzolPatch(sourceX - 1, sourceY, sourceZ + 2, world); + generatePodzolPatch(sourceX + 2, sourceY, sourceZ + 2, world); for (int i = 0; i < 5; i++) { int n = random.nextInt(64); if (n % 8 == 0 || n % 8 == 7 || n / 8 == 0 || n / 8 == 7) { - generatePodzolPatch(sourceX - 3 + n % 8, sourceY, sourceZ - 3 + n / 8); + generatePodzolPatch(sourceX - 3 + n % 8, sourceY, sourceZ - 3 + n / 8, world); } } } - private void generatePodzolPatch(int sourceX, int sourceY, int sourceZ) { + private void generatePodzolPatch(int sourceX, int sourceY, int sourceZ, World world) { for (int x = -2; x <= 2; x++) { for (int z = -2; z <= 2; z++) { if (Math.abs(x) != 2 || Math.abs(z) != 2) { for (int y = 2; y >= -3; y--) { - Block block = loc.getWorld() + Block block = world .getBlockAt(sourceX + x, sourceY + y, sourceZ + z); if (block.getType() == Material.GRASS || block.getType() == Material.DIRT) { BlockState state = block.getState(); state.setType(Material.DIRT); DirtType dirtType = DirtType.PODZOL; - if (loc.getWorld().getBlockAt(sourceX + x, sourceY + y + 1, sourceZ + z) + if (world.getBlockAt(sourceX + x, sourceY + y + 1, sourceZ + z) .getType().isOccluding()) { dirtType = DirtType.NORMAL; } diff --git a/src/main/java/net/glowstone/generator/objects/trees/MegaRedwoodTree.java b/src/main/java/net/glowstone/generator/objects/trees/MegaRedwoodTree.java index 7d663cc540..ff62d8e943 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/MegaRedwoodTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/MegaRedwoodTree.java @@ -2,7 +2,7 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; +import org.bukkit.World; public class MegaRedwoodTree extends MegaJungleTree { @@ -10,14 +10,11 @@ public class MegaRedwoodTree extends MegaJungleTree { /** * Initializes this tree with a random height, preparing it to attempt to generate. - * - * @param random the PRNG - * @param location the base of the trunk + * @param random the PRNG * @param delegate the BlockStateDelegate used to check for space and to fill wood and leaf - * blocks */ - public MegaRedwoodTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public MegaRedwoodTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); setHeight(random.nextInt(15) + random.nextInt(3) + 13); setTypes(1, 1); setLeavesHeight(random.nextInt(5) + (random.nextBoolean() ? 3 : 13)); @@ -28,34 +25,35 @@ protected final void setLeavesHeight(int leavesHeight) { } @Override - public boolean generate() { - if (!canHeightFit() || !canPlaceOn() || !canPlace()) { + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { + if (cannotGenerateAt(blockX, blockY, blockZ, world)) { return false; } // generates the leaves int previousRadius = 0; - for (int y = loc.getBlockY() + height - leavesHeight; y <= loc.getBlockY() + height; y++) { - int n = loc.getBlockY() + height - y; + for (int y = blockY + height - leavesHeight; y <= blockY + height; y++) { + int n = blockY + height - y; int radius = (int) Math.floor((float) n / leavesHeight * 3.5F); if (radius == previousRadius && n > 0 && y % 2 == 0) { radius++; } - generateLeaves(loc.getBlockX(), y, loc.getBlockZ(), radius, false); + generateLeaves(blockX, y, blockZ, radius, false, world); previousRadius = radius; } // generates the trunk - generateTrunk(); + generateTrunk(world, blockX, blockY, blockZ); // blocks below trunk are always dirt - generateDirtBelowTrunk(); + generateDirtBelowTrunk(world, blockX, blockY, blockZ); return true; } @Override - protected void generateDirtBelowTrunk() { + protected void generateDirtBelowTrunk(World world, int blockX, int blockY, + int blockZ) { // mega redwood tree does not replaces blocks below (surely to preserves podzol) } } diff --git a/src/main/java/net/glowstone/generator/objects/trees/RedMushroomTree.java b/src/main/java/net/glowstone/generator/objects/trees/RedMushroomTree.java index 4f8ef005ec..c00d71ebb6 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/RedMushroomTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/RedMushroomTree.java @@ -2,7 +2,6 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; import org.bukkit.Material; public class RedMushroomTree extends BrownMushroomTree { @@ -11,12 +10,10 @@ public class RedMushroomTree extends BrownMushroomTree { * Initializes this mushroom, preparing it to attempt to generate. * * @param random the PRNG - * @param location the base of the trunk * @param delegate the BlockStateDelegate used to check for space and to fill wood and leaf - * blocks */ - public RedMushroomTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public RedMushroomTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); type = Material.HUGE_MUSHROOM_2; } } diff --git a/src/main/java/net/glowstone/generator/objects/trees/RedwoodTree.java b/src/main/java/net/glowstone/generator/objects/trees/RedwoodTree.java index 4ba1af2de5..33cecd8b02 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/RedwoodTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/RedwoodTree.java @@ -2,8 +2,8 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.material.Dirt; import org.bukkit.material.types.DirtType; @@ -14,14 +14,11 @@ public class RedwoodTree extends GenericTree { /** * Initializes this tree with a random height, preparing it to attempt to generate. - * * @param random the PRNG - * @param location the base of the trunk * @param delegate the BlockStateDelegate used to check for space and to fill wood and - * leaf blocks */ - public RedwoodTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public RedwoodTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); setOverridables( Material.AIR, Material.LEAVES @@ -41,21 +38,21 @@ protected final void setLeavesHeight(int leavesHeight) { } @Override - public boolean canPlace() { - for (int y = loc.getBlockY(); y <= loc.getBlockY() + 1 + height; y++) { + public boolean canPlace(int baseX, int baseY, int baseZ, World world) { + for (int y = baseY; y <= baseY + 1 + height; y++) { // Space requirement int radius; // default radius if above first block - if (y - loc.getBlockY() < leavesHeight) { + if (y - baseY < leavesHeight) { radius = 0; // radius is 0 for trunk below leaves } else { radius = maxRadius; } // check for block collision on horizontal slices - for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius; x++) { - for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius; z++) { + for (int x = baseX - radius; x <= baseX + radius; x++) { + for (int z = baseZ - radius; z <= baseZ + radius; z++) { if (y >= 0 && y < 256) { // we can overlap some blocks around - Material type = blockTypeAt(x, y, z); + Material type = blockTypeAt(x, y, z, world); if (!overridables.contains(type)) { return false; } @@ -69,8 +66,8 @@ public boolean canPlace() { } @Override - public boolean generate() { - if (!canHeightFit() || !canPlaceOn() || !canPlace()) { + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { + if (cannotGenerateAt(blockX, blockY, blockZ, world)) { return false; } @@ -78,14 +75,14 @@ public boolean generate() { int radius = random.nextInt(2); int peakRadius = 1; int minRadius = 0; - for (int y = loc.getBlockY() + height; y >= loc.getBlockY() + leavesHeight; y--) { + for (int y = blockY + height; y >= blockY + leavesHeight; y--) { // leaves are built from top to bottom - for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius; x++) { - for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius; z++) { - if ((Math.abs(x - loc.getBlockX()) != radius - || Math.abs(z - loc.getBlockZ()) != radius || radius <= 0) - && blockTypeAt(x, y, z) == Material.AIR) { - delegate.setTypeAndRawData(loc.getWorld(), x, y, z, Material.LEAVES, + for (int x = blockX - radius; x <= blockX + radius; x++) { + for (int z = blockZ - radius; z <= blockZ + radius; z++) { + if ((Math.abs(x - blockX) != radius + || Math.abs(z - blockZ) != radius || radius <= 0) + && blockTypeAt(x, y, z, world) == Material.AIR) { + delegate.setTypeAndRawData(world, x, y, z, Material.LEAVES, leavesType); } } @@ -104,18 +101,18 @@ && blockTypeAt(x, y, z) == Material.AIR) { // generate the trunk for (int y = 0; y < height - random.nextInt(3); y++) { - Material type = blockTypeAt(loc.getBlockX(), loc.getBlockY() + y, loc.getBlockZ()); + Material type = blockTypeAt(blockX, blockY + y, blockZ, world); if (overridables.contains(type)) { - delegate.setTypeAndRawData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() + y, - loc.getBlockZ(), Material.LOG, logType); + delegate.setTypeAndRawData(world, blockX, blockY + y, + blockZ, Material.LOG, logType); } } // block below trunk is always dirt Dirt dirt = new Dirt(DirtType.NORMAL); delegate - .setTypeAndData(loc.getWorld(), loc.getBlockX(), - loc.getBlockY() - 1, loc.getBlockZ(), + .setTypeAndData(world, blockX, + blockY - 1, blockZ, Material.DIRT, dirt); return true; diff --git a/src/main/java/net/glowstone/generator/objects/trees/SwampTree.java b/src/main/java/net/glowstone/generator/objects/trees/SwampTree.java index f4e2825495..37df2db9a8 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/SwampTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/SwampTree.java @@ -1,18 +1,27 @@ package net.glowstone.generator.objects.trees; +import com.google.common.collect.ImmutableList; import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.block.BlockFace; +import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.material.Dirt; import org.bukkit.material.types.DirtType; public class SwampTree extends CocoaTree { - public SwampTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public static final ImmutableList WATER_BLOCK_TYPES + = ImmutableList.of(Material.WATER, Material.STATIONARY_WATER); + + /** + * Initializes this tree with a random height, preparing it to attempt to generate. + * + * @param random the PRNG + * @param delegate the BlockStateDelegate used to check for space and to fill wood and + */ + public SwampTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); setOverridables( Material.AIR, Material.LEAVES @@ -22,32 +31,30 @@ public SwampTree(Random random, Location location, BlockStateDelegate delegate) } @Override - public boolean canPlaceOn() { - BlockState state = delegate - .getBlockState(loc.getBlock().getRelative(BlockFace.DOWN).getLocation()); - return state.getType() == Material.GRASS || state.getType() == Material.DIRT; + public boolean canPlaceOn(BlockState soil) { + return soil.getType() == Material.GRASS || soil.getType() == Material.DIRT; } @Override - public boolean canPlace() { - for (int y = loc.getBlockY(); y <= loc.getBlockY() + 1 + height; y++) { + public boolean canPlace(int baseX, int baseY, int baseZ, World world) { + for (int y = baseY; y <= baseY + 1 + height; y++) { // Space requirement int radius = 1; // default radius if above first block - if (y == loc.getBlockY()) { + if (y == baseY) { radius = 0; // radius at source block y is 0 (only trunk) - } else if (y >= loc.getBlockY() + 1 + height - 2) { + } else if (y >= baseY + 1 + height - 2) { radius = 3; // max radius starting at leaves bottom } // check for block collision on horizontal slices - for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius; x++) { - for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius; z++) { + for (int x = baseX - radius; x <= baseX + radius; x++) { + for (int z = baseZ - radius; z <= baseZ + radius; z++) { if (y >= 0 && y < 256) { // we can overlap some blocks around - Material type = blockTypeAt(x, y, z); + Material type = blockTypeAt(x, y, z, world); if (!overridables.contains(type)) { // the trunk can be immersed by 1 block of water if (type == Material.WATER || type == Material.STATIONARY_WATER) { - if (y > loc.getBlockY()) { + if (y > baseY) { return false; } } else { @@ -64,26 +71,25 @@ public boolean canPlace() { } @Override - public boolean generate() { - while (loc.getBlock().getRelative(BlockFace.DOWN).getType() == Material.WATER - || loc.getBlock().getRelative(BlockFace.DOWN).getType() == Material.STATIONARY_WATER) { - loc.subtract(0, 1, 0); + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { + while (WATER_BLOCK_TYPES.contains(world.getBlockAt(blockX, blockY, blockZ).getType())) { + blockY--; } - if (!canHeightFit() || !canPlaceOn() || !canPlace()) { + if (cannotGenerateAt(blockX, blockY, blockZ, world)) { return false; } // generate the leaves - for (int y = loc.getBlockY() + height - 3; y <= loc.getBlockY() + height; y++) { - int n = y - (loc.getBlockY() + height); + for (int y = blockY + height - 3; y <= blockY + height; y++) { + int n = y - (blockY + height); int radius = 2 - n / 2; - for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius; x++) { - for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius; z++) { - if (Math.abs(x - loc.getBlockX()) != radius - || Math.abs(z - loc.getBlockZ()) != radius + for (int x = blockX - radius; x <= blockX + radius; x++) { + for (int z = blockZ - radius; z <= blockZ + radius; z++) { + if (Math.abs(x - blockX) != radius + || Math.abs(z - blockZ) != radius || random.nextBoolean() && n != 0) { - replaceIfAirOrLeaves(x, y, z, Material.LEAVES, leavesType); + replaceIfAirOrLeaves(x, y, z, Material.LEAVES, leavesType, world); } } } @@ -91,21 +97,21 @@ public boolean generate() { // generate the trunk for (int y = 0; y < height; y++) { - Material material = blockTypeAt(loc.getBlockX(), loc.getBlockY() + y, loc.getBlockZ()); - if (material == Material.AIR || material == Material.LEAVES || - material == Material.WATER || material == Material.STATIONARY_WATER) { - delegate.setTypeAndRawData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() + y, - loc.getBlockZ(), Material.LOG, logType); + Material material = blockTypeAt(blockX, blockY + y, blockZ, world); + if (material == Material.AIR || material == Material.LEAVES + || material == Material.WATER || material == Material.STATIONARY_WATER) { + delegate.setTypeAndRawData( + world, blockX, blockY + y, blockZ, Material.LOG, logType); } } // add some vines on the leaves - addVinesOnLeaves(); + addVinesOnLeaves(blockX, blockY, blockZ, world, random); // block below trunk is always dirt Dirt dirt = new Dirt(DirtType.NORMAL); delegate - .setTypeAndData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() - 1, loc.getBlockZ(), + .setTypeAndData(world, blockX, blockY - 1, blockZ, Material.DIRT, dirt); return true; diff --git a/src/main/java/net/glowstone/generator/objects/trees/TallBirchTree.java b/src/main/java/net/glowstone/generator/objects/trees/TallBirchTree.java index 4590367457..73c0e802b7 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/TallBirchTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/TallBirchTree.java @@ -2,12 +2,11 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; public class TallBirchTree extends BirchTree { - public TallBirchTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + public TallBirchTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); setHeight(height + random.nextInt(7)); } } diff --git a/src/main/java/net/glowstone/generator/objects/trees/TallRedwoodTree.java b/src/main/java/net/glowstone/generator/objects/trees/TallRedwoodTree.java index 2103f6b3c3..cf0aec2c75 100644 --- a/src/main/java/net/glowstone/generator/objects/trees/TallRedwoodTree.java +++ b/src/main/java/net/glowstone/generator/objects/trees/TallRedwoodTree.java @@ -2,15 +2,21 @@ import java.util.Random; import net.glowstone.util.BlockStateDelegate; -import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.material.Dirt; import org.bukkit.material.types.DirtType; public class TallRedwoodTree extends RedwoodTree { - public TallRedwoodTree(Random random, Location location, BlockStateDelegate delegate) { - super(random, location, delegate); + /** + * Initializes this tree with a random height and radius, preparing it to attempt to generate. + * + * @param random the PRNG + * @param delegate the BlockStateDelegate used to check for space and to fill wood and + */ + public TallRedwoodTree(Random random, BlockStateDelegate delegate) { + super(random, delegate); setOverridables( Material.AIR, Material.LEAVES, @@ -27,26 +33,26 @@ public TallRedwoodTree(Random random, Location location, BlockStateDelegate dele } @Override - public boolean generate() { - if (!canHeightFit() || !canPlaceOn() || !canPlace()) { + public boolean generate(World world, Random random, int blockX, int blockY, int blockZ) { + if (cannotGenerateAt(blockX, blockY, blockZ, world)) { return false; } // generate the leaves int radius = 0; - for (int y = loc.getBlockY() + height; y >= loc.getBlockY() + leavesHeight; y--) { + for (int y = blockY + height; y >= blockY + leavesHeight; y--) { // leaves are built from top to bottom - for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius; x++) { - for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius; z++) { - if ((Math.abs(x - loc.getBlockX()) != radius - || Math.abs(z - loc.getBlockZ()) != radius || radius <= 0) && - blockTypeAt(x, y, z) == Material.AIR) { - delegate.setTypeAndRawData(loc.getWorld(), x, y, z, Material.LEAVES, + for (int x = blockX - radius; x <= blockX + radius; x++) { + for (int z = blockZ - radius; z <= blockZ + radius; z++) { + if ((Math.abs(x - blockX) != radius + || Math.abs(z - blockZ) != radius || radius <= 0) + && blockTypeAt(x, y, z, world) == Material.AIR) { + delegate.setTypeAndRawData(world, x, y, z, Material.LEAVES, leavesType); } } } - if (radius >= 1 && y == loc.getBlockY() + leavesHeight + 1) { + if (radius >= 1 && y == blockY + leavesHeight + 1) { radius--; } else if (radius < maxRadius) { radius++; @@ -55,14 +61,14 @@ public boolean generate() { // generate the trunk for (int y = 0; y < height - 1; y++) { - replaceIfAirOrLeaves(loc.getBlockX(), - loc.getBlockY() + y, loc.getBlockZ(), Material.LOG, logType); + replaceIfAirOrLeaves(blockX, + blockY + y, blockZ, Material.LOG, logType, world); } // block below trunk is always dirt Dirt dirt = new Dirt(DirtType.NORMAL); delegate - .setTypeAndData(loc.getWorld(), loc.getBlockX(), loc.getBlockY() - 1, loc.getBlockZ(), + .setTypeAndData(world, blockX, blockY - 1, blockZ, Material.DIRT, dirt); return true; diff --git a/src/main/java/net/glowstone/generator/populators/NetherPopulator.java b/src/main/java/net/glowstone/generator/populators/NetherPopulator.java index a5d794ea97..dd54e3f5a7 100644 --- a/src/main/java/net/glowstone/generator/populators/NetherPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/NetherPopulator.java @@ -30,6 +30,9 @@ public class NetherPopulator extends BlockPopulator { Material.RED_MUSHROOM); private final LavaDecorator lavaDecorator = new LavaDecorator(); + /** + * Creates a populator specialized for the Nether. + */ public NetherPopulator() { inGroundPopulators.add(orePopulator); diff --git a/src/main/java/net/glowstone/generator/populators/OverworldPopulator.java b/src/main/java/net/glowstone/generator/populators/OverworldPopulator.java index b269863772..e5d8547671 100644 --- a/src/main/java/net/glowstone/generator/populators/OverworldPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/OverworldPopulator.java @@ -38,6 +38,9 @@ public class OverworldPopulator extends BlockPopulator { private final Map biomePopulators = new HashMap<>(); + /** + * Creates a populator with biome populators for all vanilla overworld biomes. + */ public OverworldPopulator() { registerBiomePopulator(new BiomePopulator()); // defaults applied to all biomes registerBiomePopulator(new PlainsPopulator()); diff --git a/src/main/java/net/glowstone/generator/populators/StructurePopulator.java b/src/main/java/net/glowstone/generator/populators/StructurePopulator.java index ef3f7e802e..5c07519d20 100644 --- a/src/main/java/net/glowstone/generator/populators/StructurePopulator.java +++ b/src/main/java/net/glowstone/generator/populators/StructurePopulator.java @@ -26,14 +26,14 @@ public void populate(World world, Random random, Chunk source) { int cz = source.getZ(); random.setSeed(world.getSeed()); - long xRand = random.nextLong(); - long zRand = random.nextLong(); + long randX = random.nextLong(); + long randZ = random.nextLong(); boolean placed = false; for (int x = cx - 8; x <= cx + 8 && !placed; x++) { for (int z = cz - 8; z <= cz + 8 && !placed; z++) { if (world.getChunkAt(x, z).isLoaded() || world.getChunkAt(x, z).load(true)) { - random.setSeed(x * xRand + z * zRand ^ world.getSeed()); + random.setSeed(x * randX + z * randZ ^ world.getSeed()); Map structures = ((GlowWorld) world) .getStructures(); int key = GlowChunk.Key.of(x, z).hashCode(); @@ -62,8 +62,8 @@ public void populate(World world, Random random, Chunk source) { GlowStructure structure = it.next().getValue(); if (structure.getBoundingBox().intersectsWith(x, z, x + 15, z + 15)) { BlockStateDelegate delegate = new BlockStateDelegate(); - if (structure.generate(random, x, z, - delegate)) { // maybe later trigger a StructureGeneratedEvent event and cancel + if (structure.generate(random, x, z, delegate)) { + // maybe later trigger a StructureGeneratedEvent event and cancel delegate.updateBlockStates(); } else { delegate.rollbackBlockStates(); diff --git a/src/main/java/net/glowstone/generator/populators/nether/OrePopulator.java b/src/main/java/net/glowstone/generator/populators/nether/OrePopulator.java index 4fa599cf58..a63f5cd187 100644 --- a/src/main/java/net/glowstone/generator/populators/nether/OrePopulator.java +++ b/src/main/java/net/glowstone/generator/populators/nether/OrePopulator.java @@ -35,9 +35,7 @@ public void populate(World world, Random random, Chunk chunk) { int sourceX = cx + random.nextInt(16); int sourceZ = cz + random.nextInt(16); - int sourceY = oreType.getMinY() == oreType.getMaxY() ? - random.nextInt(oreType.getMinY()) + random.nextInt(oreType.getMinY()) : - random.nextInt(oreType.getMaxY() - oreType.getMinY()) + oreType.getMinY(); + int sourceY = oreType.getRandomHeight(random); new OreVein(oreType).generate(world, random, sourceX, sourceY, sourceZ); } diff --git a/src/main/java/net/glowstone/generator/populators/overworld/IcePlainsPopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/IcePlainsPopulator.java index 12cc4fc027..c78ad53610 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/IcePlainsPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/IcePlainsPopulator.java @@ -14,6 +14,10 @@ public class IcePlainsPopulator extends BiomePopulator { private static final Biome[] BIOMES = {Biome.ICE_FLATS, Biome.ICE_MOUNTAINS}; private static final TreeDecoration[] TREES = {new TreeDecoration(RedwoodTree.class, 1)}; + /** + * Creates a populator specialized for ice plains and ice mountains, with rabbits, polar bears + * and no vegetation. + */ public IcePlainsPopulator() { treeDecorator.setAmount(0); treeDecorator.setTrees(TREES); diff --git a/src/main/java/net/glowstone/generator/populators/overworld/JunglePopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/JunglePopulator.java index c3b12e73f7..a0d7cabb88 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/JunglePopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/JunglePopulator.java @@ -25,6 +25,9 @@ public class JunglePopulator extends BiomePopulator { private final MelonDecorator melonDecorator = new MelonDecorator(); + /** + * Creates a populator specialized for jungles. + */ public JunglePopulator() { treeDecorator.setAmount(65); treeDecorator.setTrees(TREES); @@ -50,8 +53,8 @@ public void populateOnGround(World world, Random random, Chunk chunk) { int y = world.getHighestBlockYAt(x, z); Block sourceBlock = world.getBlockAt(x, y, z); BlockStateDelegate delegate = new BlockStateDelegate(); - JungleBush bush = new JungleBush(random, sourceBlock.getLocation(), delegate); - if (bush.generate()) { + JungleBush bush = new JungleBush(random, delegate); + if (bush.generate(sourceBlock.getLocation())) { delegate.updateBlockStates(); } } diff --git a/src/main/java/net/glowstone/generator/populators/overworld/MegaTaigaPopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/MegaTaigaPopulator.java index aec34d21a3..277e8b7d96 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/MegaTaigaPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/MegaTaigaPopulator.java @@ -23,6 +23,9 @@ public class MegaTaigaPopulator extends TaigaPopulator { protected final StoneBoulderDecorator stoneBoulderDecorator = new StoneBoulderDecorator(); + /** + * Creates a populator specialized for the Mega Taiga and Mega Taiga Hills biomes. + */ public MegaTaigaPopulator() { treeDecorator.setTrees(TREES); tallGrassDecorator.setAmount(7); diff --git a/src/main/java/net/glowstone/generator/populators/overworld/MesaPopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/MesaPopulator.java index b2d95a2ada..50c182d13f 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/MesaPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/MesaPopulator.java @@ -10,6 +10,9 @@ public class MesaPopulator extends BiomePopulator { private static final Biome[] BIOMES = {Biome.MESA, Biome.MESA_CLEAR_ROCK, Biome.MUTATED_MESA_CLEAR_ROCK, Biome.MUTATED_MESA}; + /** + * Creates a populator specialized for mesa biomes. + */ public MesaPopulator() { flowerDecorator.setAmount(0); deadBushDecorator.setAmount(20); diff --git a/src/main/java/net/glowstone/generator/populators/overworld/MushroomIslandPopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/MushroomIslandPopulator.java index d85ff4b6b1..cd7e355848 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/MushroomIslandPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/MushroomIslandPopulator.java @@ -26,6 +26,9 @@ public class MushroomIslandPopulator extends BiomePopulator { protected final MushroomDecorator islandRedMushroomDecorator = new MushroomDecorator( Material.RED_MUSHROOM); + /** + * Creates a populator for the mushroom island biome. + */ public MushroomIslandPopulator() { treeDecorator.setAmount(1); treeDecorator.setTrees(TREES); diff --git a/src/main/java/net/glowstone/generator/populators/overworld/OceanPopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/OceanPopulator.java index 049d91dab9..173f9576b0 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/OceanPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/OceanPopulator.java @@ -9,6 +9,9 @@ public class OceanPopulator extends BiomePopulator { private static final Biome[] BIOMES = {Biome.DEEP_OCEAN, Biome.OCEAN}; + /** + * Creates a populator specialized for the ocean. + */ public OceanPopulator() { surfaceCaveDecorator.setAmount(0); entityDecorators.clear(); diff --git a/src/main/java/net/glowstone/generator/populators/overworld/OrePopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/OrePopulator.java index b233da3d0d..6d068d6130 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/OrePopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/OrePopulator.java @@ -14,12 +14,17 @@ import org.bukkit.material.types.StoneType; /** - * Populates the world with ores. + * Populates the world with ores. To get the complete set, we must also use + * {@link net.glowstone.generator.decorators.overworld.EmeraldOreDecorator}. */ public class OrePopulator extends BlockPopulator { private final Map ores = new LinkedHashMap<>(); + /** + * Creates a populator for dirt, gravel, andesite, diorite, granite; and coal, iron, gold, + * redstone, diamond and lapis lazuli ores. + */ public OrePopulator() { ores.put(new OreType(Material.DIRT, 0, 256, 32), 10); ores.put(new OreType(Material.GRAVEL, 0, 256, 32), 8); @@ -46,12 +51,11 @@ public void populate(World world, Random random, Chunk chunk) { int sourceX = cx + random.nextInt(16); int sourceZ = cz + random.nextInt(16); - int sourceY = oreType.getMinY() == oreType.getMaxY() ? - random.nextInt(oreType.getMinY()) + random.nextInt(oreType.getMinY()) : - random.nextInt(oreType.getMaxY() - oreType.getMinY()) + oreType.getMinY(); + int sourceY = oreType.getRandomHeight(random); new OreVein(oreType).generate(world, random, sourceX, sourceY, sourceZ); } } } + } diff --git a/src/main/java/net/glowstone/generator/populators/overworld/PlainsPopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/PlainsPopulator.java index 73b78bff15..ce49c94c1d 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/PlainsPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/PlainsPopulator.java @@ -25,6 +25,9 @@ public class PlainsPopulator extends BiomePopulator { FlowerType.TULIP_WHITE, FlowerType.TULIP_PINK}; private final OctaveGenerator noiseGen; + /** + * Creates a populator specialized for plains. + */ public PlainsPopulator() { flowerDecorator.setAmount(0); tallGrassDecorator.setAmount(0); diff --git a/src/main/java/net/glowstone/generator/populators/overworld/RoofedForestPopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/RoofedForestPopulator.java index 182622a656..136bfa495b 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/RoofedForestPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/RoofedForestPopulator.java @@ -19,6 +19,9 @@ public class RoofedForestPopulator extends ForestPopulator { new TreeDecoration(RedMushroomTree.class, 2), new TreeDecoration(BrownMushroomTree.class, 2), new TreeDecoration(DarkOakTree.class, 50)}; + /** + * Creates a populator specialized for the Roofed Forest and Roofed Forest M biomes. + */ public RoofedForestPopulator() { treeDecorator.setAmount(50); treeDecorator.setTrees(TREES); diff --git a/src/main/java/net/glowstone/generator/populators/overworld/SavannaMountainsPopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/SavannaMountainsPopulator.java index 44e610a600..babd6d54b5 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/SavannaMountainsPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/SavannaMountainsPopulator.java @@ -9,6 +9,9 @@ public class SavannaMountainsPopulator extends SavannaPopulator { private static final Biome[] BIOMES = {Biome.MUTATED_SAVANNA, Biome.MUTATED_SAVANNA_ROCK}; + /** + * Creates a populator specialized for the Savanna M and Savanna Plateau M biomes. + */ public SavannaMountainsPopulator() { treeDecorator.setAmount(2); flowerDecorator.setAmount(2); diff --git a/src/main/java/net/glowstone/generator/populators/overworld/SavannaPopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/SavannaPopulator.java index cbe8d9f110..5c6c7de875 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/SavannaPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/SavannaPopulator.java @@ -18,6 +18,9 @@ public class SavannaPopulator extends BiomePopulator { private static final TreeDecoration[] TREES = {new TreeDecoration(AcaciaTree.class, 4), new TreeDecoration(GenericTree.class, 1)}; + /** + * Creates a populator specialized for the Savanna and Savanna Plateau biomes. + */ public SavannaPopulator() { doublePlantDecorator.setAmount(7); doublePlantDecorator.setDoublePlants(DOUBLE_PLANTS); diff --git a/src/main/java/net/glowstone/generator/populators/overworld/SwamplandPopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/SwamplandPopulator.java index a4968c4820..2cc9d39f4f 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/SwamplandPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/SwamplandPopulator.java @@ -28,6 +28,9 @@ public class SwamplandPopulator extends BiomePopulator { Material.RED_MUSHROOM); protected final WaterLilyDecorator waterlilyDecorator = new WaterLilyDecorator(); + /** + * Creates a populator for the Swamp and Swamp M biomes. + */ public SwamplandPopulator() { sandPatchDecorator.setAmount(0); gravelPatchDecorator.setAmount(0); diff --git a/src/main/java/net/glowstone/generator/populators/overworld/TaigaPopulator.java b/src/main/java/net/glowstone/generator/populators/overworld/TaigaPopulator.java index 94bdf38e90..5dd1fb2ee9 100644 --- a/src/main/java/net/glowstone/generator/populators/overworld/TaigaPopulator.java +++ b/src/main/java/net/glowstone/generator/populators/overworld/TaigaPopulator.java @@ -30,6 +30,9 @@ public class TaigaPopulator extends BiomePopulator { protected final MushroomDecorator taigaRedMushroomDecorator = new MushroomDecorator( Material.RED_MUSHROOM); + /** + * Creates a populator specialized for Taiga, Taiga Hills and Taiga M, and their Cold variants. + */ public TaigaPopulator() { doublePlantDecorator.setAmount(7); doublePlantDecorator.setDoublePlants(DOUBLE_PLANTS); diff --git a/src/main/java/net/glowstone/generator/structures/GlowJungleTemple.java b/src/main/java/net/glowstone/generator/structures/GlowJungleTemple.java index eebcfae4e3..85689c1e5b 100644 --- a/src/main/java/net/glowstone/generator/structures/GlowJungleTemple.java +++ b/src/main/java/net/glowstone/generator/structures/GlowJungleTemple.java @@ -76,7 +76,7 @@ public boolean generate(World world, Random random, StructureBoundingBox genBoun return false; } - adjustHPos(world); + adjustHorizPos(world); boundingBox.offset(new Vector(0, -4, 0)); diff --git a/src/main/java/net/glowstone/generator/structures/GlowStructurePiece.java b/src/main/java/net/glowstone/generator/structures/GlowStructurePiece.java index dbe6ea633c..83f2c05dbf 100644 --- a/src/main/java/net/glowstone/generator/structures/GlowStructurePiece.java +++ b/src/main/java/net/glowstone/generator/structures/GlowStructurePiece.java @@ -1,6 +1,8 @@ package net.glowstone.generator.structures; import java.util.Random; +import lombok.Getter; +import lombok.Setter; import net.glowstone.generator.structures.util.StructureBoundingBox; import net.glowstone.util.BlockStateDelegate; import org.bukkit.Location; @@ -10,9 +12,19 @@ public abstract class GlowStructurePiece { + @Getter + @Setter protected StructureBoundingBox boundingBox; + @Getter private BlockFace orientation; - private int unknownGD; + /** + * The NBT data field "GD" described in + * https://minecraft.gamepedia.com/Generated_structures_data_file_format like this: + * "Appears to be some sort of measure of how far this piece is from the start." + */ + @Getter + @Setter + private int unknownGd; public GlowStructurePiece() { } @@ -22,6 +34,13 @@ public GlowStructurePiece(Location location, Vector size) { createNewBoundingBox(location, size); } + /** + * Creates a structure piece. + * + * @param random the PRNG that will choose the orientation + * @param location the root location + * @param size the size as a width-height-depth vector + */ public GlowStructurePiece(Random random, Location location, Vector size) { orientation = getOrientationFromOrdinal(random.nextInt(4)); switch (orientation) { @@ -35,22 +54,11 @@ public GlowStructurePiece(Random random, Location location, Vector size) { createNewBoundingBox(location, size); } - public StructureBoundingBox getBoundingBox() { - return boundingBox; - } - - public void setBoundingBox(StructureBoundingBox boundingBox) { - this.boundingBox = boundingBox; - } - - public int getGD() { - return unknownGD; - } - - public void setGD(int gd) { - unknownGD = gd; - } - + /** + * Returns the orientation using the numeric code from NBT. + * + * @return the orientation (0=north, 1=east, 2=south, 3=west) + */ public int getNumericOrientation() { switch (orientation) { case EAST: @@ -64,18 +72,19 @@ public int getNumericOrientation() { } } + /** + * Sets the orientation using the numeric code from NBT. + * + * @param orientation the new orientation (0=north, 1=east, 2=south, 3=west) + */ public void setNumericOrientation(int orientation) { this.orientation = getOrientationFromOrdinal(orientation); } - public BlockFace getOrientation() { - return orientation; - } - protected final BlockFace getRelativeFacing(BlockFace face) { BlockFace f = getOrientationFromOrdinal(orientation.ordinal() + face.ordinal() & 0x3); - if ((orientation == BlockFace.SOUTH || orientation == BlockFace.WEST) && - (face == BlockFace.EAST || face == BlockFace.WEST)) { + if ((orientation == BlockFace.SOUTH || orientation == BlockFace.WEST) + && (face == BlockFace.EAST || face == BlockFace.WEST)) { return f.getOppositeFace(); } return f; diff --git a/src/main/java/net/glowstone/generator/structures/GlowTemple.java b/src/main/java/net/glowstone/generator/structures/GlowTemple.java index c0b2b8485d..e28b83a0ab 100644 --- a/src/main/java/net/glowstone/generator/structures/GlowTemple.java +++ b/src/main/java/net/glowstone/generator/structures/GlowTemple.java @@ -7,12 +7,22 @@ import org.bukkit.World; import org.bukkit.block.Biome; +/** + * Desert temple, jungle temple, or witch hut. + */ public class GlowTemple extends GlowStructure { private static final int MIN_DISTANCE = 8; private static final int MAX_DISTANCE = 32; private final Map types = new HashMap<>(); + /** + * Creates a structure with no pieces. + * + * @param world the world to generate in + * @param chunkX the chunk X coordinate + * @param chunkZ the chunk Z coordinate + */ public GlowTemple(World world, int chunkX, int chunkZ) { super(world, chunkX, chunkZ); types.put(Biome.DESERT, TempleType.DESERT_TEMPLE); @@ -22,6 +32,14 @@ public GlowTemple(World world, int chunkX, int chunkZ) { types.put(Biome.SWAMPLAND, TempleType.WITCH_HUT); } + /** + * Creates a random temple or witch hut. + * + * @param world the world to generate in + * @param random the PRNG that will choose this temple's orientation + * @param chunkX the chunk X coordinate + * @param chunkZ the chunk Z coordinate + */ public GlowTemple(World world, Random random, int chunkX, int chunkZ) { this(world, chunkX, chunkZ); diff --git a/src/main/java/net/glowstone/generator/structures/GlowTemplePiece.java b/src/main/java/net/glowstone/generator/structures/GlowTemplePiece.java index 98c97c6d20..ecf41e0b3e 100644 --- a/src/main/java/net/glowstone/generator/structures/GlowTemplePiece.java +++ b/src/main/java/net/glowstone/generator/structures/GlowTemplePiece.java @@ -1,6 +1,8 @@ package net.glowstone.generator.structures; import java.util.Random; +import lombok.Getter; +import lombok.Setter; import net.glowstone.generator.objects.RandomItemsContent; import net.glowstone.generator.objects.RandomItemsContent.RandomAmountItem; import org.bukkit.Location; @@ -10,14 +12,29 @@ public abstract class GlowTemplePiece extends GlowStructurePiece { + @Getter + @Setter private int width; + @Getter + @Setter private int height; + @Getter + @Setter private int depth; - private int hPos = -1; + @Getter + @Setter + private int horizPos = -1; public GlowTemplePiece() { } + /** + * Creates a temple piece. + * + * @param random the PRNG that will choose the orientation + * @param location the root location + * @param size the size as a width-height-depth vector + */ public GlowTemplePiece(Random random, Location location, Vector size) { super(random, location, size); width = size.getBlockX(); @@ -25,51 +42,20 @@ public GlowTemplePiece(Random random, Location location, Vector size) { depth = size.getBlockZ(); } - public int getWidth() { - return width; - } - - public void setWidth(int width) { - this.width = width; - } - - public int getHeight() { - return height; - } - - public void setHeight(int height) { - this.height = height; - } - - public int getDepth() { - return depth; - } - - public void setDepth(int depth) { - this.depth = depth; - } - - public int getHPos() { - return hPos; - } - - public void setHPos(int hPos) { - this.hPos = hPos; - } - - protected void adjustHPos(World world) { - if (hPos >= 0) { + protected void adjustHorizPos(World world) { + if (horizPos >= 0) { return; } - int sumY = 0, blockCount = 0; + int sumY = 0; + int blockCount = 0; for (int x = boundingBox.getMin().getBlockX(); x <= boundingBox.getMax().getBlockX(); x++) { for (int z = boundingBox.getMin().getBlockZ(); z <= boundingBox.getMax().getBlockZ(); z++) { int y = world.getHighestBlockYAt(x, z); Material type = world.getBlockAt(x, y - 1, z).getType(); - while ((type == Material.LEAVES || type == Material.LEAVES_2 || - type == Material.LOG || type == Material.LOG_2) && y > 1) { + while ((type == Material.LEAVES || type == Material.LEAVES_2 + || type == Material.LOG || type == Material.LOG_2) && y > 1) { y--; type = world.getBlockAt(x, y - 1, z).getType(); } @@ -77,8 +63,8 @@ protected void adjustHPos(World world) { blockCount++; } } - hPos = sumY / blockCount; - boundingBox.offset(new Vector(0, hPos - boundingBox.getMin().getBlockY(), 0)); + horizPos = sumY / blockCount; + boundingBox.offset(new Vector(0, horizPos - boundingBox.getMin().getBlockY(), 0)); } protected RandomItemsContent getChestContent() { diff --git a/src/main/java/net/glowstone/generator/structures/GlowWitchHut.java b/src/main/java/net/glowstone/generator/structures/GlowWitchHut.java index e1f3dce75d..7527d3317c 100644 --- a/src/main/java/net/glowstone/generator/structures/GlowWitchHut.java +++ b/src/main/java/net/glowstone/generator/structures/GlowWitchHut.java @@ -38,7 +38,7 @@ public boolean generate(World world, Random random, StructureBoundingBox genBoun return false; } - adjustHPos(world); + adjustHorizPos(world); StructureBuilder builder = new StructureBuilder(world, this, genBoundingBox, delegate); builder.fill(new Vector(1, 1, 2), new Vector(5, 4, 7), Material.WOOD, 1, diff --git a/src/main/java/net/glowstone/generator/structures/util/StructureBoundingBox.java b/src/main/java/net/glowstone/generator/structures/util/StructureBoundingBox.java index ecf32bc5ce..b2ce29b1fe 100644 --- a/src/main/java/net/glowstone/generator/structures/util/StructureBoundingBox.java +++ b/src/main/java/net/glowstone/generator/structures/util/StructureBoundingBox.java @@ -1,10 +1,13 @@ package net.glowstone.generator.structures.util; +import lombok.Getter; import org.bukkit.util.Vector; public class StructureBoundingBox { + @Getter private Vector min; + @Getter private Vector max; public StructureBoundingBox(Vector min, Vector max) { @@ -12,41 +15,60 @@ public StructureBoundingBox(Vector min, Vector max) { this.max = max; } - public Vector getMin() { - return min; - } - - public Vector getMax() { - return max; - } - + /** + * Checks whether the given point is inside a block that intersects this box. + * + * @param vec the point to check + * @return true if this box intersects the block containing {@code vec} + */ public boolean isVectorInside(Vector vec) { - return vec.getBlockX() >= min.getBlockX() && vec.getBlockX() <= max.getBlockX() && - vec.getBlockY() >= min.getBlockY() && vec.getBlockY() <= max.getBlockY() && - vec.getBlockZ() >= min.getBlockZ() && vec.getBlockZ() <= max.getBlockZ(); + return vec.getBlockX() >= min.getBlockX() && vec.getBlockX() <= max.getBlockX() + && vec.getBlockY() >= min.getBlockY() && vec.getBlockY() <= max.getBlockY() + && vec.getBlockZ() >= min.getBlockZ() && vec.getBlockZ() <= max.getBlockZ(); } + /** + * Whether this box intersects the given box. + * + * @param boundingBox the box to check intersection with + * @return true if the given box intersects this box; false otherwise + */ public boolean intersectsWith(StructureBoundingBox boundingBox) { return boundingBox.getMin().getBlockX() <= max.getBlockX() - && boundingBox.getMax().getBlockX() >= min.getBlockX() && - boundingBox.getMin().getBlockY() <= max.getBlockY() - && boundingBox.getMax().getBlockY() >= min.getBlockY() && - boundingBox.getMin().getBlockZ() <= max.getBlockZ() - && boundingBox.getMax().getBlockZ() >= min.getBlockZ(); + && boundingBox.getMax().getBlockX() >= min.getBlockX() + && boundingBox.getMin().getBlockY() <= max.getBlockY() + && boundingBox.getMax().getBlockY() >= min.getBlockY() + && boundingBox.getMin().getBlockZ() <= max.getBlockZ() + && boundingBox.getMax().getBlockZ() >= min.getBlockZ(); } + /** + * Whether this box intersects the given vertically-infinite box. + * + * @param minX the minimum X coordinate + * @param minZ the minimum Z coordinate + * @param maxX the maximum X coordinate + * @param maxZ the maximum Z coordinate + * @return true if the given box intersects this box; false otherwise + */ public boolean intersectsWith(int minX, int minZ, int maxX, int maxZ) { - return minX <= max.getBlockX() && maxX >= min.getBlockX() && - minZ <= max.getBlockZ() && maxZ >= min.getBlockZ(); + return minX <= max.getBlockX() && maxX >= min.getBlockX() + && minZ <= max.getBlockZ() && maxZ >= min.getBlockZ(); } + /** + * Changes this bounding box to the bounding box of the union of itself and another bounding + * box. + * + * @param boundingBox the other bounding box to contain + */ public void expandTo(StructureBoundingBox boundingBox) { min = new Vector(Math.min(min.getBlockX(), boundingBox.getMin().getBlockX()), - Math.min(min.getBlockY(), boundingBox.getMin().getBlockY()), - Math.min(min.getBlockZ(), boundingBox.getMin().getBlockZ())); + Math.min(min.getBlockY(), boundingBox.getMin().getBlockY()), + Math.min(min.getBlockZ(), boundingBox.getMin().getBlockZ())); max = new Vector(Math.max(max.getBlockX(), boundingBox.getMax().getBlockX()), - Math.max(max.getBlockY(), boundingBox.getMax().getBlockY()), - Math.max(max.getBlockZ(), boundingBox.getMax().getBlockZ())); + Math.max(max.getBlockY(), boundingBox.getMax().getBlockY()), + Math.max(max.getBlockZ(), boundingBox.getMax().getBlockZ())); } public void offset(Vector offset) { diff --git a/src/main/java/net/glowstone/generator/structures/util/StructureBuilder.java b/src/main/java/net/glowstone/generator/structures/util/StructureBuilder.java index d9c4a81d30..f74ceb384c 100644 --- a/src/main/java/net/glowstone/generator/structures/util/StructureBuilder.java +++ b/src/main/java/net/glowstone/generator/structures/util/StructureBuilder.java @@ -3,6 +3,9 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Random; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.RequiredArgsConstructor; import net.glowstone.generator.objects.RandomItemsContent; import net.glowstone.generator.structures.GlowStructurePiece; import net.glowstone.util.BlockStateDelegate; @@ -16,28 +19,41 @@ import org.bukkit.material.MaterialData; import org.bukkit.util.Vector; +@RequiredArgsConstructor public class StructureBuilder { + /** + * The world this structure is built in. + */ private final World world; - private final BlockStateDelegate delegate; - private final StructureBoundingBox boundingBox; + /** + * The structure piece whose coordinate origin and orientation we're using. + */ private final GlowStructurePiece structure; - - public StructureBuilder(World world, GlowStructurePiece structure, - StructureBoundingBox boundingBox, BlockStateDelegate delegate) { - this.world = world; - this.delegate = delegate; - this.boundingBox = boundingBox; - this.structure = structure; - } + /** + * The bounding box in which to operate; not necessarily the same as the structure piece's + * bounding box. + */ + private final StructureBoundingBox boundingBox; + /** + * The BlockStateDelegate used to read and write blocks. + */ + private final BlockStateDelegate delegate; public void addRandomMaterial(Map materials, int weight, - Material type, int data) { + Material type, int data) { materials.put(new StructureMaterial(type, data), weight); } + /** + * Chooses a random {@link StructureMaterial} from a weighted list. + * + * @param random the PRNG to use + * @param materials a map of materials to integer weights + * @return a random material + */ public StructureMaterial getRandomMaterial(Random random, - Map materials) { + Map materials) { int totalWeight = 0; for (int weight : materials.values()) { totalWeight += weight; @@ -57,117 +73,267 @@ public BlockState getBlockState(Vector pos) { return delegate.getBlockState(world, vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); } + /** + * Sets the block at a given point, if it is inside this structure's bounding box. + * + * @param pos a point relative to this structure's root point + * @param type the new block type + */ public void setBlock(Vector pos, Material type) { setBlock(pos, type, 0); } + /** + * Sets the block at a given point, if it is inside this builder's bounding box. + * + * @param pos a point relative to this structure's root point + * @param type the new block type + * @param data the new block data + */ public void setBlock(Vector pos, Material type, int data) { Vector vec = translate(pos); if (boundingBox.isVectorInside(vec)) { delegate - .setTypeAndRawData(world, vec.getBlockX(), vec.getBlockY(), vec.getBlockZ(), type, - data); + .setTypeAndRawData(world, vec.getBlockX(), vec.getBlockY(), vec + .getBlockZ(), type, + data); } } + /** + * Sets the block at a given point, if it is inside this structure's bounding box. + * + * @param pos a point relative to this structure's root point + * @param type the new block type + * @param data the new block data + */ public void setBlock(Vector pos, Material type, MaterialData data) { Vector vec = translate(pos); if (boundingBox.isVectorInside(vec)) { delegate.setTypeAndData(world, vec.getBlockX(), vec.getBlockY(), vec.getBlockZ(), type, - data); + data); } } + /** + * Builds a 1x1 column out of the given block, replacing non-solid blocks starting at a given + * location and proceeding downward until a solid block is reached. + * + * @param pos the highest point to possibly replace, relative to this structure's root + * point + * @param type the block type to fill + */ public void setBlockDownward(Vector pos, Material type) { setBlockDownward(pos, type, 0); } + /** + * Builds a 1x1 column out of the given block, replacing non-solid blocks starting at a given + * location and proceeding downward until a solid block is reached. + * + * @param pos the highest point to possibly replace, relative to this structure's root + * point + * @param type the block type to fill + * @param data the block data + */ public void setBlockDownward(Vector pos, Material type, int data) { Vector vec = translate(pos); if (boundingBox.isVectorInside(vec)) { int y = vec.getBlockY(); while (!world.getBlockAt(vec.getBlockX(), y, vec.getBlockZ()).getType().isSolid() - && y > 1) { + && y > 1) { delegate.setTypeAndRawData(world, vec.getBlockX(), y, vec.getBlockZ(), type, data); y--; } } } + /** + * Builds a 1x1 column out of the given block, replacing non-solid blocks starting at a given + * location and proceeding downward until a solid block is reached. + * + * @param pos the highest point to possibly replace, relative to this structure's root + * point + * @param type the block type to fill + * @param data the block data + */ public void setBlockDownward(Vector pos, Material type, MaterialData data) { Vector vec = translate(pos); if (boundingBox.isVectorInside(vec)) { + int x = vec.getBlockX(); int y = vec.getBlockY(); - while (!world.getBlockAt(vec.getBlockX(), y, vec.getBlockZ()).getType().isSolid() - && y > 1) { - delegate.setTypeAndData(world, vec.getBlockX(), y, vec.getBlockZ(), type, data); + int z = vec.getBlockZ(); + while (!world.getBlockAt(x, y, z).getType().isSolid() && y > 1) { + delegate.setTypeAndData(world, x, y, z, type, data); y--; } } } public void setBlockWithRandomMaterial(Vector pos, Random random, - Map materials) { + Map materials) { StructureMaterial material = getRandomMaterial(random, materials); setBlock(pos, material.getType(), material.getData()); } + /** + * Fills a box with the given block. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param type the block type + */ public void fill(Vector min, Vector max, Material type) { fill(min, max, type, 0); } + /** + * Fills a box with the given block. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param type the block type + * @param data the block data + */ public void fill(Vector min, Vector max, Material type, int data) { fill(min, max, type, data, type, data); } + /** + * Fills a box with the given block. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param type the block type + * @param data the block data + */ public void fill(Vector min, Vector max, Material type, MaterialData data) { fill(min, max, type, data, type, data); } + /** + * Builds a box from one block, and fills it with another. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param outerType the block type for the faces + * @param innerType the block type for the interior + */ public void fill(Vector min, Vector max, Material outerType, Material innerType) { fill(min, max, outerType, 0, innerType, 0); } + /** + * Builds a box from one block, and fills it with another. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param outerType the block type for the faces + * @param innerType the block type for the interior + * @param innerData the block data for the interior + */ public void fill(Vector min, Vector max, Material outerType, Material innerType, - int innerData) { + int innerData) { fill(min, max, outerType, 0, innerType, innerData); } + /** + * Builds a box from one block, and fills it with another. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param outerType the block type for the faces + * @param innerType the block type for the interior + * @param innerData the block data for the interior + */ public void fill(Vector min, Vector max, Material outerType, Material innerType, - MaterialData innerData) { + MaterialData innerData) { fill(min, max, outerType, 0, innerType, innerData); } + /** + * Builds a box from one block, and fills it with another. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param outerType the block type for the faces + * @param outerData the block data for the faces + * @param innerType the block type for the interior + * @param innerData the block data for the interior + */ public void fill(Vector min, Vector max, Material outerType, int outerData, Material innerType, - MaterialData innerData) { + MaterialData innerData) { fill(min, max, outerType, outerData, innerType, innerData.getData()); } + /** + * Builds a box from one block, and fills it with another. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param outerType the block type for the faces + * @param outerData the block data for the faces + * @param innerType the block type for the interior + */ public void fill(Vector min, Vector max, Material outerType, int outerData, - Material innerType) { + Material innerType) { fill(min, max, outerType, outerData, innerType, 0); } + /** + * Builds a box from one block, and fills it with another. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param outerType the block type for the faces + * @param outerData the block data for the faces + * @param innerType the block type for the interior + */ public void fill(Vector min, Vector max, Material outerType, MaterialData outerData, - Material innerType) { + Material innerType) { fill(min, max, outerType, outerData, innerType, 0); } + /** + * Builds a box from one block, and fills it with another. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param outerType the block type for the faces + * @param outerData the block data for the faces + * @param innerType the block type for the interior + * @param innerData the block data for the interior + */ public void fill(Vector min, Vector max, Material outerType, MaterialData outerData, - Material innerType, int innerData) { + Material innerType, int innerData) { fill(min, max, outerType, outerData.getData(), innerType, innerData); } + /** + * Builds a box from one block, and fills it with another. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param outerType the block type for the faces + * @param outerData the block data for the faces + * @param innerType the block type for the interior + * @param innerData the block data for the interior + */ public void fill(Vector min, Vector max, Material outerType, int outerData, Material innerType, - int innerData) { - for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { - for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { - for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + int innerData) { + int minX = min.getBlockX(); + int minY = min.getBlockY(); + int minZ = min.getBlockZ(); + int maxX = max.getBlockX(); + int maxY = max.getBlockY(); + int maxZ = max.getBlockZ(); + for (int y = minY; y <= maxY; y++) { + for (int x = minX; x <= maxX; x++) { + for (int z = minZ; z <= maxZ; z++) { Material type; int data; - if (x != min.getBlockX() && x != max.getBlockX() && - z != min.getBlockZ() && z != max.getBlockZ() && - y != min.getBlockY() && y != max.getBlockY()) { + if (x != minX && x != maxX && z != minZ && z != maxZ + && y != minY && y != maxY) { type = innerType; data = innerData; } else { @@ -180,16 +346,31 @@ public void fill(Vector min, Vector max, Material outerType, int outerData, Mate } } + /** + * Builds a box from one block, and fills it with another. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param outerType the block type for the faces + * @param outerData the block data for the faces + * @param innerType the block type for the interior + * @param innerData the block data for the interior + */ public void fill(Vector min, Vector max, Material outerType, MaterialData outerData, - Material innerType, MaterialData innerData) { - for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { - for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { - for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + Material innerType, MaterialData innerData) { + int minX = min.getBlockX(); + int minY = min.getBlockY(); + int minZ = min.getBlockZ(); + int maxX = max.getBlockX(); + int maxY = max.getBlockY(); + int maxZ = max.getBlockZ(); + for (int y = minY; y <= maxY; y++) { + for (int x = minX; x <= maxX; x++) { + for (int z = minZ; z <= maxZ; z++) { Material type; MaterialData data; - if (x != min.getBlockX() && x != max.getBlockX() && - z != min.getBlockZ() && z != max.getBlockZ() && - y != min.getBlockY() && y != max.getBlockY()) { + if (x != minX && x != maxX && z != minZ && z != maxZ + && y != minY && y != maxY) { type = innerType; data = innerData; } else { @@ -202,8 +383,16 @@ public void fill(Vector min, Vector max, Material outerType, MaterialData outerD } } + /** + * Sets a box of blocks to have random types, chosen independently. + * + * @param min the minimum coordinates, relative to this structure's root point + * @param max the maximum coordinates, relative to this structure's root point + * @param random the PRNG to use + * @param materials a map of possible blocks to integer weights + */ public void fillWithRandomMaterial(Vector min, Vector max, Random random, - Map materials) { + Map materials) { for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { @@ -214,28 +403,46 @@ public void fillWithRandomMaterial(Vector min, Vector max, Random random, } } + /** + * Sets the given block to a container and fills it with random items. + * + * @param pos a point relative to this structure's root point + * @param random the PRNG to use + * @param content the distribution to draw items from + * @param container the container to place + * @param maxStacks the maximum number of slots to fill + * @return true if the container was placed and filled; false if {@code pos} is outside the + * builder's bounding box or {@link RandomItemsContent#fillContainer(Random, BlockState, + * int)} fails + */ public boolean createRandomItemsContainer(Vector pos, Random random, RandomItemsContent content, - DirectionalContainer container, int maxStacks) { + DirectionalContainer container, int maxStacks) { Vector vec = translate(pos); if (boundingBox.isVectorInside(vec)) { BlockState state = world.getBlockAt(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()) - .getState(); + .getState(); delegate.backupBlockState(state.getBlock()); state.setType(container.getItemType()); state.setData(container); state.update(true); - return content.fillContainer(random, container, state, maxStacks); + return content.fillContainer(random, state, maxStacks); } return false; } + /** + * Sets the given block to a spawner for the given entity type. + * + * @param pos a point relative to this structure's root point + * @param entityType the type of entity the spawner will spawn + */ public void createMobSpawner(Vector pos, EntityType entityType) { Vector vec = translate(pos); if (boundingBox.isVectorInside(vec)) { BlockState state = world.getBlockAt(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()) - .getState(); + .getState(); delegate.backupBlockState(state.getBlock()); state.setType(Material.MOB_SPAWNER); @@ -248,11 +455,19 @@ public void createMobSpawner(Vector pos, EntityType entityType) { } } + /** + * Spawns an entity if the given position is within this structure's bounding box. + * + * @param pos a point relative to this structure's root point + * @param entityType the type of entity to spawn + * @return true if the entity was spawned; false if {@code pos} is outside the builder's + * bounding box or {@link World#spawnEntity(Location, EntityType)} fails + */ public boolean spawnMob(Vector pos, EntityType entityType) { Vector vec = translate(pos); return boundingBox.isVectorInside(vec) && world - .spawnEntity(new Location(world, vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()), - entityType) != null; + .spawnEntity(new Location(world, vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()), + entityType) != null; } private Vector translate(Vector pos) { @@ -260,43 +475,31 @@ private Vector translate(Vector pos) { switch (structure.getOrientation()) { case EAST: return new Vector(boundingBox.getMax().getBlockX() - pos.getBlockZ(), - boundingBox.getMin().getBlockY() + pos.getBlockY(), - boundingBox.getMin().getBlockZ() + pos.getBlockX()); + boundingBox.getMin().getBlockY() + pos.getBlockY(), + boundingBox.getMin().getBlockZ() + pos.getBlockX()); case SOUTH: return new Vector(boundingBox.getMin().getBlockX() + pos.getBlockX(), - boundingBox.getMin().getBlockY() + pos.getBlockY(), - boundingBox.getMax().getBlockZ() - pos.getBlockZ()); + boundingBox.getMin().getBlockY() + pos.getBlockY(), + boundingBox.getMax().getBlockZ() - pos.getBlockZ()); case WEST: return new Vector(boundingBox.getMin().getBlockX() + pos.getBlockZ(), - boundingBox.getMin().getBlockY() + pos.getBlockY(), - boundingBox.getMin().getBlockZ() + pos.getBlockX()); + boundingBox.getMin().getBlockY() + pos.getBlockY(), + boundingBox.getMin().getBlockZ() + pos.getBlockX()); default: // NORTH return new Vector(boundingBox.getMin().getBlockX() + pos.getBlockX(), - boundingBox.getMin().getBlockY() + pos.getBlockY(), - boundingBox.getMin().getBlockZ() + pos.getBlockZ()); + boundingBox.getMin().getBlockY() + pos.getBlockY(), + boundingBox.getMin().getBlockZ() + pos.getBlockZ()); } } - public static class StructureMaterial { - - private Material type; - private int data; - + @AllArgsConstructor + @Data + public static final class StructureMaterial { public StructureMaterial(Material type) { this(type, 0); } - public StructureMaterial(Material type, int data) { - this.type = type; - this.data = data; - } - - public Material getType() { - return type; - } - - public int getData() { - return data; - } + private Material type; + private int data; } } diff --git a/src/main/java/net/glowstone/inventory/EquipmentMonitor.java b/src/main/java/net/glowstone/inventory/EquipmentMonitor.java index a1e662a957..941802143c 100644 --- a/src/main/java/net/glowstone/inventory/EquipmentMonitor.java +++ b/src/main/java/net/glowstone/inventory/EquipmentMonitor.java @@ -4,6 +4,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Objects; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.bukkit.entity.LivingEntity; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; @@ -11,11 +13,16 @@ /** * Tracker for when the equipment of an entity is changed. */ +@RequiredArgsConstructor public final class EquipmentMonitor { /** * The entity whose equipment is being monitored. + * + * @param entity The entity whose equipment to monitor. + * @return The entity. */ + @Getter private final LivingEntity entity; /** @@ -33,15 +40,6 @@ public final class EquipmentMonitor { */ private boolean changesCalculated; - /** - * Create a new monitor for the given entity. - * - * @param entity The entity whose equipment to monitor. - */ - public EquipmentMonitor(LivingEntity entity) { - this.entity = entity; - } - /** * Get the item in the inventory. * @@ -119,15 +117,6 @@ public void resetChanges() { } } - /** - * Get the entity whose equipment is being monitored. - * - * @return The entity equipment. - */ - public LivingEntity getEntity() { - return entity; - } - /** * An entry which has been changed. */ diff --git a/src/main/java/net/glowstone/inventory/GlowAnvilInventory.java b/src/main/java/net/glowstone/inventory/GlowAnvilInventory.java index 7ffe3aee9e..2b28bc8b38 100644 --- a/src/main/java/net/glowstone/inventory/GlowAnvilInventory.java +++ b/src/main/java/net/glowstone/inventory/GlowAnvilInventory.java @@ -1,6 +1,8 @@ package net.glowstone.inventory; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; import net.glowstone.entity.GlowPlayer; import net.glowstone.util.InventoryUtil; import org.bukkit.ChatColor; @@ -19,7 +21,10 @@ public class GlowAnvilInventory extends GlowInventory implements AnvilInventory private static final int FIRST_ITEM_SLOT = 0; private static final int SECOND_ITEM_SLOT = 1; private static final int RESULT_SLOT = 2; - private String rename = ""; + @Getter + private String renameText = ""; + @Getter + @Setter private int repairCost; /** @@ -124,19 +129,14 @@ public ItemStack getForged() { return null; } - @Override - public String getRenameText() { - return rename; - } - /** * Sets the name of the next item to be modified on this anvil. * * @param name the item name */ public void setRenameText(String name) { - rename = name; - if (rename.isEmpty()) { + renameText = name; + if (renameText.isEmpty()) { setItem(FIRST_ITEM_SLOT, getFirstItem()); setItem(SECOND_ITEM_SLOT, getSecondItem()); } else { @@ -147,20 +147,10 @@ public void setRenameText(String name) { } // rename the item ItemMeta m = result.getItemMeta(); - m.setDisplayName(ChatColor.ITALIC + rename); + m.setDisplayName(ChatColor.ITALIC + renameText); result.setItemMeta(m); setItem(RESULT_SLOT, result); } } } - - @Override - public int getRepairCost() { - return repairCost; - } - - @Override - public void setRepairCost(int levels) { - repairCost = levels; - } } diff --git a/src/main/java/net/glowstone/inventory/GlowEnchantingInventory.java b/src/main/java/net/glowstone/inventory/GlowEnchantingInventory.java index f178ed6c6f..e1ae28d283 100644 --- a/src/main/java/net/glowstone/inventory/GlowEnchantingInventory.java +++ b/src/main/java/net/glowstone/inventory/GlowEnchantingInventory.java @@ -2,6 +2,7 @@ import static net.glowstone.util.Position.copyPosition; +import lombok.Getter; import net.glowstone.entity.GlowPlayer; import org.bukkit.Location; import org.bukkit.Material; @@ -15,6 +16,7 @@ public class GlowEnchantingInventory extends GlowInventory implements Enchanting private static final int ITEM_SLOT = 0; private static final int LAPIS_SLOT = 1; + @Getter private final Location location; private final EnchantmentManager enchantmentManager; @@ -104,10 +106,6 @@ public void setItem(int index, ItemStack item) { enchantmentManager.invalidate(); } - public Location getLocation() { - return location; - } - @Override public int getRawSlots() { return 0; diff --git a/src/main/java/net/glowstone/inventory/GlowEntityEquipment.java b/src/main/java/net/glowstone/inventory/GlowEntityEquipment.java index 8301b8bc1c..ea45577c0e 100644 --- a/src/main/java/net/glowstone/inventory/GlowEntityEquipment.java +++ b/src/main/java/net/glowstone/inventory/GlowEntityEquipment.java @@ -1,6 +1,7 @@ package net.glowstone.inventory; import lombok.AllArgsConstructor; +import lombok.Getter; import net.glowstone.constants.ItemIds; import net.glowstone.util.InventoryUtil; import org.bukkit.entity.Entity; @@ -11,6 +12,7 @@ public class GlowEntityEquipment implements EntityEquipment { private Entry[] slots = new Entry[6]; + @Getter private Entity holder; public GlowEntityEquipment(Entity holder) { @@ -225,11 +227,6 @@ public void setBootsDropChance(float chance) { setDropChance(EquipmentSlot.FEET, chance); } - @Override - public Entity getHolder() { - return this.holder; - } - @AllArgsConstructor private class Entry { diff --git a/src/main/java/net/glowstone/inventory/GlowInventory.java b/src/main/java/net/glowstone/inventory/GlowInventory.java index 610feb7289..bfab8ef09e 100644 --- a/src/main/java/net/glowstone/inventory/GlowInventory.java +++ b/src/main/java/net/glowstone/inventory/GlowInventory.java @@ -8,6 +8,8 @@ import java.util.ListIterator; import java.util.Objects; import java.util.Set; +import lombok.Getter; +import lombok.Setter; import net.glowstone.GlowServer; import net.glowstone.entity.GlowPlayer; import net.glowstone.util.InventoryUtil; @@ -39,36 +41,41 @@ public class GlowInventory implements Inventory { /** * The owner of this inventory. */ - private InventoryHolder owner; + @Getter + private InventoryHolder holder; /** * The type of this inventory. */ + @Getter private InventoryType type; /** * The inventory's name. */ + @Getter private String title; /** * The inventory's maximum stack size. */ + @Getter + @Setter private int maxStackSize = 64; protected GlowInventory() { } - public GlowInventory(InventoryHolder owner, InventoryType type) { - this(owner, type, type.getDefaultSize(), type.getDefaultTitle()); + public GlowInventory(InventoryHolder holder, InventoryType type) { + this(holder, type, type.getDefaultSize(), type.getDefaultTitle()); } - public GlowInventory(InventoryHolder owner, InventoryType type, int size) { - this(owner, type, size, type.getDefaultTitle()); + public GlowInventory(InventoryHolder holder, InventoryType type, int size) { + this(holder, type, size, type.getDefaultTitle()); } - public GlowInventory(InventoryHolder owner, InventoryType type, int size, String title) { - initialize(GlowInventorySlot.createList(size), new HashSet<>(), owner, type, title); + public GlowInventory(InventoryHolder holder, InventoryType type, int size, String title) { + initialize(GlowInventorySlot.createList(size), new HashSet<>(), holder, type, title); } /** @@ -86,7 +93,7 @@ protected void initialize(List slots, Set viewer InventoryHolder owner, InventoryType type, String title) { this.slots = slots; this.viewers = viewers; - this.owner = owner; + this.holder = owner; this.type = type; this.title = title; } @@ -118,6 +125,7 @@ public void removeViewer(HumanEntity viewer) { * @return Viewers set. */ public Set getViewersSet() { + // TODO: Defensive copy return viewers; } @@ -290,26 +298,13 @@ public int getSize() { * @return Slot list. */ public List getSlots() { + // TODO: Defensive copy return slots; } - @Override - public final InventoryType getType() { - return type; - } - - @Override - public InventoryHolder getHolder() { - return owner; - } - @Override public final String getName() { - return title; - } - - @Override - public final String getTitle() { + // Can't be fully Lombokified because getTitle() is identical return title; } @@ -326,16 +321,6 @@ public void setTitle(String title) { } } - @Override - public int getMaxStackSize() { - return maxStackSize; - } - - @Override - public void setMaxStackSize(int size) { - maxStackSize = size; - } - @Override public List getViewers() { return new ArrayList<>(viewers); diff --git a/src/main/java/net/glowstone/inventory/GlowInventorySlot.java b/src/main/java/net/glowstone/inventory/GlowInventorySlot.java index 51e932bdf4..0873886c82 100644 --- a/src/main/java/net/glowstone/inventory/GlowInventorySlot.java +++ b/src/main/java/net/glowstone/inventory/GlowInventorySlot.java @@ -2,6 +2,8 @@ import java.util.Arrays; import java.util.List; +import lombok.Getter; +import lombok.Setter; import net.glowstone.constants.ItemIds; import net.glowstone.util.InventoryUtil; import org.bukkit.event.inventory.InventoryType.SlotType; @@ -12,6 +14,8 @@ public class GlowInventorySlot { private static final SlotType DEFAULT_TYPE = SlotType.CONTAINER; private ItemStack item; + @Getter + @Setter private SlotType type; public GlowInventorySlot() { @@ -59,12 +63,4 @@ public ItemStack getItem() { public void setItem(ItemStack item) { this.item = ItemIds.sanitize(item); } - - public SlotType getType() { - return type; - } - - public void setType(SlotType type) { - this.type = type; - } } diff --git a/src/main/java/net/glowstone/inventory/GlowInventoryView.java b/src/main/java/net/glowstone/inventory/GlowInventoryView.java index 9be687bd85..3ea37760fe 100644 --- a/src/main/java/net/glowstone/inventory/GlowInventoryView.java +++ b/src/main/java/net/glowstone/inventory/GlowInventoryView.java @@ -1,5 +1,7 @@ package net.glowstone.inventory; +import lombok.Data; +import lombok.RequiredArgsConstructor; import net.glowstone.entity.GlowHumanEntity; import org.bukkit.entity.HumanEntity; import org.bukkit.event.inventory.InventoryType; @@ -10,12 +12,31 @@ /** * Standard implementation of InventoryView for most inventories. */ +@Data +@RequiredArgsConstructor public class GlowInventoryView extends InventoryView { + /** + * The player. + */ private final HumanEntity player; + + /** + * The inventory type. + */ + // NB: by spec, getter ought to return CREATIVE instead of CRAFTING if player is in creative + // mode + // but this messes up the calculations in InventoryView which expect CRAFTING but also + // apply to CREATIVE. private final InventoryType type; - private final Inventory top; - private final Inventory bottom; + /** + * The inventory in the top half of the window. + */ + private final Inventory topInventory; + /** + * The inventory in the bottom half of the window. + */ + private final Inventory bottomInventory; /** * Create the default inventory view for this player. @@ -30,10 +51,10 @@ public GlowInventoryView(GlowHumanEntity player) { * Create an inventory view for this player looking at a given top inventory. * * @param player The player. - * @param top The top inventory. + * @param topInventory The top inventory. */ - public GlowInventoryView(HumanEntity player, Inventory top) { - this(player, top.getType(), top, player.getInventory()); + public GlowInventoryView(HumanEntity player, Inventory topInventory) { + this(player, topInventory.getType(), topInventory, player.getInventory()); } /** @@ -41,16 +62,10 @@ public GlowInventoryView(HumanEntity player, Inventory top) { * * @param player The player. * @param type The inventory type. - * @param top The top inventory. - * @param bottom The bottom inventory. + * @param topInventory The top inventory. + * @param bottomInventory The bottom inventory. */ - public GlowInventoryView(HumanEntity player, InventoryType type, Inventory top, - Inventory bottom) { - this.player = player; - this.type = type; - this.top = top; - this.bottom = bottom; - } + /** * Check if an inventory view is the player's default inventory view. @@ -60,8 +75,8 @@ public GlowInventoryView(HumanEntity player, InventoryType type, Inventory top, */ public static boolean isDefault(InventoryView view) { return view.getBottomInventory() instanceof GlowPlayerInventory - && view.getTopInventory() == ((GlowPlayerInventory) view.getBottomInventory()) - .getCraftingInventory(); + && view.getTopInventory() == ((GlowPlayerInventory) view.getBottomInventory()) + .getCraftingInventory(); } @Override @@ -91,28 +106,4 @@ private void checkSlot(int slot) { throw new IllegalArgumentException("Slot out of range [0," + size + "): " + slot); } } - - @Override - public Inventory getTopInventory() { - return top; - } - - @Override - public Inventory getBottomInventory() { - return bottom; - } - - @Override - public HumanEntity getPlayer() { - return player; - } - - @Override - public InventoryType getType() { - // NB: by spec, ought to return CREATIVE instead of CRAFTING if player is in creative mode - // but this messes up the calculations in InventoryView which expect CRAFTING but also - // apply to CREATIVE. - return type; - } - } diff --git a/src/main/java/net/glowstone/inventory/GlowMerchantInventory.java b/src/main/java/net/glowstone/inventory/GlowMerchantInventory.java new file mode 100644 index 0000000000..0a94c8a6b6 --- /dev/null +++ b/src/main/java/net/glowstone/inventory/GlowMerchantInventory.java @@ -0,0 +1,45 @@ +package net.glowstone.inventory; + +import static com.google.common.base.Preconditions.checkNotNull; + +import lombok.Getter; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.Merchant; +import org.bukkit.inventory.MerchantInventory; +import org.bukkit.inventory.MerchantRecipe; + +public class GlowMerchantInventory extends GlowInventory implements MerchantInventory { + + private static final int SLOT_INPUT_1 = 0; + private static final int SLOT_INPUT_2 = 1; + private static final int SLOT_RESULT = 2; + + @Getter + private Merchant merchant; + @Getter + private int selectedRecipeIndex; + + /** + * Creates the inventory for a merchant. + * + * @param owner the CUSTOMER as an {@link InventoryHolder} + * @param merchant the merchant as a {@link Merchant} + */ + public GlowMerchantInventory(InventoryHolder owner, Merchant merchant) { + super(owner, InventoryType.MERCHANT); + checkNotNull(merchant); + + this.merchant = merchant; + this.selectedRecipeIndex = 0; + + getSlot(SLOT_INPUT_1).setType(InventoryType.SlotType.CONTAINER); + getSlot(SLOT_INPUT_2).setType(InventoryType.SlotType.CONTAINER); + getSlot(SLOT_RESULT).setType(InventoryType.SlotType.RESULT); + } + + @Override + public MerchantRecipe getSelectedRecipe() { + return merchant.getRecipe(selectedRecipeIndex); + } +} diff --git a/src/main/java/net/glowstone/inventory/GlowMetaBook.java b/src/main/java/net/glowstone/inventory/GlowMetaBook.java index 7c16493b55..edef577556 100644 --- a/src/main/java/net/glowstone/inventory/GlowMetaBook.java +++ b/src/main/java/net/glowstone/inventory/GlowMetaBook.java @@ -5,6 +5,8 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import lombok.Getter; +import lombok.Setter; import net.glowstone.util.nbt.CompoundTag; import net.glowstone.util.nbt.TagType; import org.bukkit.Material; @@ -16,7 +18,10 @@ */ class GlowMetaBook extends GlowMetaItem implements BookMeta { + @Getter private String title; + @Getter + @Setter private String author; private List pages; private Integer generation; @@ -123,11 +128,6 @@ public boolean hasTitle() { return title != null && !title.isEmpty(); } - @Override - public String getTitle() { - return title; - } - @Override public boolean setTitle(String title) { if (title != null && title.length() > 16) { @@ -142,16 +142,6 @@ public boolean hasAuthor() { return author != null && !author.isEmpty(); } - @Override - public String getAuthor() { - return author; - } - - @Override - public void setAuthor(String author) { - this.author = author; - } - @Override public boolean hasGeneration() { return generation != null; diff --git a/src/main/java/net/glowstone/inventory/GlowMetaFirework.java b/src/main/java/net/glowstone/inventory/GlowMetaFirework.java index b1abfec36d..61f733f6e3 100644 --- a/src/main/java/net/glowstone/inventory/GlowMetaFirework.java +++ b/src/main/java/net/glowstone/inventory/GlowMetaFirework.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import lombok.Getter; import net.glowstone.util.nbt.CompoundTag; import org.bukkit.FireworkEffect; import org.bukkit.Material; @@ -19,6 +20,7 @@ public class GlowMetaFirework extends GlowMetaItem implements FireworkMeta { private List effects = new ArrayList<>(); + @Getter private int power; /** @@ -136,11 +138,6 @@ public boolean hasEffects() { return !effects.isEmpty(); } - @Override - public int getPower() { - return power; - } - @Override public void setPower(int power) { checkArgument(power >= 0 && power <= 128, "Power must be 0-128, inclusive"); diff --git a/src/main/java/net/glowstone/inventory/GlowMetaFireworkEffect.java b/src/main/java/net/glowstone/inventory/GlowMetaFireworkEffect.java index eebd672f8b..041ba3572a 100644 --- a/src/main/java/net/glowstone/inventory/GlowMetaFireworkEffect.java +++ b/src/main/java/net/glowstone/inventory/GlowMetaFireworkEffect.java @@ -5,6 +5,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import lombok.Getter; +import lombok.Setter; import net.glowstone.util.nbt.CompoundTag; import org.bukkit.Color; import org.bukkit.FireworkEffect; @@ -15,6 +17,8 @@ public class GlowMetaFireworkEffect extends GlowMetaItem implements FireworkEffectMeta { + @Getter + @Setter private FireworkEffect effect; /** @@ -137,14 +141,4 @@ public Map serialize() { public boolean hasEffect() { return effect != null; } - - @Override - public FireworkEffect getEffect() { - return effect; - } - - @Override - public void setEffect(FireworkEffect effect) { - this.effect = effect; - } } diff --git a/src/main/java/net/glowstone/inventory/GlowMetaItem.java b/src/main/java/net/glowstone/inventory/GlowMetaItem.java index 38a22de33f..dc7a362db4 100644 --- a/src/main/java/net/glowstone/inventory/GlowMetaItem.java +++ b/src/main/java/net/glowstone/inventory/GlowMetaItem.java @@ -10,6 +10,8 @@ import java.util.Map.Entry; import java.util.Set; import java.util.stream.Collectors; +import lombok.Getter; +import lombok.Setter; import net.glowstone.util.nbt.CompoundTag; import net.glowstone.util.nbt.TagType; import org.bukkit.Material; @@ -22,10 +24,14 @@ */ public class GlowMetaItem implements ItemMeta { + @Getter + @Setter private String displayName; private List lore; private Map enchants; private int hideFlag; + @Getter + @Setter private boolean unbreakable; /** @@ -218,16 +224,6 @@ public boolean hasDisplayName() { return !Strings.isNullOrEmpty(displayName); } - @Override - public String getDisplayName() { - return displayName; - } - - @Override - public void setDisplayName(String name) { - displayName = name; - } - // TODO: support localization @Override @@ -252,25 +248,17 @@ public boolean hasLore() { @Override public List getLore() { + // TODO: Defensive copy return lore; } @Override public void setLore(List lore) { // todo: fancy validation things + // TODO: Defensive copy this.lore = lore; } - @Override - public boolean isUnbreakable() { - return unbreakable; - } - - @Override - public void setUnbreakable(boolean unbreakable) { - this.unbreakable = unbreakable; - } - //////////////////////////////////////////////////////////////////////////// // Enchants diff --git a/src/main/java/net/glowstone/inventory/GlowMetaPotion.java b/src/main/java/net/glowstone/inventory/GlowMetaPotion.java index e394ed1ddd..5e8ab3ead6 100644 --- a/src/main/java/net/glowstone/inventory/GlowMetaPotion.java +++ b/src/main/java/net/glowstone/inventory/GlowMetaPotion.java @@ -51,7 +51,13 @@ public GlowMetaPotion(ItemMeta meta) { this.basePotionData = potion.getBasePotionData(); } - public static PotionEffect fromNBT(CompoundTag tag) { + /** + * Reads a {@link PotionEffect} from an NBT compound tag. + * + * @param tag a potion effect NBT compound tag + * @return {@code tag} as a {@link PotionEffect} + */ + public static PotionEffect fromNbt(CompoundTag tag) { PotionEffectType type = PotionEffectType.getById(tag.getByte("Id")); int duration = tag.getInt("Duration"); int amplifier = tag.getByte("Amplifier"); @@ -61,7 +67,13 @@ public static PotionEffect fromNBT(CompoundTag tag) { return new PotionEffect(type, duration, amplifier, ambient, particles); } - public static CompoundTag toNBT(PotionEffect effect) { + /** + * Converts a {@link PotionEffect} to an NBT compound tag. + * + * @param effect the potion effect + * @return {@code effect} as an NBT compound tag + */ + public static CompoundTag toNbt(PotionEffect effect) { CompoundTag tag = new CompoundTag(); tag.putByte("Id", effect.getType().getId()); @@ -101,7 +113,7 @@ void writeNbt(CompoundTag tag) { super.writeNbt(tag); if (hasCustomEffects()) { - List customEffects = effects.stream().map(GlowMetaPotion::toNBT) + List customEffects = effects.stream().map(GlowMetaPotion::toNbt) .collect(Collectors.toList()); tag.putCompoundList("CustomEffects", customEffects); } @@ -118,7 +130,7 @@ void readNbt(CompoundTag tag) { if (tag.isList("CustomEffects", TagType.COMPOUND)) { List customEffects = tag.getCompoundList("CustomEffects"); for (CompoundTag effect : customEffects) { - addCustomEffect(fromNBT(effect), true); + addCustomEffect(fromNbt(effect), true); } } if (tag.isString("Potion")) { @@ -214,7 +226,7 @@ public boolean hasColor() { } /** - * Converts the PotionData of this item meta to a Potion ID string + * Converts the PotionData of this item meta to a Potion ID string. * * @return the Potion ID string */ @@ -236,7 +248,8 @@ private String dataToString() { */ private PotionData dataFromString(String string) { PotionType type; - boolean extended = false, upgraded = false; + boolean extended = false; + boolean upgraded = false; if (string.startsWith("minecraft:")) { string = string.replace("minecraft:", ""); } @@ -271,7 +284,7 @@ enum PotionTypeTable { } /** - * Converts a Vanilla Potion ID to an equivalent Bukkit PotionType + * Converts a Vanilla Potion ID to an equivalent Bukkit PotionType. * * @param name the Vanilla Potion ID * @return the PotionType equivalent @@ -286,7 +299,7 @@ static PotionType fromName(String name) { } /** - * Converts a Bukkit PotionType to an equivalent Vanilla Potion ID + * Converts a Bukkit PotionType to an equivalent Vanilla Potion ID. * * @param type the Bukkit PotionType * @return the Vanilla Potion ID equivalent diff --git a/src/main/java/net/glowstone/inventory/GlowMetaSkull.java b/src/main/java/net/glowstone/inventory/GlowMetaSkull.java index 824e937dc3..9b195f6a43 100644 --- a/src/main/java/net/glowstone/inventory/GlowMetaSkull.java +++ b/src/main/java/net/glowstone/inventory/GlowMetaSkull.java @@ -38,7 +38,8 @@ public GlowMetaSkull(ItemMeta meta) { owner.set(((GlowMetaSkull) skull).owner.get()); } else { if (!setOwningPlayerInternal(skull.getOwningPlayer())) { - owner.set(UNKNOWN_PLAYER); // necessary to preserve the return value of hasOwner() + owner.set(UNKNOWN_PLAYER); + // necessary to preserve the return value of hasOwner() } } } @@ -86,7 +87,7 @@ public Map serialize() { void writeNbt(CompoundTag tag) { super.writeNbt(tag); if (hasOwner()) { - tag.putCompound("SkullOwner", owner.get().toNBT()); + tag.putCompound("SkullOwner", owner.get().toNbt()); } } @@ -97,7 +98,7 @@ void readNbt(CompoundTag tag) { if (tag.isString("SkullOwner")) { owner.set(PlayerProfile.getProfile(tag.getString("SkullOwner")).join()); } else if (tag.isCompound("SkullOwner")) { - owner.set(PlayerProfile.fromNBT(tag.getCompound("SkullOwner")).join()); + owner.set(PlayerProfile.fromNbt(tag.getCompound("SkullOwner")).join()); } } } @@ -133,7 +134,7 @@ public OfflinePlayer getOwningPlayer() { /** * {@inheritDoc} * - * When this returns false, it may still succeed asynchronously. + *

When this returns false, it may still succeed asynchronously. */ @Override public boolean setOwningPlayer(OfflinePlayer owningPlayer) { diff --git a/src/main/java/net/glowstone/inventory/GlowPlayerInventory.java b/src/main/java/net/glowstone/inventory/GlowPlayerInventory.java index 0369349865..5e1b0a575f 100644 --- a/src/main/java/net/glowstone/inventory/GlowPlayerInventory.java +++ b/src/main/java/net/glowstone/inventory/GlowPlayerInventory.java @@ -1,5 +1,6 @@ package net.glowstone.inventory; +import lombok.Getter; import net.glowstone.GlowServer; import net.glowstone.entity.GlowHumanEntity; import net.glowstone.entity.GlowPlayer; @@ -42,28 +43,40 @@ public class GlowPlayerInventory extends GlowInventory implements PlayerInventor /** * The crafting inventory. + * + * @return The GlowCraftingInventory attached to this player */ - private final GlowCraftingInventory crafting; + @Getter + private final GlowCraftingInventory craftingInventory; /** - * Tracker for inventory drags. + * Tracker for inventory drags by this player. + * + * @return The DragTracker. */ - private final DragTracker tracker = new DragTracker(); + @Getter + private final DragTracker dragTracker = new DragTracker(); /** * The current held item slot. */ - private int heldSlot; + @Getter + private int heldItemSlot; /** * The human entity for this inventory, stored for location. */ private GlowHumanEntity owner; + /** + * Creates the instance for the given player's inventory. + * + * @param owner the player who owns this inventory + */ public GlowPlayerInventory(GlowHumanEntity owner) { // all player inventories are ID 0 // 36 = 4 rows of 9 // + 4 = armor, completed inventory // + 1 = off hand slot super(owner, InventoryType.PLAYER, SIZE); - crafting = new GlowCraftingInventory(owner, InventoryType.CRAFTING); + craftingInventory = new GlowCraftingInventory(owner, InventoryType.CRAFTING); this.owner = owner; for (int i = 0; i <= 8; i++) { getSlot(i).setType(SlotType.QUICKBAR); @@ -82,19 +95,15 @@ public static boolean canEquipInHelmetSlot(Material material) { } /** - * Get the crafting inventory. + * Sets which hotbar slot is the main-hand item. * - * @return The GlowCraftingInventory attached to this player + * @param slot the slot number, starting with 0 (1 less than the default keyboard shortcut) */ - public GlowCraftingInventory getCraftingInventory() { - return crafting; - } - public void setRawHeldItemSlot(int slot) { if (slot < 0 || slot > 8) { throw new IllegalArgumentException(slot + " not in range 0..8"); } - heldSlot = slot; + heldItemSlot = slot; setItemInMainHand(getItemInMainHand()); // send to player again just in case } @@ -138,10 +147,12 @@ public void handleShiftClick(GlowPlayer player, InventoryView view, int clickedS if (top.getType().equals(InventoryType.FURNACE)) { CraftingManager cm = ((GlowServer) Bukkit.getServer()).getCraftingManager(); if (cm.getFurnaceRecipe(clickedItem) != null) { - // move items are be burnable to the input slot TODO: Use of variable (INPUT_SLOT) instead of hard coded value ? + // move items are be burnable to the input slot + // TODO: Use of variable (INPUT_SLOT) instead of hard coded value ? clickedItem = top.tryToFillSlots(clickedItem, 0, -1); } else if (cm.isFuel(clickedItem.getType())) { - // move fuel items direct to fuel slot TODO: Use of variable (FUEL_SLOT) instead of hard coded value ? + // move fuel items direct to fuel slot + // TODO: Use of variable (FUEL_SLOT) instead of hard coded value ? clickedItem = top.tryToFillSlots(clickedItem, 1, -1); } else { // switch them between hotbar and main inventory depending on where they are now @@ -174,15 +185,6 @@ public void handleShiftClick(GlowPlayer player, InventoryView view, int clickedS //////////////////////////////////////////////////////////////////////////// // Overrides - /** - * Get the DragTracker associated with this player. - * - * @return The DragTracker. - */ - public DragTracker getDragTracker() { - return tracker; - } - @Override public HumanEntity getHolder() { return (HumanEntity) super.getHolder(); @@ -229,6 +231,9 @@ public void setItem(EquipmentSlot slot, ItemStack item) { case HEAD: setHelmet(item); break; + default: + // TODO: should this raise a warning? + // do nothing } } @@ -329,12 +334,12 @@ public void setBoots(ItemStack boots) { @Override public ItemStack getItemInMainHand() { - return getItem(heldSlot).clone(); + return getItem(heldItemSlot).clone(); } @Override public void setItemInMainHand(ItemStack item) { - setItem(heldSlot, item); + setItem(heldItemSlot, item); } @Override @@ -359,11 +364,6 @@ public void setItemInHand(ItemStack item) { setItemInMainHand(item); } - @Override - public int getHeldItemSlot() { - return heldSlot; - } - @Override public void setHeldItemSlot(int slot) { setRawHeldItemSlot(slot); @@ -378,7 +378,17 @@ public Location getLocation() { return owner.getLocation(); } + /** + * Remove all matching items from the inventory. + * + * @param type the item to remove, or null to remove everything + * @param data the data value to match on, or null to match all data values + * @return the number of items (not stacks) removed + */ public int clear(Material type, MaterialData data) { + if (type == Material.AIR) { + return 0; + } int numCleared = 0; for (int i = 0; i < getSize(); ++i) { ItemStack stack = getItem(i); diff --git a/src/main/java/net/glowstone/inventory/GlowSuperInventory.java b/src/main/java/net/glowstone/inventory/GlowSuperInventory.java index 1757666546..2a7ef16206 100644 --- a/src/main/java/net/glowstone/inventory/GlowSuperInventory.java +++ b/src/main/java/net/glowstone/inventory/GlowSuperInventory.java @@ -58,6 +58,7 @@ protected void initialize(List parents, InventoryHolder owner, } public List getParents() { + // TODO: Replace with a facade return parents; } } diff --git a/src/main/java/net/glowstone/inventory/InventoryMonitor.java b/src/main/java/net/glowstone/inventory/InventoryMonitor.java index 1dec931dfb..7a591118d6 100644 --- a/src/main/java/net/glowstone/inventory/InventoryMonitor.java +++ b/src/main/java/net/glowstone/inventory/InventoryMonitor.java @@ -3,6 +3,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Objects; +import lombok.Getter; import net.glowstone.constants.ItemIds; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryView; @@ -17,7 +18,27 @@ public final class InventoryMonitor { private final InventoryView view; private final ItemStack[] slots; - private final int size, id; + /** + * Get the number of slots in this inventory view. + * + * @return The number of slots. + */ + @Getter + private final int size; + /** + * The network ID of this inventory view. + * + * @return The id. + */ + @Getter + private final int id; + + /** + * Get the network type ID of this inventory view. + * + * @return The type id. + */ + @Getter private final String type; /** @@ -26,7 +47,6 @@ public final class InventoryMonitor { * @param view The view to monitor. */ public InventoryMonitor(InventoryView view) { - boolean isDefault = GlowInventoryView.isDefault(view); this.view = view; if (view.getTopInventory().getType() != InventoryType.CRAFTING && view.getBottomInventory().getType() == InventoryType.PLAYER) { @@ -38,7 +58,7 @@ public InventoryMonitor(InventoryView view) { slots = new ItemStack[size]; // determine id and type id - if (isDefault) { + if (GlowInventoryView.isDefault(view)) { id = 0; } else { id = nextId; @@ -123,36 +143,10 @@ public List getChanges() { * @return The contents. */ public ItemStack[] getContents() { + // TODO: Defensive deep copy return slots; } - /** - * Get the number of slots in this inventory view. - * - * @return The number of slots. - */ - public int getSize() { - return size; - } - - /** - * Get the network ID of this inventory view. - * - * @return The id. - */ - public int getId() { - return id; - } - - /** - * Get the network type ID of this inventory view. - * - * @return The type id. - */ - public String getType() { - return type; - } - /** * An entry which has been changed. */ diff --git a/src/main/java/net/glowstone/inventory/WindowClickLogic.java b/src/main/java/net/glowstone/inventory/WindowClickLogic.java index fa214b11f3..729560b545 100644 --- a/src/main/java/net/glowstone/inventory/WindowClickLogic.java +++ b/src/main/java/net/glowstone/inventory/WindowClickLogic.java @@ -15,7 +15,8 @@ private WindowClickLogic() { } /** - * Determine the ClickType of a window click message based on the raw mode, button, and slot values if possible. + * Determine the ClickType of a window click message based on the raw mode, button, and slot + * values if possible. * * @param mode The raw mode number. * @param button The raw button number. @@ -75,18 +76,20 @@ public static ClickType getClickType(int mode, int button, int slot) { return ClickType.CONTROL_DROP; } break; - case 5: // drag + // TODO: implement this? break; - case 6: return ClickType.DOUBLE_CLICK; + default: + return ClickType.UNKNOWN; } return ClickType.UNKNOWN; } /** - * Determine the InventoryAction to be performed for a window click based on the click type, slot type, and items involved. + * Determine the InventoryAction to be performed for a window click based on the click type, + * slot type, and items involved. * * @param clickType The click type. * @param slot The slot clicked. @@ -95,11 +98,12 @@ public static ClickType getClickType(int mode, int button, int slot) { * @return The InventoryAction to perform, or UNKNOWN. */ public static InventoryAction getAction(ClickType clickType, SlotType slot, ItemStack cursor, - ItemStack slotItem) { + ItemStack slotItem) { boolean outside = slot == SlotType.OUTSIDE; switch (clickType) { case LEFT: - // "SWAP_WITH_CURSOR", "PLACE_ONE", "DROP_ALL_CURSOR", "PLACE_ALL", "PLACE_SOME", "NOTHING", "PICKUP_ALL" + // "SWAP_WITH_CURSOR", "PLACE_ONE", "DROP_ALL_CURSOR", "PLACE_ALL", "PLACE_SOME", + // "NOTHING", "PICKUP_ALL" if (InventoryUtil.isEmpty(cursor)) { if (outside || InventoryUtil.isEmpty(slotItem)) { return InventoryAction.NOTHING; @@ -121,7 +125,7 @@ public static InventoryAction getAction(ClickType clickType, SlotType slot, Item if (slotItem.isSimilar(cursor)) { int transfer = Math.min(cursor.getAmount(), - slotItem.getType().getMaxStackSize() - slotItem.getAmount()); + slotItem.getType().getMaxStackSize() - slotItem.getAmount()); if (transfer == 0) { return InventoryAction.NOTHING; } else if (transfer == 1) { @@ -226,8 +230,9 @@ public static boolean isPlaceAction(InventoryAction action) { case PLACE_ALL: case PLACE_SOME: return true; + default: + return false; } - return false; } /** @@ -243,7 +248,8 @@ public static boolean isPickupAction(InventoryAction action) { case PICKUP_ONE: case PICKUP_SOME: return true; + default: + return false; } - return false; } } diff --git a/src/main/java/net/glowstone/inventory/crafting/DynamicRecipe.java b/src/main/java/net/glowstone/inventory/crafting/DynamicRecipe.java index 99d77f3073..6195eb3f02 100644 --- a/src/main/java/net/glowstone/inventory/crafting/DynamicRecipe.java +++ b/src/main/java/net/glowstone/inventory/crafting/DynamicRecipe.java @@ -1,6 +1,7 @@ package net.glowstone.inventory.crafting; import com.google.common.base.Preconditions; +import lombok.Getter; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; @@ -14,6 +15,12 @@ public class DynamicRecipe implements Recipe { private ItemMatcher matcher; + /** + * Gets the result of this recipe, given the input of {@link #matches(ItemStack[])}. + * + * @return The result of the recipe, or null if it does not match + */ + @Getter private ItemStack result; public DynamicRecipe() { @@ -45,14 +52,4 @@ public boolean matches(ItemStack[] matrix) { result = matcher.getResult(matrix); return result != null; } - - /** - * Gets the result of this recipe, given the input of {@link #matches(ItemStack[])}. - * - * @return The result of the recipe, or null if it does not match - */ - @Override - public ItemStack getResult() { - return result; - } } diff --git a/src/main/java/net/glowstone/inventory/crafting/GlowBannerMatcher.java b/src/main/java/net/glowstone/inventory/crafting/GlowBannerMatcher.java index 58f0596402..4303995105 100644 --- a/src/main/java/net/glowstone/inventory/crafting/GlowBannerMatcher.java +++ b/src/main/java/net/glowstone/inventory/crafting/GlowBannerMatcher.java @@ -1,6 +1,7 @@ package net.glowstone.inventory.crafting; import java.util.List; +import lombok.Getter; import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.block.banner.Pattern; @@ -156,9 +157,11 @@ private enum LayerRecipe { TRIANGLE_TOP("# #", " # ", " "), TRIANGLE_TOP_LEFT("## ", "# ", " "), TRIANGLE_TOP_RIGHT(" ##", " #", " "); - + @Getter char[] values; - Material item; + @Getter + Material type; + @Getter short data; LayerRecipe(String... rows) { @@ -172,28 +175,16 @@ private enum LayerRecipe { } LayerRecipe(Material item) { - this.item = item; + this.type = item; } LayerRecipe(Material item, short data) { - this.item = item; + this.type = item; this.data = data; } - public char[] getValues() { - return values; - } - public boolean hasItem() { - return item != null; - } - - public Material getType() { - return item; - } - - public short getData() { - return data; + return type != null; } public Pattern getPattern() { diff --git a/src/main/java/net/glowstone/inventory/crafting/PlayerRecipeMonitor.java b/src/main/java/net/glowstone/inventory/crafting/PlayerRecipeMonitor.java index 631b040422..6a6541bad7 100644 --- a/src/main/java/net/glowstone/inventory/crafting/PlayerRecipeMonitor.java +++ b/src/main/java/net/glowstone/inventory/crafting/PlayerRecipeMonitor.java @@ -13,10 +13,16 @@ public final class PlayerRecipeMonitor { private final GlowPlayer player; - private final Set recipes, toBeDisplayed; + private final Set recipes; + private final Set toBeDisplayed; private boolean bookOpen; private boolean filterCraftable; + /** + * Creates an instance associated with the given player and with an empty recipe book. + * + * @param player the player + */ public PlayerRecipeMonitor(GlowPlayer player) { this.player = player; this.bookOpen = false; @@ -25,6 +31,11 @@ public PlayerRecipeMonitor(GlowPlayer player) { this.toBeDisplayed = new HashSet<>(); } + /** + * Creates a message to send this recipe book's state to the client. + * + * @return an {@link UnlockRecipesMessage} containing this recipe book's state + */ public UnlockRecipesMessage createInitMessage() { int status = UnlockRecipesMessage.ACTION_INIT; int[] recipeIds = new int[0]; // todo: conversion to internal IDs @@ -33,6 +44,11 @@ public UnlockRecipesMessage createInitMessage() { recipeIds); } + /** + * Restores state from an NBT tag. + * + * @param playerData an NBT tag containing a compound subtag named recipeBook + */ public void read(CompoundTag playerData) { if (!playerData.isCompound("recipeBook")) { return; @@ -52,6 +68,11 @@ public void read(CompoundTag playerData) { } } + /** + * Populates a recipeBook compound subtag and adds it to the given tag. + * + * @param playerData a compound tag describing the player + */ public void write(CompoundTag playerData) { CompoundTag recipeBook = new CompoundTag(); recipeBook.putBool("isFilteringCraftable", filterCraftable); diff --git a/src/main/java/net/glowstone/io/PlayerDataService.java b/src/main/java/net/glowstone/io/PlayerDataService.java index 4991ef8c45..1d911c4122 100644 --- a/src/main/java/net/glowstone/io/PlayerDataService.java +++ b/src/main/java/net/glowstone/io/PlayerDataService.java @@ -15,7 +15,8 @@ public interface PlayerDataService { /** * Begin reading player data for online or offline player loading. * - *

Some attributes may be read before or without constructing a player entity, see {@link PlayerReader} for more information. + *

Some attributes may be read before or without constructing a player entity, see {@link + * PlayerReader} for more information. * *

When finished with the PlayerReader, {@link PlayerReader#close()} should be called. * @@ -41,23 +42,27 @@ public interface PlayerDataService { /** * Get a collection of all known offline players. * - *

Currently online players may or may not be included, but if they are, they will be included in OfflinePlayer form. + *

Currently online players may or may not be included, but if they are, they will be + * included in OfflinePlayer form. * * @return All known offline players. */ CompletableFuture> getOfflinePlayers(); /** - * A piecewise reader for initializing new players. See {@link PlayerDataService#beginReadingData}. + * A piecewise reader for initializing new players. See + * {@link PlayerDataService#beginReadingData}. */ interface PlayerReader extends AutoCloseable { /** * Check whether the player has played before. * - *

If the player has not played before, most of the rest of the fields will have their default values. + *

If the player has not played before, most of the rest of the fields will have their + * default values. * - *

If the player has played before, some fields may still not have meaningful values, depending on the data. + *

If the player has played before, some fields may still not have meaningful values, + * depending on the data. * * @return True if the player has played before. */ diff --git a/src/main/java/net/glowstone/io/WorldMetadataService.java b/src/main/java/net/glowstone/io/WorldMetadataService.java index 7a4fd619fa..f5156ff382 100644 --- a/src/main/java/net/glowstone/io/WorldMetadataService.java +++ b/src/main/java/net/glowstone/io/WorldMetadataService.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.util.UUID; +import lombok.Data; /** * Provider of I/O for world metadata. @@ -9,7 +10,8 @@ public interface WorldMetadataService { /** - * Reads the world's metadata from storage, including final values such as seed and UUID that are only set on first load. + * Reads the world's metadata from storage, including final values such as seed and UUID that + * are only set on first load. * * @return A {@link WorldFinalValues} with the seed and UUID. */ @@ -23,24 +25,12 @@ public interface WorldMetadataService { void writeWorldData() throws IOException; /** - * A structure representing properties stored about a world that cannot be changed after its initialization, namely seed and UUID. + * A structure representing properties stored about a world that cannot be changed after its + * initialization, namely seed and UUID. */ + @Data class WorldFinalValues { - private final long seed; private final UUID uuid; - - public WorldFinalValues(long seed, UUID uuid) { - this.seed = seed; - this.uuid = uuid; - } - - public long getSeed() { - return seed; - } - - public UUID getUuid() { - return uuid; - } } } diff --git a/src/main/java/net/glowstone/io/WorldStorageProvider.java b/src/main/java/net/glowstone/io/WorldStorageProvider.java index 5dd9df1503..0c514c9fd3 100644 --- a/src/main/java/net/glowstone/io/WorldStorageProvider.java +++ b/src/main/java/net/glowstone/io/WorldStorageProvider.java @@ -23,49 +23,56 @@ public interface WorldStorageProvider { File getFolder(); /** - * Gets the {@link ChunkIoService} for this world, to be used for reading and writing chunk data. + * Gets the {@link ChunkIoService} for this world, to be used for reading and writing chunk + * data. * * @return The {@link ChunkIoService}. */ ChunkIoService getChunkIoService(); /** - * Gets the {@link WorldMetadataService} for this world, to be used for reading and writing world metadata (seed, time, so on). + * Gets the {@link WorldMetadataService} for this world, to be used for reading and writing + * world metadata (seed, time, so on). * * @return The {@link WorldMetadataService}. */ WorldMetadataService getMetadataService(); /** - * Gets the {@link PlayerDataService} for this world, to be used for reading and writing data for online and offline players. + * Gets the {@link PlayerDataService} for this world, to be used for reading and writing data + * for online and offline players. * * @return The {@link PlayerDataService}. */ PlayerDataService getPlayerDataService(); /** - * Gets the {@link StructureDataService} for this world, to be used for reading and writing data for structures. + * Gets the {@link StructureDataService} for this world, to be used for reading and writing data + * for structures. * * @return The {@link StructureDataService}. */ StructureDataService getStructureDataService(); /** - * Gets the {@link ScoreboardIoService} for this world, to be used for reading and writing data for scoreboards. + * Gets the {@link ScoreboardIoService} for this world, to be used for reading and writing data + * for scoreboards. * * @return The {@link ScoreboardIoService}. */ ScoreboardIoService getScoreboardIoService(); /** - * Gets the {@link PlayerStatisticIoService} for this world, to be used for reading and writing player statistics. + * Gets the {@link PlayerStatisticIoService} for this world, to be used for reading and writing + * player statistics. * * @return The {@link PlayerStatisticIoService}. */ PlayerStatisticIoService getPlayerStatisticIoService(); /** - * Gets the {@link FunctionIoService} for this world, to be used for reading and writing functions. + * Gets the {@link FunctionIoService} for this world, to be used for reading and writing + * functions. * * @return The {@link FunctionIoService}. */ diff --git a/src/main/java/net/glowstone/io/anvil/AnvilChunkIoService.java b/src/main/java/net/glowstone/io/anvil/AnvilChunkIoService.java index a077480cf9..df0bfbc67e 100644 --- a/src/main/java/net/glowstone/io/anvil/AnvilChunkIoService.java +++ b/src/main/java/net/glowstone/io/anvil/AnvilChunkIoService.java @@ -19,8 +19,8 @@ import net.glowstone.io.ChunkIoService; import net.glowstone.io.entity.EntityStorage; import net.glowstone.util.nbt.CompoundTag; -import net.glowstone.util.nbt.NBTInputStream; -import net.glowstone.util.nbt.NBTOutputStream; +import net.glowstone.util.nbt.NbtInputStream; +import net.glowstone.util.nbt.NbtOutputStream; import net.glowstone.util.nbt.TagType; import org.bukkit.Chunk; import org.bukkit.Location; @@ -62,7 +62,7 @@ public boolean read(GlowChunk chunk) throws IOException { DataInputStream in = region.getChunkDataInputStream(regionX, regionZ); CompoundTag levelTag; - try (NBTInputStream nbt = new NBTInputStream(in, false)) { + try (NbtInputStream nbt = new NbtInputStream(in, false)) { CompoundTag root = nbt.readCompound(); levelTag = root.getCompound("Level"); } @@ -269,7 +269,7 @@ public void write(GlowChunk chunk) throws IOException { CompoundTag levelOut = new CompoundTag(); levelOut.putCompound("Level", levelTags); - try (NBTOutputStream nbt = new NBTOutputStream( + try (NbtOutputStream nbt = new NbtOutputStream( region.getChunkDataOutputStream(regionX, regionZ), false)) { nbt.writeTag(levelOut); } diff --git a/src/main/java/net/glowstone/io/anvil/AnvilWorldStorageProvider.java b/src/main/java/net/glowstone/io/anvil/AnvilWorldStorageProvider.java index 78c428f77c..5561728c7c 100644 --- a/src/main/java/net/glowstone/io/anvil/AnvilWorldStorageProvider.java +++ b/src/main/java/net/glowstone/io/anvil/AnvilWorldStorageProvider.java @@ -1,14 +1,12 @@ package net.glowstone.io.anvil; import java.io.File; +import lombok.Getter; import net.glowstone.GlowWorld; -import net.glowstone.io.ChunkIoService; import net.glowstone.io.FunctionIoService; import net.glowstone.io.PlayerDataService; -import net.glowstone.io.PlayerStatisticIoService; import net.glowstone.io.ScoreboardIoService; import net.glowstone.io.StructureDataService; -import net.glowstone.io.WorldMetadataService; import net.glowstone.io.WorldStorageProvider; import net.glowstone.io.data.WorldFunctionIoService; import net.glowstone.io.json.JsonPlayerStatisticIoService; @@ -22,24 +20,35 @@ */ public class AnvilWorldStorageProvider implements WorldStorageProvider { - private final File dir; + @Getter + private final File folder; private final File dataDir; private GlowWorld world; - private AnvilChunkIoService service; - private NbtWorldMetadataService meta; - private StructureDataService structures; - private PlayerDataService players; - private ScoreboardIoService scoreboard; - private JsonPlayerStatisticIoService statistics; - private FunctionIoService functions; + @Getter + private AnvilChunkIoService chunkIoService; + @Getter + private NbtWorldMetadataService metadataService; + @Getter + private StructureDataService structureDataService; + @Getter(lazy = true) + private final PlayerDataService playerDataService + = new NbtPlayerDataService(world.getServer(), new File(folder, "playerdata")); + @Getter(lazy = true) + private final ScoreboardIoService scoreboardIoService + = new NbtScoreboardIoService(world.getServer(), new File(folder, "data")); + @Getter(lazy = true) + private final JsonPlayerStatisticIoService playerStatisticIoService + = new JsonPlayerStatisticIoService(world.getServer(), new File(folder, "stats")); + @Getter(lazy = true) + private final FunctionIoService functionIoService = new WorldFunctionIoService(world, dataDir); /** * Create an instance for the given root folder. - * @param dir the root folder + * @param folder the root folder */ - public AnvilWorldStorageProvider(File dir) { - this.dir = dir; - this.dataDir = new File(dir, "data"); + public AnvilWorldStorageProvider(File folder) { + this.folder = folder; + this.dataDir = new File(folder, "data"); this.dataDir.mkdirs(); } @@ -49,63 +58,9 @@ public void setWorld(GlowWorld world) { throw new IllegalArgumentException("World is already set"); } this.world = world; - service = new AnvilChunkIoService(dir); - meta = new NbtWorldMetadataService(world, dir); + chunkIoService = new AnvilChunkIoService(folder); + metadataService = new NbtWorldMetadataService(world, folder); dataDir.mkdirs(); - structures = new NbtStructureDataService(world, dataDir); - functions = new WorldFunctionIoService(world, dataDir); - } - - @Override - public File getFolder() { - return dir; - } - - @Override - public ChunkIoService getChunkIoService() { - return service; - } - - @Override - public WorldMetadataService getMetadataService() { - return meta; - } - - @Override - public StructureDataService getStructureDataService() { - return structures; - } - - @Override - public PlayerDataService getPlayerDataService() { - if (players == null) { - players = new NbtPlayerDataService(world.getServer(), new File(dir, "playerdata")); - } - return players; - } - - @Override - public ScoreboardIoService getScoreboardIoService() { - if (scoreboard == null) { - scoreboard = new NbtScoreboardIoService(world.getServer(), new File(dir, "data")); - } - return scoreboard; - } - - @Override - public PlayerStatisticIoService getPlayerStatisticIoService() { - if (statistics == null) { - statistics = new JsonPlayerStatisticIoService( - world.getServer(), new File(dir, "stats")); - } - return statistics; - } - - @Override - public FunctionIoService getFunctionIoService() { - if (functions == null) { - functions = new WorldFunctionIoService(world, dataDir); - } - return functions; + structureDataService = new NbtStructureDataService(world, dataDir); } } diff --git a/src/main/java/net/glowstone/io/anvil/RegionFile.java b/src/main/java/net/glowstone/io/anvil/RegionFile.java index 6a062d65f9..3f7684a572 100644 --- a/src/main/java/net/glowstone/io/anvil/RegionFile.java +++ b/src/main/java/net/glowstone/io/anvil/RegionFile.java @@ -38,12 +38,14 @@ import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.util.BitSet; +import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; import java.util.zip.ZipException; +import lombok.Getter; import net.glowstone.GlowServer; import net.glowstone.util.config.ServerConfig.Key; import org.bukkit.Bukkit; @@ -51,40 +53,39 @@ /** * Interfaces with region files on the disk * - * Region File Format + *

Region File Format * - *

Concept: The minimum unit of storage on hard drives is 4KB. 90% of Minecraft - * chunks are smaller than 4KB. 99% are smaller than 8KB. Write a simple - * container to store chunks in single files in runs of 4KB sectors. + *

Concept: The minimum unit of storage on hard drives is 4KB. 90% of Minecraft chunks are + * smaller than 4KB. 99% are smaller than 8KB. Write a simple container to store chunks in single + * files in runs of 4KB sectors. * - *

Each region file represents a 32x32 group of chunks. The conversion from - * chunk number to region number is floor(coord / 32): a chunk at (30, -3) - * would be in region (0, -1), and one at (70, -30) would be at (3, -1). - * Region files are named "r.x.z.data", where x and z are the region coordinates. + *

Each region file represents a 32x32 group of chunks. The conversion from chunk number to + * region number is floor(coord / 32): a chunk at (30, -3) would be in region (0, -1), and one at + * (70, -30) would be at (3, -1). Region files are named "r.x.z.data", where x and z are the region + * coordinates. * - *

A region file begins with a 4KB header that describes where chunks are stored - * in the file. A 4-byte big-endian integer represents sector offsets and sector - * counts. The chunk offset for a chunk (x, z) begins at byte 4*(x+z*32) in the - * file. The bottom byte of the chunk offset indicates the number of sectors the - * chunk takes up, and the top 3 bytes represent the sector number of the chunk. - * Given a chunk offset o, the chunk data begins at byte 4096*(o/256) and takes up - * at most 4096*(o%256) bytes. A chunk cannot exceed 1MB in size. If a chunk - * offset is 0, the corresponding chunk is not stored in the region file. + *

A region file begins with a 4KB header that describes where chunks are stored in the file. A + * 4-byte big-endian integer represents sector offsets and sector counts. The chunk offset for a + * chunk (x, z) begins at byte 4*(x+z*32) in the file. The bottom byte of the chunk offset indicates + * the number of sectors the chunk takes up, and the top 3 bytes represent the sector number of the + * chunk. Given a chunk offset o, the chunk data begins at byte 4096*(o/256) and takes up at most + * 4096*(o%256) bytes. A chunk cannot exceed 1MB in size. If a chunk offset is 0, the corresponding + * chunk is not stored in the region file. * - *

Chunk data begins with a 4-byte big-endian integer representing the chunk data - * length in bytes, not counting the length field. The length must be smaller than - * 4096 times the number of sectors. The next byte is a version field, to allow - * backwards-compatible updates to how chunks are encoded. + *

Chunk data begins with a 4-byte big-endian integer representing the chunk data length in + * bytes, not counting the length field. The length must be smaller than 4096 times the number of + * sectors. The next byte is a version field, to allow backwards-compatible updates to how chunks + * are encoded. * - *

A version of 1 represents a gzipped NBT file. - * The gzipped data is the chunk length - 1. + *

A version of 1 represents a gzipped NBT file. The gzipped data is the chunk length - 1. * - *

A version of 2 represents a deflated (zlib compressed) NBT file. - * The deflated data is the chunk length - 1. + *

A version of 2 represents a deflated (zlib compressed) NBT file. The deflated data is the + * chunk length - 1. */ public class RegionFile { - private static final boolean COMPRESSION_ENABLED = ((GlowServer) Bukkit.getServer()).getConfig().getBoolean(Key.REGION_COMPRESSION); + private static final boolean COMPRESSION_ENABLED = ((GlowServer) Bukkit.getServer()).getConfig() + .getBoolean(Key.REGION_COMPRESSION); private static final byte VERSION_GZIP = 1; private static final byte VERSION_DEFLATE = 2; @@ -100,14 +101,28 @@ public class RegionFile { private RandomAccessFile file; private BitSet sectorsUsed; private int totalSectors; - private int sizeDelta; + private final AtomicInteger sizeDelta = new AtomicInteger(); + /** + * Returns the modification timestamp of the region file when it was first opened by this + * instance, or zero if this instance created the file. The timestamp is in milliseconds since + * the Unix epoch (see {@link File#lastModified}). + * + * @return the modification timestamp + */ + @Getter private long lastModified; + /** + * Opens a region file for reading and writing, creating it if it doesn't exist. + * + * @param path the file path; must be in an existing folder + * @throws IOException if the file cannot be opened + */ public RegionFile(File path) throws IOException { offsets = new int[SECTOR_INTS]; chunkTimestamps = new int[SECTOR_INTS]; - sizeDelta = 0; + sizeDelta.set(0); if (path.exists()) { lastModified = path.lastModified(); @@ -122,28 +137,29 @@ public RegionFile(File path) throws IOException { // fast path for new or region files under 4K file.write(emptySector); file.write(emptySector); - sizeDelta = 2 * SECTOR_BYTES; + sizeDelta.set(2 * SECTOR_BYTES); } else { // seek to the end to prepare for grows file.seek(initialLength); if (initialLength < 2 * SECTOR_BYTES) { // if the file size is under 8KB, grow it - sizeDelta = 2 * SECTOR_BYTES - initialLength; + sizeDelta.set(2 * SECTOR_BYTES - initialLength); GlowServer.logger.warning( - "Region \"" + path + "\" under 8K: " + initialLength + " increasing by " + ( - 2 * SECTOR_BYTES - initialLength)); + "Region \"" + path + "\" under 8K: " + initialLength + " increasing by " + ( + 2 * SECTOR_BYTES - initialLength)); - for (long i = 0; i < sizeDelta; ++i) { + for (long i = 0; i < sizeDelta.get(); ++i) { file.write(0); } } else if ((initialLength & (SECTOR_BYTES - 1)) != 0) { // if the file size is not a multiple of 4KB, grow it - sizeDelta = initialLength & (SECTOR_BYTES - 1); + sizeDelta.set(initialLength & (SECTOR_BYTES - 1)); GlowServer.logger.warning( - "Region \"" + path + "\" not aligned: " + initialLength + " increasing by " + ( - SECTOR_BYTES - (initialLength & (SECTOR_BYTES - 1)))); + "Region \"" + path + "\" not aligned: " + initialLength + " increasing by " + + ( + SECTOR_BYTES - (initialLength & (SECTOR_BYTES - 1)))); - for (long i = 0; i < sizeDelta; ++i) { + for (long i = 0; i < sizeDelta.get(); ++i) { file.write(0); } } @@ -182,8 +198,9 @@ public RegionFile(File path) throws IOException { } } else if (offset != 0) { GlowServer.logger.warning( - "Region \"" + path + "\": offsets[" + i + "] = " + offset + " -> " + startSector - + "," + numSectors + " does not fit"); + "Region \"" + path + "\": offsets[" + i + "] = " + offset + " -> " + + startSector + + "," + numSectors + " does not fit"); } } // read timestamps from timestamp table @@ -192,21 +209,23 @@ public RegionFile(File path) throws IOException { } } - /* the modification date of the region file when it was first opened */ - public long getLastModified() { - return lastModified; - } - - /* gets how much the region file has grown since it was last checked */ + /** + * Returns how much the region file has grown since this function was last called. + * + * @return the growth in bytes + */ public int getSizeDelta() { - int ret = sizeDelta; - sizeDelta = 0; - return ret; + return sizeDelta.getAndSet(0); } - /* - * gets an (uncompressed) stream representing the chunk data returns null if - * the chunk is not found or an error occurs + /** + * Gets an (uncompressed) stream representing the chunk data. Returns null if the chunk is not + * found or an error occurs. + * + * @param x the chunk X coordinate relative to the region + * @param z the chunk Z coordinate relative to the region + * @return an input stream with the chunk data, or null if the chunk is missing + * @throws IOException if the file cannot be read, or the chunk is invalid */ public DataInputStream getChunkDataInputStream(int x, int z) throws IOException { checkBounds(x, z); @@ -221,7 +240,7 @@ public DataInputStream getChunkDataInputStream(int x, int z) throws IOException int numSectors = offset & 0xFF; if (sectorNumber + numSectors > totalSectors) { throw new IOException( - "Invalid sector: " + sectorNumber + "+" + numSectors + " > " + totalSectors); + "Invalid sector: " + sectorNumber + "+" + numSectors + " > " + totalSectors); } file.seek(sectorNumber * SECTOR_BYTES); @@ -238,7 +257,7 @@ public DataInputStream getChunkDataInputStream(int x, int z) throws IOException file.read(data); try { return new DataInputStream(new BufferedInputStream( - new GZIPInputStream(new ByteArrayInputStream(data), 2048))); + new GZIPInputStream(new ByteArrayInputStream(data), 2048))); } catch (ZipException e) { if (e.getMessage().equals("Not in GZIP format")) { GlowServer.logger.info("Incorrect region version, switching to zlib..."); @@ -257,12 +276,22 @@ public DataInputStream getChunkDataInputStream(int x, int z) throws IOException } private DataInputStream getZlibInputStream(byte[] data) { - return new DataInputStream(new BufferedInputStream(new InflaterInputStream(new ByteArrayInputStream(data), new Inflater(), 2048))); + return new DataInputStream(new BufferedInputStream(new InflaterInputStream( + new ByteArrayInputStream(data), new Inflater(), 2048))); } + /** + * Creates a {@link DataOutputStream} to write a chunk to a byte. + * + * @param x the chunk X coordinate within the region + * @param z the chunk Z coordinate within the region + * @return a {@link DataOutputStream}, backed by memory, that can prepare the chunk for writing + * to disk. + */ public DataOutputStream getChunkDataOutputStream(int x, int z) { checkBounds(x, z); - Deflater deflater = new Deflater(COMPRESSION_ENABLED ? Deflater.BEST_SPEED : Deflater.NO_COMPRESSION); + Deflater deflater = new Deflater( + COMPRESSION_ENABLED ? Deflater.BEST_SPEED : Deflater.NO_COMPRESSION); deflater.setStrategy(Deflater.HUFFMAN_ONLY); DeflaterOutputStream dos = new DeflaterOutputStream(new ChunkBuffer(x, z), deflater, 2048); return new DataOutputStream(new BufferedOutputStream(dos)); @@ -330,7 +359,7 @@ protected void write(int x, int z, byte[] data, int length) throws IOException { sectorsUsed.set(totalSectors + i); } totalSectors += sectorsNeeded; - sizeDelta += SECTOR_BYTES * sectorsNeeded; + sizeDelta.addAndGet(SECTOR_BYTES * sectorsNeeded); write(sectorNumber, data, length); setOffset(x, z, sectorNumber << 8 | sectorsNeeded); @@ -386,7 +415,8 @@ public void close() throws IOException { */ class ChunkBuffer extends ByteArrayOutputStream { - private final int x, z; + private final int x; + private final int z; public ChunkBuffer(int x, int z) { super(SECTOR_BYTES); // initialize to 4KB diff --git a/src/main/java/net/glowstone/io/anvil/RegionFileCache.java b/src/main/java/net/glowstone/io/anvil/RegionFileCache.java index 483f8c17a5..28887447d3 100644 --- a/src/main/java/net/glowstone/io/anvil/RegionFileCache.java +++ b/src/main/java/net/glowstone/io/anvil/RegionFileCache.java @@ -44,7 +44,8 @@ */ public class RegionFileCache { - private static final int MAX_CACHE_SIZE = ((GlowServer) Bukkit.getServer()).getConfig().getInt(Key.REGION_CACHE_SIZE); + private static final int MAX_CACHE_SIZE = + ((GlowServer) Bukkit.getServer()).getConfig().getInt(Key.REGION_CACHE_SIZE); private static final RemovalListener removalListener = removal -> { try { @@ -55,15 +56,15 @@ public class RegionFileCache { }; private LoadingCache regions = CacheBuilder.newBuilder() - .expireAfterAccess(5, TimeUnit.MINUTES) - .maximumSize(MAX_CACHE_SIZE) - .removalListener(removalListener) - .build(new CacheLoader() { - @Override - public RegionFile load(File file) throws Exception { - return new RegionFile(file); - } - }); + .expireAfterAccess(5, TimeUnit.MINUTES) + .maximumSize(MAX_CACHE_SIZE) + .removalListener(removalListener) + .build(new CacheLoader() { + @Override + public RegionFile load(File file) throws Exception { + return new RegionFile(file); + } + }); private final String extension; private final File regionDir; @@ -73,11 +74,20 @@ public RegionFileCache(File basePath, String extension) { regionDir = new File(basePath, "region"); } + /** + * Returns the region file where a chunk is stored, opening it if necessary. Both the region + * file and the directory containing it will be created if they don't exist. + * + * @param chunkX the absolute chunk X coordinate + * @param chunkZ the absolute chunk Z coordinate + * @return the region file + */ public RegionFile getRegionFile(int chunkX, int chunkZ) { if (!regionDir.isDirectory() && !regionDir.mkdirs()) { GlowServer.logger.warning("Failed to create directory: " + regionDir); } - return regions.getUnchecked(new File(regionDir, "r." + (chunkX >> 5) + "." + (chunkZ >> 5) + extension)); + return regions.getUnchecked( + new File(regionDir, "r." + (chunkX >> 5) + "." + (chunkZ >> 5) + extension)); } public void clear() throws RejectedExecutionException { diff --git a/src/main/java/net/glowstone/io/entity/AbstractHorseStore.java b/src/main/java/net/glowstone/io/entity/AbstractHorseStore.java index 6387d24f8d..40b871cf3b 100644 --- a/src/main/java/net/glowstone/io/entity/AbstractHorseStore.java +++ b/src/main/java/net/glowstone/io/entity/AbstractHorseStore.java @@ -1,13 +1,16 @@ package net.glowstone.io.entity; +import java.util.function.Function; import net.glowstone.entity.passive.GlowAbstractHorse; import net.glowstone.util.nbt.CompoundTag; +import org.bukkit.Location; import org.bukkit.entity.EntityType; public class AbstractHorseStore extends TameableStore { - public AbstractHorseStore(Class clazz, EntityType type) { - super(clazz, type); + public AbstractHorseStore(Class clazz, EntityType type, + Function creator) { + super(clazz, type, creator); } @Override diff --git a/src/main/java/net/glowstone/io/entity/AgeableStore.java b/src/main/java/net/glowstone/io/entity/AgeableStore.java index 56221ce70f..3f4c93ab99 100644 --- a/src/main/java/net/glowstone/io/entity/AgeableStore.java +++ b/src/main/java/net/glowstone/io/entity/AgeableStore.java @@ -1,6 +1,6 @@ package net.glowstone.io.entity; -import java.lang.reflect.Constructor; +import java.util.function.Function; import net.glowstone.entity.GlowAgeable; import net.glowstone.util.nbt.CompoundTag; import org.bukkit.Location; @@ -8,32 +8,22 @@ public class AgeableStore extends CreatureStore { - private Constructor constructor; + private Function creator; - public AgeableStore(Class clazz, EntityType type) { + public AgeableStore(Class clazz, EntityType type, Function creator) { super(clazz, type); - init(clazz); + this.creator = creator; } - public AgeableStore(Class clazz, String type) { + public AgeableStore(Class clazz, String type, Function creator) { super(clazz, type); - init(clazz); - } - - private void init(Class clazz) { - Constructor ctor = null; - try { - ctor = clazz.getConstructor(Location.class); - } catch (Exception e) { - e.printStackTrace(); - } - constructor = ctor; + this.creator = creator; } @Override public T createEntity(Location location, CompoundTag compound) { try { - return constructor.newInstance(location); + return creator.apply(location); } catch (Exception e) { e.printStackTrace(); throw new UnsupportedOperationException("Not implemented yet."); diff --git a/src/main/java/net/glowstone/io/entity/AnimalStore.java b/src/main/java/net/glowstone/io/entity/AnimalStore.java index afcbc1c291..53df94b8d4 100644 --- a/src/main/java/net/glowstone/io/entity/AnimalStore.java +++ b/src/main/java/net/glowstone/io/entity/AnimalStore.java @@ -1,6 +1,6 @@ package net.glowstone.io.entity; -import java.lang.reflect.Constructor; +import java.util.function.Function; import net.glowstone.entity.GlowAnimal; import net.glowstone.util.nbt.CompoundTag; import org.bukkit.Location; @@ -8,32 +8,22 @@ public class AnimalStore extends EntityStore { - private Constructor constructor; + private final Function creator; - public AnimalStore(Class clazz, EntityType type) { + public AnimalStore(Class clazz, EntityType type, Function creator) { super(clazz, type); - init(clazz); + this.creator = creator; } - public AnimalStore(Class clazz, String type) { + public AnimalStore(Class clazz, String type, Function creator) { super(clazz, type); - init(clazz); - } - - private void init(Class clazz) { - Constructor ctor = null; - try { - ctor = clazz.getConstructor(Location.class); - } catch (Exception e) { - e.printStackTrace(); - } - constructor = ctor; + this.creator = creator; } @Override public T createEntity(Location location, CompoundTag compound) { try { - return constructor.newInstance(location); + return creator.apply(location); } catch (Exception e) { e.printStackTrace(); throw new UnsupportedOperationException("Not implemented yet."); diff --git a/src/main/java/net/glowstone/io/entity/BatStore.java b/src/main/java/net/glowstone/io/entity/BatStore.java index 451096d852..1d557b6081 100644 --- a/src/main/java/net/glowstone/io/entity/BatStore.java +++ b/src/main/java/net/glowstone/io/entity/BatStore.java @@ -16,6 +16,7 @@ public GlowBat createEntity(Location location, CompoundTag compound) { return new GlowBat(location); } + @Override public void load(GlowBat entity, CompoundTag compound) { super.load(entity, compound); if (compound.isByte("BatFlags")) { @@ -26,6 +27,7 @@ public void load(GlowBat entity, CompoundTag compound) { } + @Override public void save(GlowBat entity, CompoundTag tag) { super.save(entity, tag); tag.putBool("BatFlags", entity.isAwake()); diff --git a/src/main/java/net/glowstone/io/entity/ChestedHorseStore.java b/src/main/java/net/glowstone/io/entity/ChestedHorseStore.java index 0e2af2f940..033d41f332 100644 --- a/src/main/java/net/glowstone/io/entity/ChestedHorseStore.java +++ b/src/main/java/net/glowstone/io/entity/ChestedHorseStore.java @@ -1,17 +1,20 @@ package net.glowstone.io.entity; import java.util.List; +import java.util.function.Function; import net.glowstone.entity.passive.GlowChestedHorse; import net.glowstone.io.nbt.NbtSerialization; import net.glowstone.util.nbt.CompoundTag; import net.glowstone.util.nbt.TagType; +import org.bukkit.Location; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; public class ChestedHorseStore extends AbstractHorseStore { - public ChestedHorseStore(Class clazz, EntityType type) { - super(clazz, type); + public ChestedHorseStore(Class clazz, EntityType type, + Function creator) { + super(clazz, type, creator); } @Override diff --git a/src/main/java/net/glowstone/io/entity/ChickenStore.java b/src/main/java/net/glowstone/io/entity/ChickenStore.java index ffa7b60455..019aca80da 100644 --- a/src/main/java/net/glowstone/io/entity/ChickenStore.java +++ b/src/main/java/net/glowstone/io/entity/ChickenStore.java @@ -7,7 +7,7 @@ class ChickenStore extends AgeableStore { public ChickenStore() { - super(GlowChicken.class, EntityType.CHICKEN); + super(GlowChicken.class, EntityType.CHICKEN, GlowChicken::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/CreatureStore.java b/src/main/java/net/glowstone/io/entity/CreatureStore.java index fdeabf4b82..06d7126150 100644 --- a/src/main/java/net/glowstone/io/entity/CreatureStore.java +++ b/src/main/java/net/glowstone/io/entity/CreatureStore.java @@ -14,10 +14,12 @@ public CreatureStore(Class clazz, String type) { super(clazz, type); } + @Override public void load(T entity, CompoundTag compound) { super.load(entity, compound); } + @Override public void save(T entity, CompoundTag tag) { super.save(entity, tag); } diff --git a/src/main/java/net/glowstone/io/entity/CreeperStore.java b/src/main/java/net/glowstone/io/entity/CreeperStore.java index b398521a40..02d2ace171 100644 --- a/src/main/java/net/glowstone/io/entity/CreeperStore.java +++ b/src/main/java/net/glowstone/io/entity/CreeperStore.java @@ -7,7 +7,7 @@ class CreeperStore extends MonsterStore { public CreeperStore() { - super(GlowCreeper.class, EntityType.CREEPER); + super(GlowCreeper.class, EntityType.CREEPER, GlowCreeper::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/EndermanStore.java b/src/main/java/net/glowstone/io/entity/EndermanStore.java index 8dc533b257..842f63b755 100644 --- a/src/main/java/net/glowstone/io/entity/EndermanStore.java +++ b/src/main/java/net/glowstone/io/entity/EndermanStore.java @@ -10,7 +10,7 @@ class EndermanStore extends MonsterStore { public EndermanStore() { - super(GlowEnderman.class, EntityType.ENDERMAN); + super(GlowEnderman.class, EntityType.ENDERMAN, GlowEnderman::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/EndermiteStore.java b/src/main/java/net/glowstone/io/entity/EndermiteStore.java index ac3b439d5b..c652496374 100644 --- a/src/main/java/net/glowstone/io/entity/EndermiteStore.java +++ b/src/main/java/net/glowstone/io/entity/EndermiteStore.java @@ -7,7 +7,7 @@ class EndermiteStore extends MonsterStore { public EndermiteStore() { - super(GlowEndermite.class, EntityType.ENDERMITE); + super(GlowEndermite.class, EntityType.ENDERMITE, GlowEndermite::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/EntityStorage.java b/src/main/java/net/glowstone/io/entity/EntityStorage.java index 7d33a968f0..0adb3ffddb 100644 --- a/src/main/java/net/glowstone/io/entity/EntityStorage.java +++ b/src/main/java/net/glowstone/io/entity/EntityStorage.java @@ -7,13 +7,16 @@ import net.glowstone.entity.monster.GlowBlaze; import net.glowstone.entity.monster.GlowCaveSpider; import net.glowstone.entity.monster.GlowGiant; +import net.glowstone.entity.monster.GlowHusk; import net.glowstone.entity.monster.GlowMagmaCube; import net.glowstone.entity.monster.GlowSilverfish; import net.glowstone.entity.monster.GlowSkeleton; import net.glowstone.entity.monster.GlowSlime; import net.glowstone.entity.monster.GlowSnowman; import net.glowstone.entity.monster.GlowSpider; +import net.glowstone.entity.monster.GlowStray; import net.glowstone.entity.monster.GlowWitch; +import net.glowstone.entity.monster.GlowWitherSkeleton; import net.glowstone.entity.objects.GlowMinecart; import net.glowstone.entity.passive.GlowCow; import net.glowstone.entity.passive.GlowDonkey; @@ -62,15 +65,17 @@ public final class EntityStorage { bind(new OcelotStore()); bind(new WolfStore()); bind(new VillagerStore()); - bind(new AgeableStore<>(GlowCow.class, EntityType.COW)); - bind(new AgeableStore<>(GlowMooshroom.class, EntityType.MUSHROOM_COW)); - bind(new WaterMobStore<>(GlowSquid.class, EntityType.SQUID)); - bind(new AgeableStore<>(GlowPolarBear.class, EntityType.POLAR_BEAR)); - bind(new AbstractHorseStore<>(GlowZombieHorse.class, EntityType.ZOMBIE_HORSE)); - bind(new AbstractHorseStore<>(GlowSkeletonHorse.class, EntityType.SKELETON_HORSE)); - bind(new ChestedHorseStore<>(GlowLlama.class, EntityType.LLAMA)); - bind(new ChestedHorseStore<>(GlowMule.class, EntityType.MULE)); - bind(new ChestedHorseStore<>(GlowDonkey.class, EntityType.DONKEY)); + bind(new AgeableStore<>(GlowCow.class, EntityType.COW, GlowCow::new)); + bind(new AgeableStore<>(GlowMooshroom.class, EntityType.MUSHROOM_COW, GlowMooshroom::new)); + bind(new WaterMobStore<>(GlowSquid.class, EntityType.SQUID, GlowSquid::new)); + bind(new AgeableStore<>(GlowPolarBear.class, EntityType.POLAR_BEAR, GlowPolarBear::new)); + bind(new AbstractHorseStore<>(GlowZombieHorse.class, EntityType.ZOMBIE_HORSE, + GlowZombieHorse::new)); + bind(new AbstractHorseStore<>(GlowSkeletonHorse.class, EntityType.SKELETON_HORSE, + GlowSkeletonHorse::new)); + bind(new ChestedHorseStore<>(GlowLlama.class, EntityType.LLAMA, GlowLlama::new)); + bind(new ChestedHorseStore<>(GlowMule.class, EntityType.MULE, GlowMule::new)); + bind(new ChestedHorseStore<>(GlowDonkey.class, EntityType.DONKEY, GlowDonkey::new)); bind(new HorseStore()); bind(new ParrotStore()); @@ -81,32 +86,35 @@ public final class EntityStorage { bind(new GhastStore()); bind(new GuardianStore()); bind(new IronGolemStore()); - bind(new SlimeStore<>(GlowSlime.class, EntityType.SLIME)); - bind(new SlimeStore<>(GlowMagmaCube.class, EntityType.MAGMA_CUBE)); + bind(new SlimeStore<>(GlowSlime.class, EntityType.SLIME, GlowSlime::new)); + bind(new SlimeStore<>(GlowMagmaCube.class, EntityType.MAGMA_CUBE, GlowMagmaCube::new)); bind(new ZombieStore<>()); + bind(new ZombieStore<>(GlowHusk.class, EntityType.HUSK, GlowHusk::new)); bind(new PigZombieStore()); - bind(new MonsterStore<>(GlowSkeleton.class, EntityType.SKELETON)); - bind(new MonsterStore<>(GlowSkeleton.class, EntityType.STRAY)); - bind(new MonsterStore<>(GlowSkeleton.class, EntityType.WITHER_SKELETON)); - bind(new MonsterStore<>(GlowBlaze.class, EntityType.BLAZE)); - bind(new MonsterStore<>(GlowCaveSpider.class, EntityType.CAVE_SPIDER)); - bind(new MonsterStore<>(GlowSpider.class, EntityType.SPIDER)); - bind(new MonsterStore<>(GlowSnowman.class, EntityType.SNOWMAN)); - bind(new MonsterStore<>(GlowGiant.class, EntityType.GIANT)); - bind(new MonsterStore<>(GlowSilverfish.class, EntityType.SILVERFISH)); - bind(new MonsterStore<>(GlowWitch.class, EntityType.WITCH)); + bind(new MonsterStore<>(GlowSkeleton.class, EntityType.SKELETON, GlowSkeleton::new)); + bind(new MonsterStore<>(GlowStray.class, EntityType.STRAY, GlowStray::new)); + bind(new MonsterStore<>(GlowWitherSkeleton.class, EntityType.WITHER_SKELETON, + GlowWitherSkeleton::new)); + bind(new MonsterStore<>(GlowBlaze.class, EntityType.BLAZE, GlowBlaze::new)); + bind(new MonsterStore<>(GlowCaveSpider.class, EntityType.CAVE_SPIDER, GlowCaveSpider::new)); + bind(new MonsterStore<>(GlowSpider.class, EntityType.SPIDER, GlowSpider::new)); + bind(new MonsterStore<>(GlowSnowman.class, EntityType.SNOWMAN, GlowSnowman::new)); + bind(new MonsterStore<>(GlowGiant.class, EntityType.GIANT, GlowGiant::new)); + bind(new MonsterStore<>(GlowSilverfish.class, EntityType.SILVERFISH, GlowSilverfish::new)); + bind(new MonsterStore<>(GlowWitch.class, EntityType.WITCH, GlowWitch::new)); bind(new ShulkerStore()); bind(new WitherStore()); bind(new VexStore()); bind(new VindicatorStore()); bind(new EvokerStore()); bind(new EnderDragonStore()); + bind(new ZombieVillagerStore()); bind(new ArmorStandStore()); bind(new FallingBlockStore()); bind(new ItemFrameStore()); bind(new ItemStore()); - bind(new TNTPrimedStorage()); + bind(new TntPrimedStorage()); bind(new EnderCrystalStore()); bind(new BoatStore()); for (GlowMinecart.MinecartType type : GlowMinecart.MinecartType.values()) { diff --git a/src/main/java/net/glowstone/io/entity/EntityStore.java b/src/main/java/net/glowstone/io/entity/EntityStore.java index 07cddadfbf..e743d61b67 100644 --- a/src/main/java/net/glowstone/io/entity/EntityStore.java +++ b/src/main/java/net/glowstone/io/entity/EntityStore.java @@ -4,6 +4,8 @@ import java.util.List; import java.util.UUID; import java.util.logging.Level; +import lombok.Data; +import lombok.RequiredArgsConstructor; import net.glowstone.GlowServer; import net.glowstone.entity.GlowEntity; import net.glowstone.io.nbt.NbtSerialization; @@ -18,27 +20,16 @@ * * @param The type of entity being stored. */ +@Data +@RequiredArgsConstructor public abstract class EntityStore { - protected final Class clazz; - protected final String type; + protected final Class type; + protected final String entityType; - public EntityStore(Class clazz, EntityType type) { - this.clazz = clazz; - this.type = type.getName(); - } - - public EntityStore(Class clazz, String name) { - this.type = name; - this.clazz = clazz; - } - - public final String getEntityType() { - return type; - } - - public final Class getType() { - return clazz; + public EntityStore(Class type, EntityType entityType) { + this.type = type; + this.entityType = entityType.getName(); } /** @@ -155,7 +146,7 @@ private Entity loadPassenger(T vehicle, CompoundTag compoundTag) { * @param tag The target tag. */ public void save(T entity, CompoundTag tag) { - tag.putString("id", "minecraft:" + type); + tag.putString("id", "minecraft:" + entityType); // write world info, Pos, Rotation, and Motion Location loc = entity.getLocation(); diff --git a/src/main/java/net/glowstone/io/entity/EvokerStore.java b/src/main/java/net/glowstone/io/entity/EvokerStore.java index 512d29e9ae..dd7cef4656 100644 --- a/src/main/java/net/glowstone/io/entity/EvokerStore.java +++ b/src/main/java/net/glowstone/io/entity/EvokerStore.java @@ -6,6 +6,6 @@ public class EvokerStore extends MonsterStore { public EvokerStore() { - super(GlowEvoker.class, EntityType.EVOKER); + super(GlowEvoker.class, EntityType.EVOKER, GlowEvoker::new); } } diff --git a/src/main/java/net/glowstone/io/entity/GhastStore.java b/src/main/java/net/glowstone/io/entity/GhastStore.java index 5d89962895..72cd1d48aa 100644 --- a/src/main/java/net/glowstone/io/entity/GhastStore.java +++ b/src/main/java/net/glowstone/io/entity/GhastStore.java @@ -7,7 +7,7 @@ class GhastStore extends MonsterStore { public GhastStore() { - super(GlowGhast.class, EntityType.GHAST); + super(GlowGhast.class, EntityType.GHAST, GlowGhast::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/GuardianStore.java b/src/main/java/net/glowstone/io/entity/GuardianStore.java index 9f97e45bad..2501adef1f 100644 --- a/src/main/java/net/glowstone/io/entity/GuardianStore.java +++ b/src/main/java/net/glowstone/io/entity/GuardianStore.java @@ -7,7 +7,7 @@ class GuardianStore extends MonsterStore { public GuardianStore() { - super(GlowGuardian.class, EntityType.GUARDIAN); + super(GlowGuardian.class, EntityType.GUARDIAN, GlowGuardian::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/HorseStore.java b/src/main/java/net/glowstone/io/entity/HorseStore.java index df4fbca0fe..3a46115f84 100644 --- a/src/main/java/net/glowstone/io/entity/HorseStore.java +++ b/src/main/java/net/glowstone/io/entity/HorseStore.java @@ -9,7 +9,7 @@ public class HorseStore extends AbstractHorseStore { public HorseStore() { - super(GlowHorse.class, EntityType.HORSE); + super(GlowHorse.class, EntityType.HORSE, GlowHorse::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/IronGolemStore.java b/src/main/java/net/glowstone/io/entity/IronGolemStore.java index deed7e064d..95c65fd3de 100644 --- a/src/main/java/net/glowstone/io/entity/IronGolemStore.java +++ b/src/main/java/net/glowstone/io/entity/IronGolemStore.java @@ -7,7 +7,7 @@ class IronGolemStore extends MonsterStore { public IronGolemStore() { - super(GlowIronGolem.class, EntityType.IRON_GOLEM); + super(GlowIronGolem.class, EntityType.IRON_GOLEM, GlowIronGolem::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/ItemFrameStore.java b/src/main/java/net/glowstone/io/entity/ItemFrameStore.java index fbdeab5664..81da061987 100644 --- a/src/main/java/net/glowstone/io/entity/ItemFrameStore.java +++ b/src/main/java/net/glowstone/io/entity/ItemFrameStore.java @@ -14,6 +14,7 @@ public ItemFrameStore() { super(GlowItemFrame.class, EntityType.ITEM_FRAME); } + @Override public GlowItemFrame createEntity(Location location, CompoundTag compound) { // item frame will be set by loading code below return new GlowItemFrame(null, location, null); diff --git a/src/main/java/net/glowstone/io/entity/LivingEntityStore.java b/src/main/java/net/glowstone/io/entity/LivingEntityStore.java index bbab8a9a7c..0f081b20e5 100644 --- a/src/main/java/net/glowstone/io/entity/LivingEntityStore.java +++ b/src/main/java/net/glowstone/io/entity/LivingEntityStore.java @@ -116,33 +116,36 @@ public void load(T entity, CompoundTag compound) { AttributeManager am = entity.getAttributeManager(); for (CompoundTag tag : attributes) { - if (tag.isString("Name") && tag.isDouble("Base")) { - List modifiers = null; - if (tag.isList("Modifiers", TagType.COMPOUND)) { - modifiers = new ArrayList<>(); - - List modifierTags = tag.getCompoundList("Modifiers"); - for (CompoundTag modifierTag : modifierTags) { - if (modifierTag.isDouble("Amount") && modifierTag.isString("Name") && - modifierTag.isInt("Operation") && modifierTag.isLong("UUIDLeast") && - modifierTag.isLong("UUIDMost")) { - modifiers.add(new Modifier( + if (!tag.isString("Name") || !tag.isDouble("Base")) { + continue; + } + List modifiers = null; + if (tag.isList("Modifiers", TagType.COMPOUND)) { + modifiers = new ArrayList<>(); + + List modifierTags = tag.getCompoundList("Modifiers"); + for (CompoundTag modifierTag : modifierTags) { + if (modifierTag.isDouble("Amount") + && modifierTag.isString("Name") + && modifierTag.isInt("Operation") + && modifierTag.isLong("UUIDLeast") + && modifierTag.isLong("UUIDMost")) { + modifiers.add(new Modifier( modifierTag.getString("Name"), new UUID(modifierTag.getLong("UUIDLeast"), - modifierTag.getLong("UUIDMost")), + modifierTag.getLong("UUIDMost")), modifierTag.getDouble("Amount"), (byte) modifierTag.getInt("Operation"))); - } } } - - am.setProperty(tag.getString("Name"), tag.getDouble("Base"), modifiers); } + + am.setProperty(tag.getString("Name"), tag.getDouble("Base"), modifiers); } } if (compound.isByte("Leashed") && compound.getBool("Leashed") && !compound - .isCompound("Leash")) { + .isCompound("Leash")) { // We know that there was something leashed, but not what entity it was // This can happen, when for example Minecart got leashed // We still have to make sure that we drop a Leash Item @@ -158,7 +161,7 @@ public void load(T entity, CompoundTag compound) { int z = leash.getInt("Z"); LeashHitch leashHitch = GlowLeashHitch - .getLeashHitchAt(new Location(entity.getWorld(), x, y, z).getBlock()); + .getLeashHitchAt(new Location(entity.getWorld(), x, y, z).getBlock()); entity.setLeashHolder(leashHitch); } } @@ -278,9 +281,9 @@ public void save(T entity, CompoundTag tag) { modifierTag.putString("Name", modifier.getName()); modifierTag.putInt("Operation", modifier.getOperation()); modifierTag - .putLong("UUIDLeast", modifier.getUuid().getLeastSignificantBits()); + .putLong("UUIDLeast", modifier.getUuid().getLeastSignificantBits()); modifierTag - .putLong("UUIDMost", modifier.getUuid().getMostSignificantBits()); + .putLong("UUIDMost", modifier.getUuid().getMostSignificantBits()); modifiers.add(modifierTag); } attribute.putCompoundList("Modifiers", modifiers); @@ -307,25 +310,25 @@ public void save(T entity, CompoundTag tag) { EntityEquipment equip = entity.getEquipment(); if (equip != null) { tag.putCompoundList("HandItems", Arrays.asList( - NbtSerialization.writeItem(equip.getItemInMainHand(), -1), - NbtSerialization.writeItem(equip.getItemInOffHand(), -1) + NbtSerialization.writeItem(equip.getItemInMainHand(), -1), + NbtSerialization.writeItem(equip.getItemInOffHand(), -1) )); tag.putCompoundList("ArmorItems", Arrays.asList( - NbtSerialization.writeItem(equip.getBoots(), -1), - NbtSerialization.writeItem(equip.getLeggings(), -1), - NbtSerialization.writeItem(equip.getChestplate(), -1), - NbtSerialization.writeItem(equip.getHelmet(), -1) + NbtSerialization.writeItem(equip.getBoots(), -1), + NbtSerialization.writeItem(equip.getLeggings(), -1), + NbtSerialization.writeItem(equip.getChestplate(), -1), + NbtSerialization.writeItem(equip.getHelmet(), -1) )); tag.putList("HandDropChances", TagType.FLOAT, Arrays.asList( - equip.getItemInMainHandDropChance(), - equip.getItemInOffHandDropChance() + equip.getItemInMainHandDropChance(), + equip.getItemInOffHandDropChance() )); tag.putList("ArmorDropChances", TagType.FLOAT, Arrays.asList( - equip.getBootsDropChance(), - equip.getLeggingsDropChance(), - equip.getChestplateDropChance(), - equip.getHelmetDropChance() + equip.getBootsDropChance(), + equip.getLeggingsDropChance(), + equip.getChestplateDropChance(), + equip.getHelmetDropChance() )); } tag.putBool("CanPickUpLoot", entity.getCanPickupItems()); diff --git a/src/main/java/net/glowstone/io/entity/MinecartStore.java b/src/main/java/net/glowstone/io/entity/MinecartStore.java index 5e55197314..42dac7b96f 100644 --- a/src/main/java/net/glowstone/io/entity/MinecartStore.java +++ b/src/main/java/net/glowstone/io/entity/MinecartStore.java @@ -1,7 +1,6 @@ package net.glowstone.io.entity; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; +import java.util.function.Function; import net.glowstone.entity.objects.GlowMinecart; import net.glowstone.io.nbt.NbtSerialization; import net.glowstone.util.nbt.CompoundTag; @@ -10,23 +9,17 @@ public class MinecartStore extends EntityStore { - private GlowMinecart.MinecartType type; + private GlowMinecart.MinecartType minecartType; - public MinecartStore(GlowMinecart.MinecartType type) { - super((Class) type.getMinecartClass(), type.getEntityType()); - this.type = type; + public MinecartStore(GlowMinecart.MinecartType minecartType) { + super(minecartType.getMinecartClass(), minecartType.getEntityType()); + this.minecartType = minecartType; } @Override public GlowMinecart createEntity(Location location, CompoundTag compound) { - try { - Constructor constructor = type.getMinecartClass() - .getConstructor(Location.class); - return constructor.newInstance(location); - } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { - e.printStackTrace(); - } - return null; + Function creator = minecartType.getCreator(); + return creator == null ? null : creator.apply(location); } @Override @@ -34,9 +27,9 @@ public void load(GlowMinecart entity, CompoundTag tag) { super.load(entity, tag); if (entity instanceof InventoryHolder) { InventoryHolder inv = (InventoryHolder) entity; - if (inv.getInventory() != null) { - inv.getInventory().setContents(NbtSerialization - .readInventory(tag.getCompoundList("Items"), 0, inv.getInventory().getSize())); + if (inv.getInventory() != null && tag.isCompoundList("Items")) { + inv.getInventory().setContents(NbtSerialization.readInventory( + tag.getCompoundList("Items"), 0, inv.getInventory().getSize())); } } // todo @@ -49,7 +42,7 @@ public void save(GlowMinecart entity, CompoundTag tag) { InventoryHolder inv = (InventoryHolder) entity; if (inv.getInventory() != null) { tag.putCompoundList("Items", - NbtSerialization.writeInventory(inv.getInventory().getContents(), 0)); + NbtSerialization.writeInventory(inv.getInventory().getContents(), 0)); } } // todo diff --git a/src/main/java/net/glowstone/io/entity/MonsterStore.java b/src/main/java/net/glowstone/io/entity/MonsterStore.java index 70d581361b..e2cb3b1af3 100644 --- a/src/main/java/net/glowstone/io/entity/MonsterStore.java +++ b/src/main/java/net/glowstone/io/entity/MonsterStore.java @@ -1,6 +1,6 @@ package net.glowstone.io.entity; -import java.lang.reflect.Constructor; +import java.util.function.Function; import net.glowstone.entity.monster.GlowMonster; import net.glowstone.util.nbt.CompoundTag; import org.bukkit.Location; @@ -8,32 +8,24 @@ public class MonsterStore extends EntityStore { - private Constructor constructor; + private final Function creator; - public MonsterStore(Class clazz, EntityType type) { + public MonsterStore(Class clazz, EntityType type, + Function creator) { super(clazz, type); - init(clazz); + this.creator = creator; } - public MonsterStore(Class clazz, String type) { + public MonsterStore(Class clazz, String type, + Function creator) { super(clazz, type); - init(clazz); - } - - private void init(Class clazz) { - Constructor ctor = null; - try { - ctor = clazz.getConstructor(Location.class); - } catch (Exception e) { - e.printStackTrace(); - } - constructor = ctor; + this.creator = creator; } @Override public T createEntity(Location location, CompoundTag compound) { try { - return constructor.newInstance(location); + return creator.apply(location); } catch (Exception e) { e.printStackTrace(); throw new UnsupportedOperationException("Not implemented yet."); diff --git a/src/main/java/net/glowstone/io/entity/OcelotStore.java b/src/main/java/net/glowstone/io/entity/OcelotStore.java index 4f26e8890d..50dd4cff60 100644 --- a/src/main/java/net/glowstone/io/entity/OcelotStore.java +++ b/src/main/java/net/glowstone/io/entity/OcelotStore.java @@ -8,7 +8,7 @@ class OcelotStore extends TameableStore { public OcelotStore() { - super(GlowOcelot.class, EntityType.OCELOT); + super(GlowOcelot.class, EntityType.OCELOT, GlowOcelot::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/ParrotStore.java b/src/main/java/net/glowstone/io/entity/ParrotStore.java index 2b95090f2a..d1f97cec1b 100644 --- a/src/main/java/net/glowstone/io/entity/ParrotStore.java +++ b/src/main/java/net/glowstone/io/entity/ParrotStore.java @@ -7,7 +7,7 @@ public class ParrotStore extends TameableStore { public ParrotStore() { - super(GlowParrot.class, EntityType.PARROT); + super(GlowParrot.class, EntityType.PARROT, GlowParrot::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/PigStore.java b/src/main/java/net/glowstone/io/entity/PigStore.java index eac327f85a..6b360ecd42 100644 --- a/src/main/java/net/glowstone/io/entity/PigStore.java +++ b/src/main/java/net/glowstone/io/entity/PigStore.java @@ -7,7 +7,7 @@ class PigStore extends AgeableStore { public PigStore() { - super(GlowPig.class, EntityType.PIG); + super(GlowPig.class, EntityType.PIG, GlowPig::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/PigZombieStore.java b/src/main/java/net/glowstone/io/entity/PigZombieStore.java index aee8c55a84..ddce5dac45 100644 --- a/src/main/java/net/glowstone/io/entity/PigZombieStore.java +++ b/src/main/java/net/glowstone/io/entity/PigZombieStore.java @@ -9,7 +9,7 @@ class PigZombieStore extends ZombieStore { public PigZombieStore() { - super(GlowPigZombie.class, EntityType.PIG_ZOMBIE); + super(GlowPigZombie.class, EntityType.PIG_ZOMBIE, GlowPigZombie::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/RabbitStore.java b/src/main/java/net/glowstone/io/entity/RabbitStore.java index 6380a29c11..b7ea075778 100644 --- a/src/main/java/net/glowstone/io/entity/RabbitStore.java +++ b/src/main/java/net/glowstone/io/entity/RabbitStore.java @@ -30,7 +30,7 @@ class RabbitStore extends AgeableStore { .build(); public RabbitStore() { - super(GlowRabbit.class, EntityType.RABBIT); + super(GlowRabbit.class, EntityType.RABBIT, GlowRabbit::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/SheepStore.java b/src/main/java/net/glowstone/io/entity/SheepStore.java index 31f9a51e67..94520e2113 100644 --- a/src/main/java/net/glowstone/io/entity/SheepStore.java +++ b/src/main/java/net/glowstone/io/entity/SheepStore.java @@ -12,7 +12,7 @@ class SheepStore extends AgeableStore { public static final String COLOR_KEY = "Color"; public SheepStore() { - super(GlowSheep.class, EntityType.SHEEP); + super(GlowSheep.class, EntityType.SHEEP, GlowSheep::new); } @Override @@ -20,6 +20,7 @@ public GlowSheep createEntity(Location location, CompoundTag compound) { return new GlowSheep(location); } + @Override public void load(GlowSheep entity, CompoundTag compound) { super.load(entity, compound); if (compound.isByte(COLOR_KEY)) { @@ -35,6 +36,7 @@ public void load(GlowSheep entity, CompoundTag compound) { } } + @Override public void save(GlowSheep entity, CompoundTag tag) { super.save(entity, tag); tag.putByte(COLOR_KEY, entity.getColor().ordinal()); diff --git a/src/main/java/net/glowstone/io/entity/ShulkerStore.java b/src/main/java/net/glowstone/io/entity/ShulkerStore.java index 0826b9ab37..5e5cd5a3b1 100644 --- a/src/main/java/net/glowstone/io/entity/ShulkerStore.java +++ b/src/main/java/net/glowstone/io/entity/ShulkerStore.java @@ -8,7 +8,7 @@ public class ShulkerStore extends MonsterStore { public ShulkerStore() { - super(GlowShulker.class, EntityType.SHULKER); + super(GlowShulker.class, EntityType.SHULKER, GlowShulker::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/SlimeStore.java b/src/main/java/net/glowstone/io/entity/SlimeStore.java index 69cc9b2f81..bd32403885 100644 --- a/src/main/java/net/glowstone/io/entity/SlimeStore.java +++ b/src/main/java/net/glowstone/io/entity/SlimeStore.java @@ -1,13 +1,15 @@ package net.glowstone.io.entity; +import java.util.function.Function; import net.glowstone.entity.monster.GlowSlime; import net.glowstone.util.nbt.CompoundTag; +import org.bukkit.Location; import org.bukkit.entity.EntityType; class SlimeStore extends MonsterStore { - public SlimeStore(Class clazz, EntityType type) { - super(clazz, type); + public SlimeStore(Class clazz, EntityType type, Function creator) { + super(clazz, type, creator); } @Override diff --git a/src/main/java/net/glowstone/io/entity/TameableStore.java b/src/main/java/net/glowstone/io/entity/TameableStore.java index 24d5b40307..2658970d46 100644 --- a/src/main/java/net/glowstone/io/entity/TameableStore.java +++ b/src/main/java/net/glowstone/io/entity/TameableStore.java @@ -1,16 +1,18 @@ package net.glowstone.io.entity; import java.util.UUID; +import java.util.function.Function; import net.glowstone.entity.passive.GlowTameable; import net.glowstone.util.nbt.CompoundTag; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.entity.EntityType; abstract class TameableStore extends AgeableStore { - public TameableStore(Class clazz, EntityType type) { - super(clazz, type); + public TameableStore(Class clazz, EntityType type, Function creator) { + super(clazz, type, creator); } @Override @@ -18,17 +20,17 @@ public void load(T entity, CompoundTag compound) { // TODO make this better. super.load(entity, compound); if (compound.containsKey("OwnerUUID") && !compound.getString("OwnerUUID").isEmpty()) { - entity.setOwnerUUID(UUID.fromString(compound.getString("OwnerUUID"))); - if (Bukkit.getPlayer(entity.getOwnerUUID()) != null) { - entity.setOwner(Bukkit.getPlayer(entity.getOwnerUUID())); + entity.setOwnerUuid(UUID.fromString(compound.getString("OwnerUUID"))); + if (Bukkit.getPlayer(entity.getOwnerUuid()) != null) { + entity.setOwner(Bukkit.getPlayer(entity.getOwnerUuid())); } } else if (compound.containsKey("Owner") && !compound.getString("Owner").isEmpty()) { String playerName = compound.getString("Owner"); OfflinePlayer player = Bukkit.getOfflinePlayer(playerName); if (player.hasPlayedBefore()) { - entity.setOwnerUUID(player.getUniqueId()); - if (Bukkit.getPlayer(entity.getOwnerUUID()) != null) { - entity.setOwner(Bukkit.getPlayer(entity.getOwnerUUID())); + entity.setOwnerUuid(player.getUniqueId()); + if (Bukkit.getPlayer(entity.getOwnerUuid()) != null) { + entity.setOwner(Bukkit.getPlayer(entity.getOwnerUuid())); } } } diff --git a/src/main/java/net/glowstone/io/entity/TNTPrimedStorage.java b/src/main/java/net/glowstone/io/entity/TntPrimedStorage.java similarity index 51% rename from src/main/java/net/glowstone/io/entity/TNTPrimedStorage.java rename to src/main/java/net/glowstone/io/entity/TntPrimedStorage.java index 9eff3c96e3..e0dbd71d73 100644 --- a/src/main/java/net/glowstone/io/entity/TNTPrimedStorage.java +++ b/src/main/java/net/glowstone/io/entity/TntPrimedStorage.java @@ -1,23 +1,23 @@ package net.glowstone.io.entity; -import net.glowstone.entity.GlowTNTPrimed; +import net.glowstone.entity.GlowTntPrimed; import net.glowstone.util.nbt.CompoundTag; import org.bukkit.Location; import org.bukkit.entity.EntityType; -class TNTPrimedStorage extends EntityStore { +class TntPrimedStorage extends EntityStore { - public TNTPrimedStorage() { - super(GlowTNTPrimed.class, EntityType.PRIMED_TNT); + public TntPrimedStorage() { + super(GlowTntPrimed.class, EntityType.PRIMED_TNT); } @Override - public GlowTNTPrimed createEntity(Location location, CompoundTag compound) { - return new GlowTNTPrimed(location, null); + public GlowTntPrimed createEntity(Location location, CompoundTag compound) { + return new GlowTntPrimed(location, null); } @Override - public void load(GlowTNTPrimed entity, CompoundTag tag) { + public void load(GlowTntPrimed entity, CompoundTag tag) { super.load(entity, tag); if (tag.isByte("Fuse")) { @@ -26,7 +26,7 @@ public void load(GlowTNTPrimed entity, CompoundTag tag) { } @Override - public void save(GlowTNTPrimed entity, CompoundTag tag) { + public void save(GlowTntPrimed entity, CompoundTag tag) { super.save(entity, tag); tag.putByte("Fuse", entity.getFuseTicks()); diff --git a/src/main/java/net/glowstone/io/entity/VexStore.java b/src/main/java/net/glowstone/io/entity/VexStore.java index 04f5f1d76a..0346364496 100644 --- a/src/main/java/net/glowstone/io/entity/VexStore.java +++ b/src/main/java/net/glowstone/io/entity/VexStore.java @@ -7,7 +7,7 @@ public class VexStore extends MonsterStore { public VexStore() { - super(GlowVex.class, EntityType.VEX); + super(GlowVex.class, EntityType.VEX, GlowVex::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/VillagerStore.java b/src/main/java/net/glowstone/io/entity/VillagerStore.java index 5d2ce9fb07..b86dc4b40b 100644 --- a/src/main/java/net/glowstone/io/entity/VillagerStore.java +++ b/src/main/java/net/glowstone/io/entity/VillagerStore.java @@ -8,23 +8,23 @@ import net.glowstone.util.nbt.TagType; import org.bukkit.entity.EntityType; import org.bukkit.entity.Villager; -import org.bukkit.entity.Villager.Profession; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.MerchantRecipe; class VillagerStore extends AgeableStore { public VillagerStore() { - super(GlowVillager.class, EntityType.VILLAGER); + super(GlowVillager.class, EntityType.VILLAGER, GlowVillager::new); } @Override public void load(GlowVillager entity, CompoundTag compound) { super.load(entity, compound); if (compound.isInt("Profession")) { - entity.setProfession(Profession.values()[compound.getInt("Profession")]); - } else { - entity.setProfession(Profession.FARMER); + int professionId = compound.getInt("Profession"); + if (GlowVillager.isValidProfession(professionId)) { + entity.setProfession(GlowVillager.getProfessionById(professionId)); + } } if (compound.isInt("Career")) { int id = compound.getInt("Career"); @@ -51,11 +51,9 @@ public void load(GlowVillager entity, CompoundTag compound) { entity.clearRecipes(); List recipesList = offers.getList("Recipes", TagType.COMPOUND); for (CompoundTag recipeTag : recipesList) { - boolean experienceReward = recipeTag.getBool("rewardExp"); - int uses = recipeTag.getInt("uses"); - int maxUses = recipeTag.getInt("maxUses"); - CompoundTag sellTag = recipeTag.getCompound("sell"), buy1tag = recipeTag - .getCompound("buy"), buy2tag = null; + CompoundTag sellTag = recipeTag.getCompound("sell"); + CompoundTag buy1tag = recipeTag.getCompound("buy"); + CompoundTag buy2tag = null; if (recipeTag.isCompound("buyB")) { buy2tag = recipeTag.getCompound("buyB"); } @@ -66,6 +64,9 @@ public void load(GlowVillager entity, CompoundTag compound) { if (buy2tag != null) { ingredients.add(NbtSerialization.readItem(buy2tag)); } + boolean experienceReward = recipeTag.getBool("rewardExp"); + int uses = recipeTag.getInt("uses"); + int maxUses = recipeTag.getInt("maxUses"); MerchantRecipe recipe = new MerchantRecipe(sell, uses, maxUses, experienceReward); recipe.setIngredients(ingredients); @@ -80,7 +81,9 @@ public void load(GlowVillager entity, CompoundTag compound) { @Override public void save(GlowVillager entity, CompoundTag tag) { super.save(entity, tag); - tag.putInt("Profession", entity.getProfession().ordinal()); + if (entity.getProfession() != null && entity.getProfession() != Villager.Profession.HUSK) { + tag.putInt("Profession", entity.getProfession().ordinal()); + } if (entity.getCareer() != null) { tag.putInt("Career", entity.getCareer().getId()); } diff --git a/src/main/java/net/glowstone/io/entity/VindicatorStore.java b/src/main/java/net/glowstone/io/entity/VindicatorStore.java index 73b034e428..bcc50b7433 100644 --- a/src/main/java/net/glowstone/io/entity/VindicatorStore.java +++ b/src/main/java/net/glowstone/io/entity/VindicatorStore.java @@ -7,7 +7,7 @@ public class VindicatorStore extends MonsterStore { public VindicatorStore() { - super(GlowVindicator.class, EntityType.VINDICATOR); + super(GlowVindicator.class, EntityType.VINDICATOR, GlowVindicator::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/WaterMobStore.java b/src/main/java/net/glowstone/io/entity/WaterMobStore.java index 213b7b87d0..d153842322 100644 --- a/src/main/java/net/glowstone/io/entity/WaterMobStore.java +++ b/src/main/java/net/glowstone/io/entity/WaterMobStore.java @@ -1,6 +1,6 @@ package net.glowstone.io.entity; -import java.lang.reflect.Constructor; +import java.util.function.Function; import net.glowstone.entity.GlowWaterMob; import net.glowstone.util.nbt.CompoundTag; import org.bukkit.Location; @@ -8,23 +8,24 @@ public class WaterMobStore extends EntityStore { - private final Constructor constructor; + private final Function creator; - public WaterMobStore(Class clazz, EntityType type) { + /** + * Creates the instance for a mob type. + * + * @param clazz the mob type as a class + * @param type the mob type as an {@link EntityType} + * @param creator the mob type's constructor taking a Location + */ + public WaterMobStore(Class clazz, EntityType type, Function creator) { super(clazz, type); - Constructor ctor = null; - try { - ctor = clazz.getConstructor(Location.class); - } catch (Exception e) { - e.printStackTrace(); - } - constructor = ctor; + this.creator = creator; } @Override public T createEntity(Location location, CompoundTag compound) { try { - return constructor.newInstance(location); + return creator.apply(location); } catch (Exception e) { e.printStackTrace(); throw new UnsupportedOperationException("Not implemented yet."); diff --git a/src/main/java/net/glowstone/io/entity/WitherStore.java b/src/main/java/net/glowstone/io/entity/WitherStore.java index beaa34ab3e..7de5e0e49e 100644 --- a/src/main/java/net/glowstone/io/entity/WitherStore.java +++ b/src/main/java/net/glowstone/io/entity/WitherStore.java @@ -7,7 +7,7 @@ public class WitherStore extends MonsterStore { public WitherStore() { - super(GlowWither.class, EntityType.WITHER); + super(GlowWither.class, EntityType.WITHER, GlowWither::new); } @Override diff --git a/src/main/java/net/glowstone/io/entity/WolfStore.java b/src/main/java/net/glowstone/io/entity/WolfStore.java index a5324f6b9f..3bb0278285 100644 --- a/src/main/java/net/glowstone/io/entity/WolfStore.java +++ b/src/main/java/net/glowstone/io/entity/WolfStore.java @@ -8,14 +8,18 @@ class WolfStore extends TameableStore { public WolfStore() { - super(GlowWolf.class, EntityType.WOLF); + super(GlowWolf.class, EntityType.WOLF, GlowWolf::new); } @Override public void load(GlowWolf entity, CompoundTag compound) { super.load(entity, compound); - entity.setCollarColor(DyeColor.getByDyeData(compound.getByte("CollarColor"))); - entity.setAngry(compound.getBool("Angry")); + if (compound.isByte("CollarColor")) { + entity.setCollarColor(DyeColor.getByDyeData(compound.getByte("CollarColor"))); + } + if (compound.isByte("Angry")) { + entity.setAngry(compound.getBool("Angry")); + } } @Override diff --git a/src/main/java/net/glowstone/io/entity/ZombieStore.java b/src/main/java/net/glowstone/io/entity/ZombieStore.java index 8787650325..e9a9463ea7 100644 --- a/src/main/java/net/glowstone/io/entity/ZombieStore.java +++ b/src/main/java/net/glowstone/io/entity/ZombieStore.java @@ -1,17 +1,19 @@ package net.glowstone.io.entity; +import java.util.function.Function; import net.glowstone.entity.monster.GlowZombie; import net.glowstone.util.nbt.CompoundTag; +import org.bukkit.Location; import org.bukkit.entity.EntityType; class ZombieStore extends MonsterStore { public ZombieStore() { - super(GlowZombie.class, EntityType.ZOMBIE); + super(GlowZombie.class, EntityType.ZOMBIE, GlowZombie::new); } - public ZombieStore(Class clazz, EntityType type) { - super(clazz, type); + public ZombieStore(Class clazz, EntityType type, Function creator) { + super(clazz, type, creator); } @Override diff --git a/src/main/java/net/glowstone/io/entity/ZombieVillagerStore.java b/src/main/java/net/glowstone/io/entity/ZombieVillagerStore.java new file mode 100644 index 0000000000..9bfd39b2df --- /dev/null +++ b/src/main/java/net/glowstone/io/entity/ZombieVillagerStore.java @@ -0,0 +1,72 @@ +package net.glowstone.io.entity; + +import static com.google.common.base.Preconditions.checkArgument; +import static net.glowstone.entity.passive.GlowVillager.getRandomProfession; + +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; +import net.glowstone.entity.monster.GlowZombie; +import net.glowstone.entity.monster.GlowZombieVillager; +import net.glowstone.entity.passive.GlowVillager; +import net.glowstone.util.nbt.CompoundTag; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Villager; + +public class ZombieVillagerStore extends ZombieStore { + + private static final Villager.Profession[] PROFESSIONS = Villager.Profession.values(); + + public ZombieVillagerStore() { + super(GlowZombieVillager.class, EntityType.ZOMBIE_VILLAGER, GlowZombieVillager::new); + } + + @Override + public void load(GlowZombie zombie, CompoundTag compound) { + checkArgument(zombie instanceof GlowZombieVillager); + GlowZombieVillager entity = (GlowZombieVillager) zombie; + super.load(entity, compound); + + if (compound.isInt("Profession")) { + int professionId = compound.getInt("Profession"); + if (GlowVillager.isValidProfession(professionId)) { + entity.setVillagerProfession(GlowVillager.getProfessionById(professionId)); + } else { + entity.setVillagerProfession(getRandomProfession(ThreadLocalRandom.current())); + } + } else { + entity.setVillagerProfession(getRandomProfession(ThreadLocalRandom.current())); + } + + if (compound.isInt("ConversionTime")) { + entity.setConversionTime(compound.getInt("ConversionTime")); + } else { + entity.setConversionTime(-1); + } + + if (compound.isLong("ConversionPlayerMost") && compound.isLong("ConversionPlayerLeast")) { + UUID conversionPlayer = new UUID(compound.getLong("ConversionPlayerMost"), + compound.getLong("ConversionPlayerLeast")); + entity.setConversionPlayer(conversionPlayer); + } + } + + @Override + public void save(GlowZombie zombie, CompoundTag compound) { + checkArgument(zombie instanceof GlowZombieVillager); + GlowZombieVillager entity = (GlowZombieVillager) zombie; + super.save(entity, compound); + + final Villager.Profession profession = entity.getVillagerProfession(); + if (profession != null && profession != Villager.Profession.HUSK) { + compound.putInt("Profession", profession.ordinal()); + } + + compound.putInt("ConversionTime", entity.getConversionTime()); + + final UUID conversionPlayer = entity.getConversionPlayer(); + if (conversionPlayer != null) { + compound.putLong("ConversionPlayerMost", conversionPlayer.getMostSignificantBits()); + compound.putLong("ConversionPlayerLeast", conversionPlayer.getLeastSignificantBits()); + } + } +} diff --git a/src/main/java/net/glowstone/io/json/JsonPlayerStatisticIoService.java b/src/main/java/net/glowstone/io/json/JsonPlayerStatisticIoService.java index 7525d1f063..7f1343093e 100644 --- a/src/main/java/net/glowstone/io/json/JsonPlayerStatisticIoService.java +++ b/src/main/java/net/glowstone/io/json/JsonPlayerStatisticIoService.java @@ -25,7 +25,7 @@ public JsonPlayerStatisticIoService(GlowServer server, File statsDir) { } /** - * Gets the statistics file for the given UUID + * Gets the statistics file for the given UUID. * * @param uuid the UUID of the player * @return the statistics file of the given UUID @@ -38,7 +38,8 @@ private File getPlayerFile(UUID uuid) { } /** - * Reads the stats of a player from its statistics file and writes the values to the StatisticMap. + * Reads the stats of a player from its statistics file and writes the values to the + * StatisticMap. * * @param player the player to read the statistics from */ @@ -61,10 +62,14 @@ public void readStatistics(GlowPlayer player) { longValue = (Long) object.get("value"); } } else { - GlowServer.logger.warning("Unknown statistic type for '" + entry.getKey() + "': " + entry.getValue() + " (" + entry.getValue().getClass().getSimpleName() + ")"); + GlowServer.logger.warning(String.format( + "Unknown statistic type for '%s': %s (%s)", + entry.getKey(), entry.getValue(), + entry.getValue().getClass().getSimpleName())); } if (longValue != null) { - player.getStatisticMap().getValues().put(entry.getKey(), longValue.intValue()); + player.getStatisticMap().getValues() + .put(entry.getKey(), longValue.intValue()); } } } catch (ParseException | IOException e) { diff --git a/src/main/java/net/glowstone/io/nbt/NbtPlayerDataService.java b/src/main/java/net/glowstone/io/nbt/NbtPlayerDataService.java index c544778cf8..21369137fa 100644 --- a/src/main/java/net/glowstone/io/nbt/NbtPlayerDataService.java +++ b/src/main/java/net/glowstone/io/nbt/NbtPlayerDataService.java @@ -18,8 +18,8 @@ import net.glowstone.io.PlayerDataService; import net.glowstone.io.entity.EntityStorage; import net.glowstone.util.nbt.CompoundTag; -import net.glowstone.util.nbt.NBTInputStream; -import net.glowstone.util.nbt.NBTOutputStream; +import net.glowstone.util.nbt.NbtInputStream; +import net.glowstone.util.nbt.NbtOutputStream; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.World; @@ -76,11 +76,11 @@ public CompletableFuture> getOfflinePlayers() { futures.add(GlowOfflinePlayer.getOfflinePlayer(server, uuid)); } - CompletableFuture gotAll = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])); + CompletableFuture gotAll = CompletableFuture.allOf(futures.toArray( + new CompletableFuture[futures.size()])); - return gotAll.thenApplyAsync((v) -> { - return futures.stream().map((f) -> f.join()).collect(Collectors.toList()); - }); + return gotAll.thenApplyAsync((v) -> + futures.stream().map((f) -> f.join()).collect(Collectors.toList())); } @Override @@ -93,7 +93,7 @@ public void readData(GlowPlayer player) { File playerFile = getPlayerFile(player.getUniqueId()); CompoundTag playerTag = new CompoundTag(); if (playerFile.exists()) { - try (NBTInputStream in = new NBTInputStream(new FileInputStream(playerFile))) { + try (NbtInputStream in = new NbtInputStream(new FileInputStream(playerFile))) { playerTag = in.readCompound(); } catch (IOException e) { player.kickPlayer("Failed to read player data!"); @@ -109,7 +109,7 @@ public void writeData(GlowPlayer player) { File playerFile = getPlayerFile(player.getUniqueId()); CompoundTag tag = new CompoundTag(); EntityStorage.save(player, tag); - try (NBTOutputStream out = new NBTOutputStream(new FileOutputStream(playerFile))) { + try (NbtOutputStream out = new NbtOutputStream(new FileOutputStream(playerFile))) { out.writeTag(tag); } catch (IOException e) { player.kickPlayer("Failed to save player data!"); @@ -125,7 +125,7 @@ private class NbtPlayerReader implements PlayerReader { public NbtPlayerReader(File playerFile) { if (playerFile.exists()) { - try (NBTInputStream in = new NBTInputStream(new FileInputStream(playerFile))) { + try (NbtInputStream in = new NbtInputStream(new FileInputStream(playerFile))) { tag = in.readCompound(); hasPlayed = true; } catch (IOException e) { diff --git a/src/main/java/net/glowstone/io/nbt/NbtScoreboardIoService.java b/src/main/java/net/glowstone/io/nbt/NbtScoreboardIoService.java index 8e332bf35f..b37d4ca9a7 100644 --- a/src/main/java/net/glowstone/io/nbt/NbtScoreboardIoService.java +++ b/src/main/java/net/glowstone/io/nbt/NbtScoreboardIoService.java @@ -9,13 +9,14 @@ import net.glowstone.scoreboard.NbtScoreboardIoWriter; /** - * An implementation of the {@link ScoreboardIoService} which reads and writes scoreboards in NBT form + * An implementation of the {@link ScoreboardIoService} which reads and writes scoreboards in NBT + * form. */ public final class NbtScoreboardIoService implements ScoreboardIoService { private static final String SCOREBOARD_SAVE_FILE = "scoreboard.dat"; /** - * The root directory of the scoreboard + * The root directory of the scoreboard. */ private final File dir; private final GlowServer server; diff --git a/src/main/java/net/glowstone/io/nbt/NbtSerialization.java b/src/main/java/net/glowstone/io/nbt/NbtSerialization.java index 8d25ebed17..df5f7d2447 100644 --- a/src/main/java/net/glowstone/io/nbt/NbtSerialization.java +++ b/src/main/java/net/glowstone/io/nbt/NbtSerialization.java @@ -138,9 +138,9 @@ public static World readWorld(GlowServer server, CompoundTag compound) { } if (world == null && compound.isInt("Dimension")) { int dim = compound.getInt("Dimension"); - for (World sWorld : server.getWorlds()) { - if (sWorld.getEnvironment().getId() == dim) { - world = sWorld; + for (World serverWorld : server.getWorlds()) { + if (serverWorld.getEnvironment().getId() == dim) { + world = serverWorld; break; } } @@ -155,10 +155,10 @@ public static World readWorld(GlowServer server, CompoundTag compound) { * @param compound The tag to write to. */ public static void writeWorld(World world, CompoundTag compound) { - UUID worldUUID = world.getUID(); + UUID worldUuid = world.getUID(); // world UUID used by Bukkit and code above - compound.putLong("WorldUUIDMost", worldUUID.getMostSignificantBits()); - compound.putLong("WorldUUIDLeast", worldUUID.getLeastSignificantBits()); + compound.putLong("WorldUUIDMost", worldUuid.getMostSignificantBits()); + compound.putLong("WorldUUIDLeast", worldUuid.getLeastSignificantBits()); // leave a Dimension value for possible Vanilla use compound.putInt("Dimension", world.getEnvironment().getId()); } @@ -167,7 +167,9 @@ public static void writeWorld(World world, CompoundTag compound) { * Read a Location from the "Pos" and "Rotation" children of a tag. * *

If "Pos" is absent or invalid, null is returned. - *

If "Rotation" is absent or invalid, it is skipped and a location without rotation is returned. + * + *

If "Rotation" is absent or invalid, it is skipped and a location without rotation is + * returned. * * @param world The world of the location (see readWorld). * @param tag The tag to read from. diff --git a/src/main/java/net/glowstone/io/nbt/NbtStructureDataService.java b/src/main/java/net/glowstone/io/nbt/NbtStructureDataService.java index 8c179a13be..8092080e47 100644 --- a/src/main/java/net/glowstone/io/nbt/NbtStructureDataService.java +++ b/src/main/java/net/glowstone/io/nbt/NbtStructureDataService.java @@ -15,8 +15,8 @@ import net.glowstone.io.structure.StructureStorage; import net.glowstone.io.structure.StructureStore; import net.glowstone.util.nbt.CompoundTag; -import net.glowstone.util.nbt.NBTInputStream; -import net.glowstone.util.nbt.NBTOutputStream; +import net.glowstone.util.nbt.NbtInputStream; +import net.glowstone.util.nbt.NbtOutputStream; import org.bukkit.Bukkit; public class NbtStructureDataService implements StructureDataService { @@ -25,6 +25,12 @@ public class NbtStructureDataService implements StructureDataService { private final File structureDir; private final GlowServer server; + /** + * Creates the instance for the given world's structures. + * + * @param world the world + * @param structureDir the world's structure-data folder, which is created if it doesn't exist + */ public NbtStructureDataService(GlowWorld world, File structureDir) { this.world = world; this.structureDir = structureDir; @@ -41,7 +47,7 @@ public Map readStructuresData() { for (StructureStore store : StructureStorage.getStructureStores()) { File structureFile = new File(structureDir, store.getId() + ".dat"); if (structureFile.exists()) { - try (NBTInputStream in = new NBTInputStream(new FileInputStream(structureFile))) { + try (NbtInputStream in = new NbtInputStream(new FileInputStream(structureFile))) { CompoundTag data = new CompoundTag(); data = in.readCompound(); if (data.isCompound("data")) { @@ -74,7 +80,6 @@ public Map readStructuresData() { public void writeStructuresData(Map structures) { for (GlowStructure structure : structures.values()) { if (structure.isDirty()) { - CompoundTag root = new CompoundTag(); CompoundTag data = new CompoundTag(); CompoundTag features = new CompoundTag(); CompoundTag feature = new CompoundTag(); @@ -82,7 +87,7 @@ public void writeStructuresData(Map structures) { .saveStructure(structure, feature); File structureFile = new File(structureDir, store.getId() + ".dat"); if (structureFile.exists()) { - try (NBTInputStream in = new NBTInputStream( + try (NbtInputStream in = new NbtInputStream( new FileInputStream(structureFile))) { data = new CompoundTag(); data = in.readCompound(); @@ -100,8 +105,9 @@ public void writeStructuresData(Map structures) { String key = "[" + structure.getChunkX() + "," + structure.getChunkZ() + "]"; features.putCompound(key, feature); data.putCompound("Features", features); + CompoundTag root = new CompoundTag(); root.putCompound("data", data); - try (NBTOutputStream nbtOut = new NBTOutputStream( + try (NbtOutputStream nbtOut = new NbtOutputStream( new FileOutputStream(structureFile))) { nbtOut.writeTag(root); } catch (IOException e) { diff --git a/src/main/java/net/glowstone/io/nbt/NbtWorldMetadataService.java b/src/main/java/net/glowstone/io/nbt/NbtWorldMetadataService.java index aedcaf06b1..217b516bb5 100644 --- a/src/main/java/net/glowstone/io/nbt/NbtWorldMetadataService.java +++ b/src/main/java/net/glowstone/io/nbt/NbtWorldMetadataService.java @@ -13,8 +13,8 @@ import net.glowstone.GlowWorld; import net.glowstone.io.WorldMetadataService; import net.glowstone.util.nbt.CompoundTag; -import net.glowstone.util.nbt.NBTInputStream; -import net.glowstone.util.nbt.NBTOutputStream; +import net.glowstone.util.nbt.NbtInputStream; +import net.glowstone.util.nbt.NbtOutputStream; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.WorldType; @@ -27,6 +27,13 @@ public class NbtWorldMetadataService implements WorldMetadataService { private CompoundTag unknownTags; + /** + * Creates the instance for the given world's metadata. + * + * @param world the world + * @param dir the world's metadata folder, containing uid.dat and level.dat if the world has + * been previously saved; if this folder doesn't exist, it is created + */ public NbtWorldMetadataService(GlowWorld world, File dir) { this.world = world; this.dir = dir; @@ -57,7 +64,7 @@ public WorldFinalValues readWorldData() { CompoundTag level = new CompoundTag(); File levelFile = new File(dir, "level.dat"); if (levelFile.exists()) { - try (NBTInputStream in = new NBTInputStream(new FileInputStream(levelFile))) { + try (NbtInputStream in = new NbtInputStream(new FileInputStream(levelFile))) { level = in.readCompound(); if (level.isCompound("Data")) { level = level.getCompound("Data"); @@ -241,7 +248,7 @@ public void writeWorldData() throws IOException { CompoundTag root = new CompoundTag(); root.putCompound("Data", out); - try (NBTOutputStream nbtOut = new NBTOutputStream( + try (NbtOutputStream nbtOut = new NbtOutputStream( new FileOutputStream(new File(dir, "level.dat")))) { nbtOut.writeTag(root); } catch (IOException e) { diff --git a/src/main/java/net/glowstone/io/structure/StructurePieceStorage.java b/src/main/java/net/glowstone/io/structure/StructurePieceStorage.java index ef0bfd14c3..c0d490523a 100644 --- a/src/main/java/net/glowstone/io/structure/StructurePieceStorage.java +++ b/src/main/java/net/glowstone/io/structure/StructurePieceStorage.java @@ -8,7 +8,8 @@ import net.glowstone.util.nbt.CompoundTag; /** - * The class responsible for mapping structure piece types to their storage methods and reading and writing structure piece data using those storage methods. + * The class responsible for mapping structure piece types to their storage methods and reading and + * writing structure piece data using those storage methods. */ public final class StructurePieceStorage { @@ -23,7 +24,8 @@ public final class StructurePieceStorage { * *

This is generally used to map structure pieces being stored. */ - private static final Map, StructurePieceStore> classTable = new HashMap<>(); + private static final Map, StructurePieceStore> classTable + = new HashMap<>(); /* * Populates the maps with stores. @@ -63,7 +65,8 @@ public static GlowStructurePiece loadStructurePiece(CompoundTag compound) { StructurePieceStore store = idTable.get(compound.getString("id")); if (store == null) { GlowServer.logger.severe(MessageFormat - .format("Unknown structure piece type to load: \"{0}\"", compound.getString("id"))); + .format("Unknown structure piece type to load: \"{0}\"", compound + .getString("id"))); return null; } @@ -81,7 +84,7 @@ public static void saveStructurePiece(GlowStructurePiece structurePiece, Compoun StructurePieceStore store = classTable.get(structurePiece.getClass()); if (store == null) { throw new IllegalArgumentException( - "Unknown structure piece type to save: \"" + structurePiece.getClass() + "\""); + "Unknown structure piece type to save: \"" + structurePiece.getClass() + "\""); } compound.putString("id", store.getId()); @@ -93,7 +96,7 @@ public static void saveStructurePiece(GlowStructurePiece structurePiece, Compoun * Helper method to call StructurePieceStore methods for type safety. */ private static T createStructurePiece( - StructurePieceStore store, CompoundTag compound) { + StructurePieceStore store, CompoundTag compound) { T structurePiece = store.createStructurePiece(); store.load(structurePiece, compound); return structurePiece; @@ -104,7 +107,7 @@ private static T createStructurePiece( */ @SuppressWarnings("unchecked") private static StructurePieceStore getBaseStore( - StructurePieceStore store) { + StructurePieceStore store) { return (StructurePieceStore) store; } } diff --git a/src/main/java/net/glowstone/io/structure/StructurePieceStore.java b/src/main/java/net/glowstone/io/structure/StructurePieceStore.java index 23d2f67859..28bb873b68 100644 --- a/src/main/java/net/glowstone/io/structure/StructurePieceStore.java +++ b/src/main/java/net/glowstone/io/structure/StructurePieceStore.java @@ -1,5 +1,6 @@ package net.glowstone.io.structure; +import lombok.Data; import net.glowstone.generator.structures.GlowStructurePiece; import net.glowstone.generator.structures.util.StructureBoundingBox; import net.glowstone.util.nbt.CompoundTag; @@ -10,23 +11,11 @@ * * @param The type of structure piece being stored. */ +@Data public abstract class StructurePieceStore { + private final Class type; private final String id; - private final Class clazz; - - public StructurePieceStore(Class clazz, String id) { - this.id = id; - this.clazz = clazz; - } - - public final String getId() { - return id; - } - - public final Class getType() { - return clazz; - } /** * Create a structure piece of this store's type. @@ -45,7 +34,7 @@ public final Class getType() { */ public void load(T structurePiece, CompoundTag compound) { if (compound.isInt("GD")) { - structurePiece.setGD(compound.getInt("GD")); + structurePiece.setUnknownGd(compound.getInt("GD")); } if (compound.isInt("O")) { structurePiece.setNumericOrientation(compound.getInt("O")); @@ -67,7 +56,7 @@ public void load(T structurePiece, CompoundTag compound) { * @param compound The target tag. */ public void save(T structurePiece, CompoundTag compound) { - compound.putInt("GD", structurePiece.getGD()); + compound.putInt("GD", structurePiece.getUnknownGd()); compound.putInt("O", structurePiece.getNumericOrientation()); StructureBoundingBox boundingBox = structurePiece.getBoundingBox(); int[] bb = new int[6]; diff --git a/src/main/java/net/glowstone/io/structure/StructureStorage.java b/src/main/java/net/glowstone/io/structure/StructureStorage.java index 3fb382d18c..3d46065fc3 100644 --- a/src/main/java/net/glowstone/io/structure/StructureStorage.java +++ b/src/main/java/net/glowstone/io/structure/StructureStorage.java @@ -9,18 +9,22 @@ import net.glowstone.util.nbt.CompoundTag; /** - * The class responsible for mapping structure types to their storage methods and reading and writing structure data using those storage methods. + * The class responsible for mapping structure types to their storage methods and reading and + * writing structure data using those storage methods. */ public final class StructureStorage { /** - * A table which maps structure ids to compound readers. This is generally used to map stored structures to actual structures. + * A table which maps structure ids to compound readers. This is generally used to map stored + * structures to actual structures. */ private static final Map> idTable = new HashMap<>(); /** - * A table which maps structures to stores. This is generally used to map structures being stored. + * A table which maps structures to stores. This is generally used to map structures being + * stored. */ - private static final Map, StructureStore> classTable = new HashMap<>(); + private static final Map, StructureStore> classTable + = new HashMap<>(); /* * Populates the maps with stores. @@ -71,10 +75,11 @@ public static GlowStructure loadStructure(GlowWorld world, CompoundTag compound) StructureStore store = idTable.get(compound.getString("id")); if (store == null) { throw new IllegalArgumentException( - "Unknown structure type: \"" + compound.getString("id") + "\""); + "Unknown structure type: \"" + compound.getString("id") + "\""); } - int x = 0, z = 0; + int x = 0; + int z = 0; if (compound.isInt("ChunkX")) { x = compound.getInt("ChunkX"); } @@ -93,12 +98,12 @@ public static GlowStructure loadStructure(GlowWorld world, CompoundTag compound) * @return The structure store for the saved structure. */ public static StructureStore saveStructure(GlowStructure structure, - CompoundTag compound) { + CompoundTag compound) { // look up the store for the structure StructureStore store = classTable.get(structure.getClass()); if (store == null) { throw new IllegalArgumentException( - "Unknown structure type to save: \"" + structure.getClass() + "\""); + "Unknown structure type to save: \"" + structure.getClass() + "\""); } compound.putString("id", store.getId()); @@ -115,7 +120,7 @@ public static StructureStore saveStructure(GlowStructure structur * Helper method to call StructureStore methods for type safety. */ private static T createStructure(GlowWorld world, int chunkX, - int chunkZ, StructureStore store, CompoundTag compound) { + int chunkZ, StructureStore store, CompoundTag compound) { T structure = store.createStructure(world, chunkX, chunkZ); store.load(structure, compound); return structure; diff --git a/src/main/java/net/glowstone/io/structure/StructureStore.java b/src/main/java/net/glowstone/io/structure/StructureStore.java index 9c0014c47c..8897de0c9c 100644 --- a/src/main/java/net/glowstone/io/structure/StructureStore.java +++ b/src/main/java/net/glowstone/io/structure/StructureStore.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; +import lombok.Data; import net.glowstone.GlowWorld; import net.glowstone.generator.structures.GlowStructure; import net.glowstone.generator.structures.GlowStructurePiece; @@ -16,26 +17,15 @@ * * @param The type of structure being stored. */ +@Data public abstract class StructureStore { + private final Class type; private final String id; - private final Class clazz; - - public StructureStore(Class clazz, String id) { - this.id = id; - this.clazz = clazz; - } - - public final String getId() { - return id; - } - - public final Class getType() { - return clazz; - } /** - * Create a structure of this store's type in the given world. The load method will be called separately. + * Create a structure of this store's type in the given world. The load method will be called + * separately. * * @param world The target world. * @param chunkX The structure chunk X. @@ -45,7 +35,8 @@ public final Class getType() { public abstract T createStructure(GlowWorld world, int chunkX, int chunkZ); /** - * Create a new structure of this store's type in the given world. The load method will be called separately. + * Create a new structure of this store's type in the given world. The load method will be + * called separately. * * @param world The target world. * @param random The seeded random. @@ -66,7 +57,7 @@ public void load(T structure, CompoundTag compound) { int[] bb = compound.getIntArray("BB"); if (bb.length == 6) { StructureBoundingBox boundingBox = new StructureBoundingBox( - new Vector(bb[0], bb[1], bb[2]), new Vector(bb[3], bb[4], bb[5])); + new Vector(bb[0], bb[1], bb[2]), new Vector(bb[3], bb[4], bb[5])); structure.setBoundingBox(boundingBox); } } diff --git a/src/main/java/net/glowstone/io/structure/TemplePieceStore.java b/src/main/java/net/glowstone/io/structure/TemplePieceStore.java index d425c087b0..fe8a8c5186 100644 --- a/src/main/java/net/glowstone/io/structure/TemplePieceStore.java +++ b/src/main/java/net/glowstone/io/structure/TemplePieceStore.java @@ -23,7 +23,7 @@ public void load(T structurePiece, CompoundTag compound) { structurePiece.setDepth(compound.getInt("Depth")); } if (compound.isInt("HPos")) { - structurePiece.setHPos(compound.getInt("HPos")); + structurePiece.setHorizPos(compound.getInt("HPos")); } } @@ -34,6 +34,6 @@ public void save(T structurePiece, CompoundTag compound) { compound.putInt("Width", structurePiece.getWidth()); compound.putInt("Height", structurePiece.getHeight()); compound.putInt("Depth", structurePiece.getDepth()); - compound.putInt("HPos", structurePiece.getHPos()); + compound.putInt("HPos", structurePiece.getHorizPos()); } } diff --git a/src/main/java/net/glowstone/map/GlowMapCanvas.java b/src/main/java/net/glowstone/map/GlowMapCanvas.java index 7836d4a00c..38c65d4a1d 100644 --- a/src/main/java/net/glowstone/map/GlowMapCanvas.java +++ b/src/main/java/net/glowstone/map/GlowMapCanvas.java @@ -1,6 +1,9 @@ package net.glowstone.map; import java.awt.Image; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; import net.glowstone.net.message.play.game.MapDataMessage.Section; import org.bukkit.entity.Player; import org.bukkit.map.MapCanvas; @@ -16,8 +19,12 @@ public final class GlowMapCanvas implements MapCanvas { public static final int MAP_SIZE = 128; + @Getter(AccessLevel.PROTECTED) private final byte[] buffer = new byte[MAP_SIZE * MAP_SIZE]; + @Getter private final MapView mapView; + @Getter + @Setter private MapCursorCollection cursors = new MapCursorCollection(); private byte[] base; @@ -51,21 +58,6 @@ public void update(Player player) { } } - @Override - public MapView getMapView() { - return mapView; - } - - @Override - public MapCursorCollection getCursors() { - return cursors; - } - - @Override - public void setCursors(MapCursorCollection cursors) { - this.cursors = cursors; - } - @Override public void setPixel(int x, int y, byte color) { if (x < 0 || y < 0 || x >= MAP_SIZE || y >= MAP_SIZE) { @@ -97,10 +89,6 @@ protected void setBase(byte... base) { this.base = base; } - protected byte[] getBuffer() { - return buffer; - } - @Override public void drawImage(int x, int y, Image image) { throw new UnsupportedOperationException("Not supported yet."); diff --git a/src/main/java/net/glowstone/map/GlowMapView.java b/src/main/java/net/glowstone/map/GlowMapView.java index a267c0b77a..86725287cb 100644 --- a/src/main/java/net/glowstone/map/GlowMapView.java +++ b/src/main/java/net/glowstone/map/GlowMapView.java @@ -61,6 +61,7 @@ public void setScale(Scale scale) { @Override public List getRenderers() { + // TODO: Defensive copy return renderers; } diff --git a/src/main/java/net/glowstone/net/GameServer.java b/src/main/java/net/glowstone/net/GameServer.java index 38428c9216..27b69116d9 100644 --- a/src/main/java/net/glowstone/net/GameServer.java +++ b/src/main/java/net/glowstone/net/GameServer.java @@ -18,8 +18,10 @@ public GameServer(GlowServer server, CountDownLatch latch) { bootstrap.childHandler(new GlowChannelInitializer(this)); } + @Override public ChannelFuture bind(InetSocketAddress address) { - GlowServer.logger.info("Binding server to " + address + "..."); + GlowServer.logger.info("Binding server to " + + address.getAddress().getHostAddress() + ":" + address.getPort() + "..."); return super.bind(address); } @@ -27,22 +29,24 @@ public ChannelFuture bind(InetSocketAddress address) { public void onBindSuccess(InetSocketAddress address) { getServer().setPort(address.getPort()); getServer().setIp(address.getHostString()); - GlowServer.logger.info("Successfully bound server to " + address + '.'); + GlowServer.logger.info("Successfully bound server to " + + address.getAddress().getHostAddress() + ":" + address.getPort() + '.'); super.onBindSuccess(address); } @Override public void onBindFailure(InetSocketAddress address, Throwable t) { - GlowServer.logger.severe("Failed to bind server to " + address + '.'); + GlowServer.logger.severe("Failed to bind server to " + + address.getAddress().getHostAddress() + ":" + address.getPort() + '.'); if (t.getMessage().contains("Cannot assign requested address")) { GlowServer.logger.severe("The 'server.ip' in your configuration may not be valid."); GlowServer.logger.severe("Unless you are sure you need it, try removing it."); - GlowServer.logger.severe(t.getLocalizedMessage()); + GlowServer.logger.severe(t.getMessage()); } else if (t.getMessage().contains("Address already in use")) { GlowServer.logger.severe("The address was already in use. Check that no server is"); GlowServer.logger.severe("already running on that port. If needed, try killing all"); GlowServer.logger.severe("Java processes using Task Manager or similar."); - GlowServer.logger.severe(t.getLocalizedMessage()); + GlowServer.logger.severe(t.getMessage()); } else { GlowServer.logger.log(Level.SEVERE, "An unknown bind error has occurred.", t); } diff --git a/src/main/java/net/glowstone/net/GlowBufUtils.java b/src/main/java/net/glowstone/net/GlowBufUtils.java index 4cc0994e42..f41c4030d3 100644 --- a/src/main/java/net/glowstone/net/GlowBufUtils.java +++ b/src/main/java/net/glowstone/net/GlowBufUtils.java @@ -19,9 +19,9 @@ import net.glowstone.util.Position; import net.glowstone.util.TextMessage; import net.glowstone.util.nbt.CompoundTag; -import net.glowstone.util.nbt.NBTInputStream; -import net.glowstone.util.nbt.NBTOutputStream; -import net.glowstone.util.nbt.NBTReadLimiter; +import net.glowstone.util.nbt.NbtInputStream; +import net.glowstone.util.nbt.NbtOutputStream; +import net.glowstone.util.nbt.NbtReadLimiter; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.util.BlockVector; @@ -197,9 +197,9 @@ private static CompoundTag readCompound(ByteBuf buf, boolean network) { } buf.readerIndex(idx); - try (NBTInputStream str = new NBTInputStream(new ByteBufInputStream(buf), false)) { + try (NbtInputStream str = new NbtInputStream(new ByteBufInputStream(buf), false)) { return str.readCompound( - network ? new NBTReadLimiter(2097152L) : NBTReadLimiter.UNLIMITED); + network ? new NbtReadLimiter(2097152L) : NbtReadLimiter.UNLIMITED); } catch (IOException e) { return null; } @@ -218,7 +218,7 @@ public static void writeCompound(ByteBuf buf, CompoundTag data) { } ByteArrayOutputStream out = new ByteArrayOutputStream(); - try (NBTOutputStream str = new NBTOutputStream(out, false)) { + try (NbtOutputStream str = new NbtOutputStream(out, false)) { str.writeTag(data); } catch (IOException e) { GlowServer.logger.log(Level.WARNING, "Error serializing NBT: " + data, e); diff --git a/src/main/java/net/glowstone/net/GlowDatagramServer.java b/src/main/java/net/glowstone/net/GlowDatagramServer.java index 7c88a05445..aa1caa5f33 100644 --- a/src/main/java/net/glowstone/net/GlowDatagramServer.java +++ b/src/main/java/net/glowstone/net/GlowDatagramServer.java @@ -48,6 +48,7 @@ public ChannelFuture bind(InetSocketAddress address) { }); } + @Override public void shutdown() { bootstrap.config().group().shutdownGracefully(); } diff --git a/src/main/java/net/glowstone/net/GlowNetworkServer.java b/src/main/java/net/glowstone/net/GlowNetworkServer.java index b9c19a1778..89fd844f39 100644 --- a/src/main/java/net/glowstone/net/GlowNetworkServer.java +++ b/src/main/java/net/glowstone/net/GlowNetworkServer.java @@ -3,18 +3,27 @@ import io.netty.channel.ChannelFuture; import java.net.InetSocketAddress; import java.util.concurrent.CountDownLatch; +import lombok.Getter; import net.glowstone.GlowServer; /** * Represents a network server. * - * Modified implementation of {@link com.flowpowered.network.NetworkServer}. + *

Modified implementation of {@link com.flowpowered.network.NetworkServer}. */ public abstract class GlowNetworkServer { + @Getter private final GlowServer server; protected CountDownLatch latch; + /** + * Creates an instance for the specified server. + * + * @param server the associated GlowServer + * @param latch The countdown latch used during server startup to wait for network server + * binding. + */ public GlowNetworkServer(GlowServer server, CountDownLatch latch) { this.server = server; this.latch = latch; @@ -22,10 +31,6 @@ public GlowNetworkServer(GlowServer server, CountDownLatch latch) { public abstract ChannelFuture bind(InetSocketAddress address); - public GlowServer getServer() { - return server; - } - public void onBindSuccess(InetSocketAddress address) { latch.countDown(); } diff --git a/src/main/java/net/glowstone/net/GlowSession.java b/src/main/java/net/glowstone/net/GlowSession.java index 0b02383902..41d35fd9fb 100644 --- a/src/main/java/net/glowstone/net/GlowSession.java +++ b/src/main/java/net/glowstone/net/GlowSession.java @@ -20,6 +20,7 @@ import java.util.logging.Level; import javax.crypto.SecretKey; import lombok.Getter; +import lombok.Setter; import net.glowstone.EventFactory; import net.glowstone.GlowServer; import net.glowstone.entity.GlowPlayer; @@ -56,7 +57,10 @@ public class GlowSession extends BasicSession { /** * The server this session belongs to. + * + * @return The server. */ + @Getter private final GlowServer server; /** @@ -72,26 +76,39 @@ public class GlowSession extends BasicSession { /** * The remote address of the connection. */ + @Getter private InetSocketAddress address; /** - * The state of the connection + * The state of the connection. + * + * @return true if this session's state is online */ + @Getter private boolean online; /** - * The verify token used in authentication + * The randomly-generated verify token used in authentication for this session. + * + * @param verifyToken the verify token + * @return The verify token */ + @Getter + @Setter private byte[] verifyToken; /** - * The verify username used in authentication + * The verify username used in authentication. */ + @Getter + @Setter private String verifyUsername; /** - * The hostname used to connect. + * The hostname/port the player used to connect to the server. */ - private String hostname; + @Getter + @Setter + private InetSocketAddress virtualHost; /** * The version used to connect. @@ -100,17 +117,22 @@ public class GlowSession extends BasicSession { private int version = -1; /** - * Data regarding a user who has connected through a proxy, - * used to provide online-mode UUID and properties and - * other data even if the server is running in offline mode. + * Data regarding a user who has connected through a proxy, used to provide online-mode UUID and + * properties and other data even if the server is running in offline mode. * *

Null for non-proxied sessions. + * + * @return The proxy data to use, or null for an unproxied connection. */ + @Getter private ProxyData proxyData; /** * The player associated with this session (if there is one). + * + * @return The player, or {@code null} if no player is associated with this session. */ + @Getter private GlowPlayer player; /** @@ -124,12 +146,12 @@ public class GlowSession extends BasicSession { private int previousPlacementTicks; /** - * If the connection has been disconnected + * If the connection has been disconnected. */ private boolean disconnected; /** - * If compression packet has been sent + * If compression packet has been sent. */ private boolean compresssionSent; @@ -138,7 +160,8 @@ public class GlowSession extends BasicSession { * * @param server The server this session belongs to. * @param channel The channel associated with this session. - * @param connectionManager The connection manager to manage connections for this session. + * @param connectionManager The connection manager to manage connections for this + * session. */ public GlowSession(GlowServer server, Channel channel, ConnectionManager connectionManager) { super(channel, ProtocolType.HANDSHAKE.getProtocol()); @@ -147,63 +170,9 @@ public GlowSession(GlowServer server, Channel channel, ConnectionManager connect address = super.getAddress(); } - /** - * Gets the server associated with this session. - * - * @return The server. - */ - public GlowServer getServer() { - return server; - } - //////////////////////////////////////////////////////////////////////////// // Auxiliary state - /** - * Get the randomly-generated verify token for this session. - * - * @return The verify token - */ - public byte[] getVerifyToken() { - return verifyToken; - } - - /** - * Sets the verify token of this session. - * - * @param verifyToken The verify token. - */ - public void setVerifyToken(byte... verifyToken) { - this.verifyToken = verifyToken; - } - - /** - * Gets the verify username for this session. - * - * @return The verify username. - */ - public String getVerifyUsername() { - return verifyUsername; - } - - /** - * Sets the verify username for this session. - * - * @param verifyUsername The verify username. - */ - public void setVerifyUsername(String verifyUsername) { - this.verifyUsername = verifyUsername; - } - - /** - * Get the {@link ProxyData} for this session if available. - * - * @return The proxy data to use, or null for an unproxied connection. - */ - public ProxyData getProxyData() { - return proxyData; - } - /** * Set the {@link ProxyData} for this session. * @@ -212,18 +181,16 @@ public ProxyData getProxyData() { public void setProxyData(ProxyData proxyData) { this.proxyData = proxyData; address = proxyData.getAddress(); - hostname = proxyData.getHostname(); + virtualHost = InetSocketAddress.createUnresolved( + proxyData.getHostname(), virtualHost.getPort()); } /** - * Set the hostname the player used to connect to the server. + * Sets the version. Must only be called once. * - * @param hostname Hostname in "addr:port" format. + * @param version the version + * @throws IllegalStateException if the version has already been set */ - public void setHostname(String hostname) { - this.hostname = hostname; - } - public void setVersion(int version) { if (this.version != -1) { throw new IllegalStateException("Cannot set version twice"); @@ -254,37 +221,15 @@ public void pong(long pingId) { } } - @Override - public InetSocketAddress getAddress() { - return address; - } - //////////////////////////////////////////////////////////////////////////// // Player and state management - /** - * Get session online state - * - * @return true if this session's state is online - */ - public boolean isOnline() { - return online; - } - - /** - * Gets the player associated with this session. - * - * @return The player, or {@code null} if no player is associated with it. - */ - public GlowPlayer getPlayer() { - return player; - } - /** * Sets the player associated with this session. * * @param profile The player's profile with name and UUID information. - * @throws IllegalStateException if there is already a player associated with this session. + * @throws IllegalStateException if there is already a player associated with this + * session. */ public void setPlayer(PlayerProfile profile) { if (player != null) { @@ -319,7 +264,7 @@ public void setPlayer(PlayerProfile profile) { } // login event - PlayerLoginEvent event = EventFactory.onPlayerLogin(player, hostname); + PlayerLoginEvent event = EventFactory.onPlayerLogin(player, virtualHost.toString()); if (event.getResult() != Result.ALLOWED) { disconnect(event.getKickMessage(), true); return; @@ -332,7 +277,8 @@ public void setPlayer(PlayerProfile profile) { online = true; - GlowServer.logger.info(player.getName() + " [" + address + "] connected, UUID: " + player.getUniqueId()); + GlowServer.logger.info(player.getName() + " [" + address + "] connected, UUID: " + player + .getUniqueId()); // message and user list String message = EventFactory.onPlayerJoin(player).getJoinMessage(); @@ -410,7 +356,8 @@ public void disconnect(String reason, boolean overrideKick) { } // perform the kick, sending a kick message if possible - if (isActive() && (getProtocol() instanceof LoginProtocol || getProtocol() instanceof PlayProtocol)) { + if (isActive() && (getProtocol() instanceof LoginProtocol + || getProtocol() instanceof PlayProtocol)) { // channel is both currently connected and in a protocol state allowing kicks ChannelFuture future = sendWithFuture(new KickMessage(reason)); if (future != null) { @@ -485,7 +432,8 @@ void pulse() { if (!other.canSee(player)) { continue; } - other.getSession().send(new DestroyEntitiesMessage(Collections.singletonList(player.getEntityId()))); + other.getSession().send(new DestroyEntitiesMessage(Collections + .singletonList(player.getEntityId()))); } player = null; // in case we are disposed twice } @@ -506,6 +454,11 @@ private void finalizeLogin(PlayerProfile profile) { //////////////////////////////////////////////////////////////////////////// // Pipeline management + /** + * Sets the protocol for this session. + * + * @param protocol the new protocol + */ public void setProtocol(ProtocolType protocol) { getChannel().flush(); @@ -514,10 +467,20 @@ public void setProtocol(ProtocolType protocol) { setProtocol(proto); } + /** + * Enables encryption or changes the session key. + * + * @param sharedSecret the new session key + */ public void enableEncryption(SecretKey sharedSecret) { updatePipeline("encryption", new EncryptionHandler(sharedSecret)); } + /** + * Enables compression if not already enabled. + * + * @param threshold the minimum message size in bytes to compress + */ public void enableCompression(int threshold) { // set compression can only be sent once if (!compresssionSent) { @@ -575,7 +538,9 @@ public void onOutboundThrowable(Throwable t) { public void onHandlerThrowable(Message message, MessageHandler handle, Throwable t) { //TODO disconnect on error // can be safely logged and the connection maintained - GlowServer.logger.log(Level.SEVERE, "Error while handling " + message + " (handler: " + handle.getClass().getSimpleName() + ")", t); + GlowServer.logger.log(Level.SEVERE, + "Error while handling " + message + " (handler: " + handle.getClass() + .getSimpleName() + ")", t); } @Override diff --git a/src/main/java/net/glowstone/net/GlowSocketServer.java b/src/main/java/net/glowstone/net/GlowSocketServer.java index ba91a98f2f..a2953e0965 100644 --- a/src/main/java/net/glowstone/net/GlowSocketServer.java +++ b/src/main/java/net/glowstone/net/GlowSocketServer.java @@ -12,6 +12,7 @@ import io.netty.channel.socket.nio.NioServerSocketChannel; import java.net.InetSocketAddress; import java.util.concurrent.CountDownLatch; +import lombok.Getter; import net.glowstone.GlowServer; public abstract class GlowSocketServer extends GlowNetworkServer { @@ -19,8 +20,16 @@ public abstract class GlowSocketServer extends GlowNetworkServer { protected final EventLoopGroup bossGroup; protected final EventLoopGroup workerGroup; protected final ServerBootstrap bootstrap; + @Getter protected Channel channel; + /** + * Creates an instance for the specified server. + * + * @param server the associated GlowServer + * @param latch The countdown latch used during server startup to wait for network server + * binding. + */ public GlowSocketServer(GlowServer server, CountDownLatch latch) { super(server, latch); boolean epoll = Epoll.isAvailable(); @@ -35,10 +44,7 @@ public GlowSocketServer(GlowServer server, CountDownLatch latch) { .childOption(ChannelOption.SO_KEEPALIVE, true); } - public Channel getChannel() { - return channel; - } - + @Override public ChannelFuture bind(InetSocketAddress address) { ChannelFuture cfuture = this.bootstrap.bind(address).addListener(future -> { if (future.isSuccess()) { @@ -51,6 +57,7 @@ public ChannelFuture bind(InetSocketAddress address) { return cfuture; } + @Override public void shutdown() { channel.close(); bootstrap.config().childGroup().shutdownGracefully(); diff --git a/src/main/java/net/glowstone/net/ProxyData.java b/src/main/java/net/glowstone/net/ProxyData.java index fa4e1cc51b..4d1cc0a00a 100644 --- a/src/main/java/net/glowstone/net/ProxyData.java +++ b/src/main/java/net/glowstone/net/ProxyData.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Getter; import net.glowstone.entity.meta.profile.PlayerProfile; import net.glowstone.entity.meta.profile.PlayerProperty; import net.glowstone.util.UuidUtils; @@ -15,23 +17,35 @@ /** * Container for proxy (e.g. BungeeCord) player data spoofing. */ +@AllArgsConstructor public final class ProxyData { - private String securityKey; // Lilypad security key - not used by us + /** + * The Lilypad security key sent by the proxy, or null if not present. + */ + @Getter + private String securityKey; + + /** The spoofed hostname to use instead of the actual one. */ + @Getter private String hostname; + + /** + * The spoofed address to use instead of the actual one. + * + * @return The spoofed address. + */ + @Getter private InetSocketAddress address; + + /** The player name for the spoofed profile, or null if not specified. */ private String name; + + /** The player UUID for the spoofed profile. */ private UUID uuid; - private List properties; - public ProxyData(String securityKey, String hostname, InetSocketAddress address, String name, UUID uuid, List properties) { - this.securityKey = securityKey; - this.hostname = hostname; - this.address = address; - this.name = name; - this.uuid = uuid; - this.properties = properties; - } + /** The player properties for the spoofed profile. */ + private List properties; /** * Create a proxy data structure for a session from the given source text. @@ -54,7 +68,8 @@ public ProxyData(GlowSession session, String sourceText) throws Exception { // LilyPad also spoofs the port, unlike Bungee hostname = (String) payload.get("h"); uuid = UuidUtils.fromFlatString((String) payload.get("u")); - address = new InetSocketAddress((String) payload.get("rIp"), ((Long) payload.get("rP")).intValue()); + address = new InetSocketAddress( + (String) payload.get("rIp"), ((Long) payload.get("rP")).intValue()); // Extract properties, if available if (payload.containsKey("p")) { @@ -81,7 +96,8 @@ public ProxyData(GlowSession session, String sourceText) throws Exception { String[] parts = sourceText.split("\0"); if (parts.length != 3 && parts.length != 4) { - throw new IllegalArgumentException("parts length was " + parts.length + ", should be 3 or 4"); + throw new IllegalArgumentException( + "parts length was " + parts.length + ", should be 3 or 4"); } // Set values that aren't supported or present to null @@ -110,33 +126,6 @@ public ProxyData(GlowSession session, String sourceText) throws Exception { } } - /** - * Gets the security key sent by the proxy, if any. - * - * @return The security key, or null if not present. - */ - public String getSecurityKey() { - return securityKey; - } - - /** - * Get the spoofed hostname to use instead of the actual one. - * - * @return The spoofed hostname. - */ - public String getHostname() { - return hostname; - } - - /** - * Get the spoofed address to use instead of the actual one. - * - * @return The spoofed address. - */ - public InetSocketAddress getAddress() { - return address; - } - /** * Get a spoofed profile to use with the given name. * @@ -148,7 +137,8 @@ public PlayerProfile getProfile(String name) { } /** - * Get a spoofed profile to use. Returns null if the proxy did not send a username as part of the payload. + * Get a spoofed profile to use. Returns null if the proxy did not send a username as part of + * the payload. * * @return The spoofed profile. */ diff --git a/src/main/java/net/glowstone/net/SessionRegistry.java b/src/main/java/net/glowstone/net/SessionRegistry.java index 98d964c57f..d1d376dfd8 100644 --- a/src/main/java/net/glowstone/net/SessionRegistry.java +++ b/src/main/java/net/glowstone/net/SessionRegistry.java @@ -4,7 +4,8 @@ import java.util.concurrent.ConcurrentMap; /** - * A list of all the sessions which provides a convenient {@link #pulse()} method to pulse every session in one operation. + * A list of all the sessions which provides a convenient {@link #pulse()} method to pulse every + * session in one operation. * * @author Graham Edgecombe */ diff --git a/src/main/java/net/glowstone/net/codec/play/entity/SetCooldownCodec.java b/src/main/java/net/glowstone/net/codec/play/entity/SetCooldownCodec.java index bf0c08e0de..17152805d3 100644 --- a/src/main/java/net/glowstone/net/codec/play/entity/SetCooldownCodec.java +++ b/src/main/java/net/glowstone/net/codec/play/entity/SetCooldownCodec.java @@ -10,14 +10,14 @@ public class SetCooldownCodec implements Codec { @Override public SetCooldownMessage decode(ByteBuf buffer) throws IOException { - int itemID = ByteBufUtils.readVarInt(buffer); + int itemId = ByteBufUtils.readVarInt(buffer); int cooldownTicks = ByteBufUtils.readVarInt(buffer); - return new SetCooldownMessage(itemID, cooldownTicks); + return new SetCooldownMessage(itemId, cooldownTicks); } @Override public ByteBuf encode(ByteBuf buf, SetCooldownMessage message) throws IOException { - ByteBufUtils.writeVarInt(buf, message.getItemID()); + ByteBufUtils.writeVarInt(buf, message.getItemId()); ByteBufUtils.writeVarInt(buf, message.getCooldownTicks()); return buf; } diff --git a/src/main/java/net/glowstone/net/codec/play/entity/SetPassengerCodec.java b/src/main/java/net/glowstone/net/codec/play/entity/SetPassengerCodec.java index 31608f449f..3bbaf5d3e1 100644 --- a/src/main/java/net/glowstone/net/codec/play/entity/SetPassengerCodec.java +++ b/src/main/java/net/glowstone/net/codec/play/entity/SetPassengerCodec.java @@ -10,14 +10,18 @@ public class SetPassengerCodec implements Codec { @Override public SetPassengerMessage decode(ByteBuf buffer) throws IOException { - int entityID = ByteBufUtils.readVarInt(buffer); - //TODO Read a array of varint? - return null; + int entityId = ByteBufUtils.readVarInt(buffer); + int length = ByteBufUtils.readVarInt(buffer); + int[] passengers = new int[length]; + for (int i = 0; i < length; i++) { + passengers[i] = ByteBufUtils.readVarInt(buffer); + } + return new SetPassengerMessage(entityId, passengers); } @Override public ByteBuf encode(ByteBuf buf, SetPassengerMessage message) throws IOException { - ByteBufUtils.writeVarInt(buf, message.getEntityID()); + ByteBufUtils.writeVarInt(buf, message.getEntityId()); ByteBufUtils.writeVarInt(buf, message.getPassengers().length); for (int passenger : message.getPassengers()) { ByteBufUtils.writeVarInt(buf, passenger); diff --git a/src/main/java/net/glowstone/net/codec/play/game/MapDataCodec.java b/src/main/java/net/glowstone/net/codec/play/game/MapDataCodec.java index f3f2887c9f..bc977815aa 100644 --- a/src/main/java/net/glowstone/net/codec/play/game/MapDataCodec.java +++ b/src/main/java/net/glowstone/net/codec/play/game/MapDataCodec.java @@ -20,7 +20,6 @@ public MapDataMessage decode(ByteBuf buf) throws IOException { @Override public ByteBuf encode(ByteBuf buf, MapDataMessage message) throws IOException { List icons = message.getIcons(); - Section section = message.getSection(); ByteBufUtils.writeVarInt(buf, message.getId()); buf.writeByte(message.getScale()); @@ -31,7 +30,7 @@ public ByteBuf encode(ByteBuf buf, MapDataMessage message) throws IOException { buf.writeByte(icon.x); buf.writeByte(icon.y); } - + Section section = message.getSection(); if (section == null) { buf.writeByte(0); } else { diff --git a/src/main/java/net/glowstone/net/codec/play/game/MultiBlockChangeCodec.java b/src/main/java/net/glowstone/net/codec/play/game/MultiBlockChangeCodec.java index b21278ee6c..e90b6720af 100644 --- a/src/main/java/net/glowstone/net/codec/play/game/MultiBlockChangeCodec.java +++ b/src/main/java/net/glowstone/net/codec/play/game/MultiBlockChangeCodec.java @@ -26,9 +26,8 @@ public ByteBuf encode(ByteBuf buf, MultiBlockChangeMessage message) throws IOExc for (BlockChangeMessage record : records) { // XZY - int pos = (record.getX() & 0xF) << 12 | - (record.getZ() & 0xF) << 8 | - record.getY() & 0xFF; + int pos = (record.getX() & 0xF) << 12 + | (record.getZ() & 0xF) << 8 | record.getY() & 0xFF; buf.writeShort(pos); ByteBufUtils.writeVarInt(buf, record.getType()); } diff --git a/src/main/java/net/glowstone/net/codec/play/game/PositionRotationCodec.java b/src/main/java/net/glowstone/net/codec/play/game/PositionRotationCodec.java index a2a894c58c..bd93b32545 100644 --- a/src/main/java/net/glowstone/net/codec/play/game/PositionRotationCodec.java +++ b/src/main/java/net/glowstone/net/codec/play/game/PositionRotationCodec.java @@ -16,8 +16,8 @@ public PositionRotationMessage decode(ByteBuf buffer) throws IOException { float rotation = buffer.readFloat(); float pitch = buffer.readFloat(); int flags = buffer.readUnsignedByte(); - int teleportID = ByteBufUtils.readVarInt(buffer); - return new PositionRotationMessage(x, y, z, rotation, pitch, flags, teleportID); + int teleportId = ByteBufUtils.readVarInt(buffer); + return new PositionRotationMessage(x, y, z, rotation, pitch, flags, teleportId); } @Override @@ -28,7 +28,7 @@ public ByteBuf encode(ByteBuf buf, PositionRotationMessage message) throws IOExc buf.writeFloat(message.getRotation()); buf.writeFloat(message.getPitch()); buf.writeByte(message.getFlags()); - ByteBufUtils.writeVarInt(buf, message.getTeleportID()); + ByteBufUtils.writeVarInt(buf, message.getTeleportId()); return buf; } } diff --git a/src/main/java/net/glowstone/net/codec/play/game/TitleCodec.java b/src/main/java/net/glowstone/net/codec/play/game/TitleCodec.java index ceb478b20f..e9c17b9ac5 100644 --- a/src/main/java/net/glowstone/net/codec/play/game/TitleCodec.java +++ b/src/main/java/net/glowstone/net/codec/play/game/TitleCodec.java @@ -44,6 +44,9 @@ public ByteBuf encode(ByteBuf buf, TitleMessage message) throws IOException { buf.writeInt(message.getStay()); buf.writeInt(message.getFadeOut()); break; + default: + // TODO: Should this raise a warning? + // do nothing } return buf; } diff --git a/src/main/java/net/glowstone/net/codec/play/game/WorldBorderCodec.java b/src/main/java/net/glowstone/net/codec/play/game/WorldBorderCodec.java index b53b6ec899..11ebcac2ad 100644 --- a/src/main/java/net/glowstone/net/codec/play/game/WorldBorderCodec.java +++ b/src/main/java/net/glowstone/net/codec/play/game/WorldBorderCodec.java @@ -80,6 +80,9 @@ public ByteBuf encode(ByteBuf buf, WorldBorderMessage message) throws IOExceptio case SET_WARNING_BLOCKS: ByteBufUtils.writeVarInt(buf, message.getWarningBlocks()); break; + default: + // TODO: Should this raise a warning? + // do nothing } return buf; } diff --git a/src/main/java/net/glowstone/net/codec/play/player/TeleportConfirmCodec.java b/src/main/java/net/glowstone/net/codec/play/player/TeleportConfirmCodec.java index 448e1087db..ce47e319a1 100644 --- a/src/main/java/net/glowstone/net/codec/play/player/TeleportConfirmCodec.java +++ b/src/main/java/net/glowstone/net/codec/play/player/TeleportConfirmCodec.java @@ -16,7 +16,7 @@ public TeleportConfirmMessage decode(ByteBuf buffer) throws IOException { @Override public ByteBuf encode(ByteBuf buf, TeleportConfirmMessage message) throws IOException { - ByteBufUtils.writeVarInt(buf, message.getTeleportID()); + ByteBufUtils.writeVarInt(buf, message.getTeleportId()); return buf; } } diff --git a/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardDisplayCodec.java b/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardDisplayCodec.java index d8b5b73388..ef24aebe51 100644 --- a/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardDisplayCodec.java +++ b/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardDisplayCodec.java @@ -8,10 +8,12 @@ public final class ScoreboardDisplayCodec implements Codec { + @Override public ScoreboardDisplayMessage decode(ByteBuf buf) throws IOException { throw new UnsupportedOperationException("Cannot decode ScoreboardDisplayMessage"); } + @Override public ByteBuf encode(ByteBuf buf, ScoreboardDisplayMessage message) throws IOException { buf.writeByte(message.getPosition()); ByteBufUtils.writeUTF8(buf, message.getObjective()); diff --git a/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardObjectiveCodec.java b/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardObjectiveCodec.java index 8974b5684f..98608b5461 100644 --- a/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardObjectiveCodec.java +++ b/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardObjectiveCodec.java @@ -8,10 +8,12 @@ public final class ScoreboardObjectiveCodec implements Codec { + @Override public ScoreboardObjectiveMessage decode(ByteBuf buf) throws IOException { throw new UnsupportedOperationException("Cannot decode ScoreboardObjectiveMessage"); } + @Override public ByteBuf encode(ByteBuf buf, ScoreboardObjectiveMessage message) throws IOException { ByteBufUtils.writeUTF8(buf, message.getName()); buf.writeByte(message.getAction()); diff --git a/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardScoreCodec.java b/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardScoreCodec.java index d925625ab0..cc66d3d65e 100644 --- a/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardScoreCodec.java +++ b/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardScoreCodec.java @@ -8,10 +8,12 @@ public final class ScoreboardScoreCodec implements Codec { + @Override public ScoreboardScoreMessage decode(ByteBuf buf) throws IOException { throw new UnsupportedOperationException("Cannot decode ScoreboardScoreMessage"); } + @Override public ByteBuf encode(ByteBuf buf, ScoreboardScoreMessage message) throws IOException { boolean remove = message.isRemove(); ByteBufUtils.writeUTF8(buf, message.getTarget()); diff --git a/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardTeamCodec.java b/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardTeamCodec.java index 89344ba50a..0a7528e776 100644 --- a/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardTeamCodec.java +++ b/src/main/java/net/glowstone/net/codec/play/scoreboard/ScoreboardTeamCodec.java @@ -11,10 +11,12 @@ public final class ScoreboardTeamCodec implements Codec { + @Override public ScoreboardTeamMessage decode(ByteBuf buf) throws IOException { throw new UnsupportedOperationException("Cannot decode ScoreboardTeamMessage"); } + @Override public ByteBuf encode(ByteBuf buf, ScoreboardTeamMessage message) throws IOException { Action action = message.getAction(); diff --git a/src/main/java/net/glowstone/net/handler/handshake/HandshakeHandler.java b/src/main/java/net/glowstone/net/handler/handshake/HandshakeHandler.java index 6236c01028..720d3d0951 100644 --- a/src/main/java/net/glowstone/net/handler/handshake/HandshakeHandler.java +++ b/src/main/java/net/glowstone/net/handler/handshake/HandshakeHandler.java @@ -1,6 +1,7 @@ package net.glowstone.net.handler.handshake; import com.flowpowered.network.MessageHandler; +import java.net.InetSocketAddress; import java.util.logging.Level; import net.glowstone.GlowServer; import net.glowstone.net.GlowSession; @@ -23,7 +24,8 @@ public void handle(GlowSession session, HandshakeMessage message) { } session.setVersion(message.getVersion()); - session.setHostname(message.getAddress() + ":" + message.getPort()); + session.setVirtualHost(InetSocketAddress.createUnresolved( + message.getAddress(), message.getPort())); // Proxies modify the hostname in the HandshakeMessage to contain // the client's UUID and (optionally) properties @@ -40,7 +42,8 @@ public void handle(GlowSession session, HandshakeMessage message) { return; // silently ignore parse data in PING protocol } catch (Exception ex) { if (protocol == ProtocolType.LOGIN) { - GlowServer.logger.log(Level.SEVERE, "Error parsing proxy data for " + session, ex); + GlowServer.logger.log(Level.SEVERE, + "Error parsing proxy data for " + session, ex); session.disconnect("Failed to parse proxy data."); } return; // silently ignore parse data in PING protocol diff --git a/src/main/java/net/glowstone/net/handler/legacyping/LegacyPingHandler.java b/src/main/java/net/glowstone/net/handler/legacyping/LegacyPingHandler.java index 126556043a..840fa461f9 100644 --- a/src/main/java/net/glowstone/net/handler/legacyping/LegacyPingHandler.java +++ b/src/main/java/net/glowstone/net/handler/legacyping/LegacyPingHandler.java @@ -43,7 +43,7 @@ public void channelRead(ChannelHandlerContext channelHandlerContext, Object obje switch (readableBytes) { case 0: sendByteBuf(channelHandlerContext, responseToByteBuf(channelHandlerContext, - String.format("%s\u00a7%d\u00a7%d", legacyPingEvent.getMotd(), + String.format("%s§%d§%d", legacyPingEvent.getMotd(), legacyPingEvent.getNumPlayers(), legacyPingEvent.getMaxPlayers()))); legacyPingProtocol = true; break; @@ -51,7 +51,7 @@ public void channelRead(ChannelHandlerContext channelHandlerContext, Object obje if (bytebuf.readByte() == (byte) 0x01) { sendByteBuf(channelHandlerContext, responseToByteBuf(channelHandlerContext, String - .format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", + .format("§1\0%d\0%s\0%s\0%d\0%d", GlowServer.PROTOCOL_VERSION, GlowServer.GAME_VERSION, legacyPingEvent.getMotd(), legacyPingEvent.getNumPlayers(), legacyPingEvent.getMaxPlayers()))); @@ -74,7 +74,7 @@ public void channelRead(ChannelHandlerContext channelHandlerContext, Object obje && bytebuf.readableBytes() == 0) { sendByteBuf(channelHandlerContext, responseToByteBuf(channelHandlerContext, String - .format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", + .format("§1\0%d\0%s\0%s\0%d\0%d", GlowServer.PROTOCOL_VERSION, GlowServer.GAME_VERSION, legacyPingEvent.getMotd(), legacyPingEvent.getNumPlayers(), diff --git a/src/main/java/net/glowstone/net/handler/play/game/PluginMessageHandler.java b/src/main/java/net/glowstone/net/handler/play/game/PluginMessageHandler.java index 0681d30322..8800293ad7 100644 --- a/src/main/java/net/glowstone/net/handler/play/game/PluginMessageHandler.java +++ b/src/main/java/net/glowstone/net/handler/play/game/PluginMessageHandler.java @@ -87,7 +87,8 @@ int entity (command block minecart) case "MC|BEdit": { // read and verify stack ItemStack item = GlowBufUtils.readSlot(buf); - //GlowServer.logger.info("BookEdit [" + session.getPlayer().getName() + "]: " + item); + //GlowServer.logger.info( + // "BookEdit [" + session.getPlayer().getName() + "]: " + item); if (item == null || item.getType() != Material.BOOK_AND_QUILL) { return; } @@ -120,7 +121,8 @@ int entity (command block minecart) case "MC|BSign": // read and verify stack ItemStack item = GlowBufUtils.readSlot(buf); - //GlowServer.logger.info("BookSign [" + session.getPlayer().getName() + "]: " + item); + //GlowServer.logger.info( + // "BookSign [" + session.getPlayer().getName() + "]: " + item); if (item == null || item.getType() != Material.WRITTEN_BOOK) { return; } diff --git a/src/main/java/net/glowstone/net/handler/play/inv/WindowClickHandler.java b/src/main/java/net/glowstone/net/handler/play/inv/WindowClickHandler.java index 653270b422..bacfd44122 100644 --- a/src/main/java/net/glowstone/net/handler/play/inv/WindowClickHandler.java +++ b/src/main/java/net/glowstone/net/handler/play/inv/WindowClickHandler.java @@ -46,7 +46,8 @@ public void handle(GlowSession session, WindowClickMessage message) { result = process(session.getPlayer(), message); } catch (IllegalArgumentException ex) { GlowServer.logger.warning( - session.getPlayer().getName() + ": illegal argument while handling click: " + ex); + session.getPlayer().getName() + ": illegal argument while handling click: " + + ex); } session.send(new TransactionMessage(message.getId(), message.getTransaction(), result)); if (!result) { @@ -65,7 +66,7 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { // check that the player has a correct view of the item if (!Objects.equals(message.getItem(), slotItem) && (message.getMode() == 0 - || message.getMode() == 1)) { + || message.getMode() == 1)) { // reject item change because of desynced inventory // in mode 3 (get) and 4 (drop), client does not send item in slot under cursor if (message.getMode() == 0 || !InventoryUtil.isEmpty(message.getItem())) { @@ -74,9 +75,9 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { // if there's an item under the cursor // recipe slot is not synced by design if (view.getTopInventory().getType() != InventoryType.CRAFTING || viewSlot >= view - .getTopInventory().getSize() - || ((GlowInventory) view.getTopInventory()).getSlot(viewSlot).getType() - != SlotType.RESULT) { + .getTopInventory().getSize() + || ((GlowInventory) view.getTopInventory()).getSlot(viewSlot).getType() + != SlotType.RESULT) { player.sendItemChange(viewSlot, slotItem); return false; } @@ -139,7 +140,7 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { Inventory dragInv = dragSlot < top.getSize() ? top : bottom; int oldItemAmount = InventoryUtil.itemOrEmpty(oldItem).getAmount(); int transfer = Math.min(Math.min(perSlot, cursor.getAmount()), - maxStack(dragInv, cursor.getType()) - oldItemAmount); + maxStack(dragInv, cursor.getType()) - oldItemAmount); ItemStack newItem = combine(oldItem, cursor, transfer); newSlots.put(dragSlot, newItem); newCursor = amountOrEmpty(newCursor, newCursor.getAmount() - transfer); @@ -150,7 +151,7 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { } InventoryDragEvent event = new InventoryDragEvent(view, newCursor, cursor, - right, newSlots); + right, newSlots); EventFactory.callEvent(event); if (event.isCancelled()) { return false; @@ -161,21 +162,21 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { } player.setItemOnCursor(newCursor); return true; + default: + return false; } - - return false; } // determine what action will be taken and fire event ClickType clickType = WindowClickLogic - .getClickType(message.getMode(), message.getButton(), viewSlot); + .getClickType(message.getMode(), message.getButton(), viewSlot); InventoryAction action = WindowClickLogic.getAction(clickType, slotType, cursor, slotItem); if (clickType == ClickType.UNKNOWN || action == InventoryAction.UNKNOWN) { // show a warning for unknown click type GlowServer.logger.warning( - player.getName() + ": mystery window click " + clickType + "/" + action + ": " - + message); + player.getName() + ": mystery window click " + clickType + "/" + action + ": " + + message); } // deny CLONE_STACK for non-creative mode players @@ -193,7 +194,8 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { action = InventoryAction.NOTHING; } } else if (inv != bottom || !inv.itemPlaceAllowed(invSlot, destItem)) { - // target and source inventory are different or destItem cannot be placed in current slot + // target and source inventory are different or destItem cannot be placed in + // current slot action = InventoryAction.HOTBAR_MOVE_AND_READD; } } @@ -219,7 +221,7 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { InventoryClickEvent event = null; if (top == inv && top instanceof GlowCraftingInventory - && top.getSlotType(invSlot) == SlotType.RESULT) { + && top.getSlotType(invSlot) == SlotType.RESULT) { // Clicked on output slot of crafting inventory if (InventoryUtil.isEmpty(slotItem)) { // No crafting recipe result, don't do anything @@ -229,10 +231,10 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { int cursorAmount = InventoryUtil.itemOrEmpty(cursor).getAmount(); if (message.getMode() == 0 && slotItem.isSimilar(cursor)) { if (!InventoryUtil.isEmpty(slotItem) - && cursorAmount + slotItem.getAmount() <= slotItem.getMaxStackSize()) { + && cursorAmount + slotItem.getAmount() <= slotItem.getMaxStackSize()) { // if the player can take the whole result if (WindowClickLogic.isPickupAction(action) || WindowClickLogic - .isPlaceAction(action)) { + .isPlaceAction(action)) { // always take the whole crafting result out of the crafting inventories action = InventoryAction.PICKUP_ALL; } else if (action == InventoryAction.DROP_ONE_SLOT) { @@ -250,7 +252,7 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { Recipe recipe = ((CraftingInventory) inv).getRecipe(); if (clickType == ClickType.NUMBER_KEY) { event = new CraftItemEvent(recipe, view, slotType, viewSlot, clickType, action, - message.getButton()); + message.getButton()); } else { event = new CraftItemEvent(recipe, view, slotType, viewSlot, clickType, action); } @@ -260,7 +262,7 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { if (event == null) { if (clickType == ClickType.NUMBER_KEY) { event = new InventoryClickEvent(view, slotType, viewSlot, clickType, action, - message.getButton()); + message.getButton()); } else { event = new InventoryClickEvent(view, slotType, viewSlot, clickType, action); } @@ -287,7 +289,8 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { view.setItem(viewSlot, InventoryUtil.createEmptyStack()); int cursorAmount = InventoryUtil.itemOrEmpty(cursor).getAmount(); player - .setItemOnCursor(amountOrEmpty(slotItem, cursorAmount + slotItem.getAmount())); + .setItemOnCursor(amountOrEmpty(slotItem, + cursorAmount + slotItem.getAmount())); break; case PICKUP_HALF: // pick up half (favor picking up) @@ -301,7 +304,7 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { case PICKUP_SOME: // pick up as many items as possible int pickUp = Math - .min(cursor.getMaxStackSize() - cursor.getAmount(), slotItem.getAmount()); + .min(cursor.getMaxStackSize() - cursor.getAmount(), slotItem.getAmount()); view.setItem(viewSlot, amountOrEmpty(slotItem, slotItem.getAmount() - pickUp)); player.setItemOnCursor(amountOrEmpty(cursor, cursor.getAmount() + pickUp)); break; @@ -318,7 +321,7 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { case PLACE_SOME: { // slotItem *should* never be empty in this situation? int transfer = Math.min(cursor.getAmount(), - maxStack(inv, slotItem.getType()) - slotItem.getAmount()); + maxStack(inv, slotItem.getType()) - slotItem.getAmount()); view.setItem(viewSlot, combine(slotItem, cursor, transfer)); player.setItemOnCursor(amountOrEmpty(cursor, cursor.getAmount() - transfer)); break; @@ -420,26 +423,30 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { int slotCount = view.countSlots(); for (int i = 0; - i < slotCount && cursor.getAmount() < maxStack(inv, cursor.getType()); ++i) { + i < slotCount && cursor.getAmount() < maxStack(inv, cursor.getType()); ++i) { ItemStack item = view.getItem(i); SlotType type = (i < top.getSize() ? top : bottom) - .getSlotType(view.convertSlot(i)); + .getSlotType(view.convertSlot(i)); if (InventoryUtil.isEmpty(item) || !cursor.isSimilar(item) - || type == SlotType.RESULT) { + || type == SlotType.RESULT) { continue; } int transfer = Math.min(item.getAmount(), - maxStack(inv, cursor.getType()) - cursor.getAmount()); + maxStack(inv, cursor.getType()) - cursor.getAmount()); cursor.setAmount(cursor.getAmount() + transfer); view.setItem(i, amountOrEmpty(item, item.getAmount() - transfer)); } break; + default: + handled = false; } if (handled && top == inv && top instanceof GlowCraftingInventory - && top.getSlotType(invSlot) == SlotType.RESULT && action != MOVE_TO_OTHER_INVENTORY - && action != NOTHING) { - // If we are crafting (but not using shift click because no more items can be crafted for the given pattern. If a new item can be crafted with another pattern, a new click is required). + && top.getSlotType(invSlot) == SlotType.RESULT && action != MOVE_TO_OTHER_INVENTORY + && action != NOTHING) { + // If we are crafting (but not using shift click because no more items can be crafted + // for the given pattern. If a new item can be crafted with another pattern, a new + // click is required). final GlowCraftingInventory glowCraftingInventory = (GlowCraftingInventory) top; glowCraftingInventory.craft(); // Notify the player the result slot changed @@ -448,7 +455,7 @@ private boolean process(GlowPlayer player, WindowClickMessage message) { if (!handled) { GlowServer.logger.warning( - player.getName() + ": unhandled click action " + action + " for " + message); + player.getName() + ": unhandled click action " + action + " for " + message); } return handled; @@ -471,7 +478,7 @@ private ItemStack combine(ItemStack slotItem, ItemStack cursor, int amount) { return slotItem; } else { throw new IllegalArgumentException( - "Trying to combine dissimilar " + slotItem + " and " + cursor); + "Trying to combine dissimilar " + slotItem + " and " + cursor); } } diff --git a/src/main/java/net/glowstone/net/handler/play/player/BlockPlacementHandler.java b/src/main/java/net/glowstone/net/handler/play/player/BlockPlacementHandler.java index 49eb3ad3bd..02d7082e7f 100644 --- a/src/main/java/net/glowstone/net/handler/play/player/BlockPlacementHandler.java +++ b/src/main/java/net/glowstone/net/handler/play/player/BlockPlacementHandler.java @@ -8,7 +8,6 @@ import net.glowstone.block.blocktype.BlockType; import net.glowstone.block.entity.BlockEntity; import net.glowstone.block.itemtype.ItemType; -import net.glowstone.block.itemtype.ItemType.Context; import net.glowstone.entity.GlowPlayer; import net.glowstone.net.GlowSession; import net.glowstone.net.message.play.player.BlockPlacementMessage; @@ -101,7 +100,9 @@ public void handle(GlowSession session, BlockPlacementMessage message) { handleRightClickBlock(player, holding, message.getHandSlot(), clicked, face, clickedLoc); } - static void handleRightClickBlock(GlowPlayer player, ItemStack holding, EquipmentSlot slot, GlowBlock clicked, BlockFace face, Vector clickedLoc) { + static void handleRightClickBlock( + GlowPlayer player, ItemStack holding, EquipmentSlot slot, GlowBlock clicked, + BlockFace face, Vector clickedLoc) { // call interact event PlayerInteractEvent event = EventFactory.onPlayerInteract( player, Action.RIGHT_CLICK_BLOCK, slot, clicked, face); @@ -124,8 +125,8 @@ static void handleRightClickBlock(GlowPlayer player, ItemStack holding, Equipmen // follows ALLOW/DENY: default to if no block was interacted with if (selectResult(event.useItemInHand(), !useInteractedBlock)) { ItemType type = ItemTable.instance().getItem(holding.getType()); - if (holding.getType() != Material.AIR && ( - type.getContext() == Context.BLOCK || type.getContext() == Context.ANY)) { + if (holding.getType() != Material.AIR + && type.getContext().isBlockApplicable()) { type.rightClickBlock(player, clicked, face, holding, clickedLoc, slot); } } diff --git a/src/main/java/net/glowstone/net/handler/play/player/InteractEntityHandler.java b/src/main/java/net/glowstone/net/handler/play/player/InteractEntityHandler.java index 584a498f3e..fbaa884ec4 100644 --- a/src/main/java/net/glowstone/net/handler/play/player/InteractEntityHandler.java +++ b/src/main/java/net/glowstone/net/handler/play/player/InteractEntityHandler.java @@ -72,7 +72,9 @@ public void handle(GlowSession session, InteractEntityMessage message) { target.setFireTicks(target.getFireTicks() + itemInHand.getEnchantmentLevel(Enchantment.FIRE_ASPECT) * 80); } - boolean showMagicCrit = false; // Shows the "magic crit" particles (blue) if the weapon was a sword or an axe (and with a damaging enchantment) + boolean showMagicCrit = false; + // Shows the "magic crit" particles (blue) if the weapon was a sword or an axe (and + // with a damaging enchantment) // Apply other enchantments that amplify damage if (itemInHand.containsEnchantment(Enchantment.DAMAGE_ALL)) { // Sharpness @@ -85,12 +87,14 @@ public void handle(GlowSession session, InteractEntityMessage message) { } } if (itemInHand.containsEnchantment(Enchantment.DAMAGE_ARTHROPODS)) { - // Bane of Arthropods (applies to Spiders, Cave Spiders, Silverfish and Endermites) + // Bane of Arthropods (applies to Spiders, Cave Spiders, Silverfish and + // Endermites) if (target.isArthropod()) { int level = itemInHand.getEnchantmentLevel(Enchantment.DAMAGE_ARTHROPODS); if (level > 0) { damage += level * 2.5F; - // TODO: add Slowness potion effect (after damaging and checking for event-cancellation) + // TODO: add Slowness potion effect (after damaging and checking for + // event-cancellation) } } if (!showMagicCrit) { diff --git a/src/main/java/net/glowstone/net/handler/play/player/PlayerActionHandler.java b/src/main/java/net/glowstone/net/handler/play/player/PlayerActionHandler.java index a26b0d73f1..7d8bfddf32 100644 --- a/src/main/java/net/glowstone/net/handler/play/player/PlayerActionHandler.java +++ b/src/main/java/net/glowstone/net/handler/play/player/PlayerActionHandler.java @@ -45,6 +45,10 @@ public void handle(GlowSession session, PlayerActionMessage message) { && hasElytra) { player.setGliding(true); } + break; + default: + // TODO: Should this raise a warning? + // do nothing } } } diff --git a/src/main/java/net/glowstone/net/handler/play/player/PlayerSwingArmHandler.java b/src/main/java/net/glowstone/net/handler/play/player/PlayerSwingArmHandler.java index 63a341cac0..bf748938a1 100644 --- a/src/main/java/net/glowstone/net/handler/play/player/PlayerSwingArmHandler.java +++ b/src/main/java/net/glowstone/net/handler/play/player/PlayerSwingArmHandler.java @@ -14,7 +14,7 @@ import org.bukkit.event.player.PlayerAnimationEvent; public final class PlayerSwingArmHandler implements - MessageHandler { + MessageHandler { @Override public void handle(GlowSession session, PlayerSwingArmMessage message) { @@ -23,8 +23,9 @@ public void handle(GlowSession session, PlayerSwingArmMessage message) { Block block = player.getTargetBlock((Set) null, 6); if (block == null || block.isEmpty()) { - if (EventFactory.onPlayerInteract(player, Action.LEFT_CLICK_AIR, message.getHandSlot()).useItemInHand() - == Result.DENY) { + if (EventFactory.onPlayerInteract( + player, Action.LEFT_CLICK_AIR, message.getHandSlot()).useItemInHand() + == Result.DENY) { return; } // todo: item interactions with air @@ -33,7 +34,7 @@ public void handle(GlowSession session, PlayerSwingArmMessage message) { if (!EventFactory.callEvent(new PlayerAnimationEvent(player)).isCancelled()) { // play the animation to others player.playAnimation(message.getHand() == 1 ? EntityAnimation.SWING_OFF_HAND - : EntityAnimation.SWING_MAIN_HAND); + : EntityAnimation.SWING_MAIN_HAND); } } } diff --git a/src/main/java/net/glowstone/net/handler/play/player/UseItemHandler.java b/src/main/java/net/glowstone/net/handler/play/player/UseItemHandler.java index d2bfcb8172..212fd1db2b 100644 --- a/src/main/java/net/glowstone/net/handler/play/player/UseItemHandler.java +++ b/src/main/java/net/glowstone/net/handler/play/player/UseItemHandler.java @@ -1,19 +1,17 @@ package net.glowstone.net.handler.play.player; import com.flowpowered.network.MessageHandler; -import java.util.Arrays; -import java.util.HashSet; +import com.google.common.collect.ImmutableSortedSet; import java.util.List; +import java.util.SortedSet; import net.glowstone.EventFactory; import net.glowstone.block.GlowBlock; import net.glowstone.block.ItemTable; import net.glowstone.block.itemtype.ItemType; -import net.glowstone.block.itemtype.ItemType.Context; import net.glowstone.entity.GlowPlayer; import net.glowstone.net.GlowSession; import net.glowstone.net.message.play.player.UseItemMessage; import net.glowstone.util.InventoryUtil; - import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -26,9 +24,9 @@ public class UseItemHandler implements MessageHandler { - private static final HashSet IGNORE_MATS = new HashSet<>(Arrays.asList( - Material.AIR, Material.WATER, Material.LAVA, Material.STATIONARY_LAVA, Material.STATIONARY_WATER - )); + private static final SortedSet IGNORE_MATS = ImmutableSortedSet.of( + Material.AIR, Material.WATER, Material.LAVA, Material.STATIONARY_LAVA, + Material.STATIONARY_WATER); @Override public void handle(GlowSession session, UseItemMessage message) { @@ -74,12 +72,14 @@ static void handleRightClick(GlowPlayer player, ItemStack holding, EquipmentSlot if (action == Action.RIGHT_CLICK_AIR) { handleRightClickAir(player, holding, slot); } else { - BlockPlacementHandler.handleRightClickBlock(player, holding, slot, block, face, clickedAt); + BlockPlacementHandler.handleRightClickBlock( + player, holding, slot, block, face, clickedAt); } } static void handleRightClickAir(GlowPlayer player, ItemStack holding, EquipmentSlot slot) { - PlayerInteractEvent event = EventFactory.onPlayerInteract(player, Action.RIGHT_CLICK_AIR, slot); + PlayerInteractEvent event = EventFactory.onPlayerInteract( + player, Action.RIGHT_CLICK_AIR, slot); if (event.useItemInHand() == null || event.useItemInHand() == Event.Result.DENY) { return; @@ -88,7 +88,7 @@ static void handleRightClickAir(GlowPlayer player, ItemStack holding, EquipmentS if (!InventoryUtil.isEmpty(holding)) { ItemType type = ItemTable.instance().getItem(holding.getType()); if (type != null) { - if (type.getContext() == Context.ANY || type.getContext() == Context.AIR) { + if (type.getContext().isAirApplicable()) { type.rightClickAir(player, holding); } } diff --git a/src/main/java/net/glowstone/net/http/HttpClient.java b/src/main/java/net/glowstone/net/http/HttpClient.java index df11bf6a13..eb2c84f945 100644 --- a/src/main/java/net/glowstone/net/http/HttpClient.java +++ b/src/main/java/net/glowstone/net/http/HttpClient.java @@ -35,6 +35,13 @@ public class HttpClient { Epoll.isAvailable() ? EpollDatagramChannel.class : NioDatagramChannel.class, DefaultDnsServerAddressStreamProvider.INSTANCE); + /** + * Opens a URL. + * + * @param url the URL to download + * @param eventLoop an {@link EventLoop} that will receive the response body + * @param callback a callback to handle the response or any error + */ public static void connect(String url, EventLoop eventLoop, HttpCallback callback) { URI uri = URI.create(url); diff --git a/src/main/java/net/glowstone/net/message/play/entity/RelativeEntityPositionMessage.java b/src/main/java/net/glowstone/net/message/play/entity/RelativeEntityPositionMessage.java index 1c79ffe114..e3e773a3a1 100644 --- a/src/main/java/net/glowstone/net/message/play/entity/RelativeEntityPositionMessage.java +++ b/src/main/java/net/glowstone/net/message/play/entity/RelativeEntityPositionMessage.java @@ -9,7 +9,9 @@ public final class RelativeEntityPositionMessage implements Message { private final int id; - private final short deltaX, deltaY, deltaZ; + private final short deltaX; + private final short deltaY; + private final short deltaZ; private final boolean onGround; public RelativeEntityPositionMessage(int id, short deltaX, short deltaY, short deltaZ) { diff --git a/src/main/java/net/glowstone/net/message/play/entity/RelativeEntityPositionRotationMessage.java b/src/main/java/net/glowstone/net/message/play/entity/RelativeEntityPositionRotationMessage.java index eec81b6e39..0dcfd3ec2d 100644 --- a/src/main/java/net/glowstone/net/message/play/entity/RelativeEntityPositionRotationMessage.java +++ b/src/main/java/net/glowstone/net/message/play/entity/RelativeEntityPositionRotationMessage.java @@ -9,8 +9,11 @@ public final class RelativeEntityPositionRotationMessage implements Message { private final int id; - private final short deltaX, deltaY, deltaZ; - private final int rotation, pitch; + private final short deltaX; + private final short deltaY; + private final short deltaZ; + private final int rotation; + private final int pitch; private final boolean onGround; public RelativeEntityPositionRotationMessage(int id, short deltaX, short deltaY, short deltaZ, diff --git a/src/main/java/net/glowstone/net/message/play/entity/SetCooldownMessage.java b/src/main/java/net/glowstone/net/message/play/entity/SetCooldownMessage.java index 1d9aafcddf..f77dc4fa20 100644 --- a/src/main/java/net/glowstone/net/message/play/entity/SetCooldownMessage.java +++ b/src/main/java/net/glowstone/net/message/play/entity/SetCooldownMessage.java @@ -8,5 +8,6 @@ @AllArgsConstructor public class SetCooldownMessage implements Message { - private final int itemID, cooldownTicks; + private final int itemId; + private final int cooldownTicks; } diff --git a/src/main/java/net/glowstone/net/message/play/entity/SetPassengerMessage.java b/src/main/java/net/glowstone/net/message/play/entity/SetPassengerMessage.java index e3a35738ca..3220d532b1 100644 --- a/src/main/java/net/glowstone/net/message/play/entity/SetPassengerMessage.java +++ b/src/main/java/net/glowstone/net/message/play/entity/SetPassengerMessage.java @@ -8,6 +8,6 @@ @RequiredArgsConstructor public class SetPassengerMessage implements Message { - private final int entityID; + private final int entityId; private final int[] passengers; } diff --git a/src/main/java/net/glowstone/net/message/play/entity/SpawnLightningStrikeMessage.java b/src/main/java/net/glowstone/net/message/play/entity/SpawnLightningStrikeMessage.java index 27e14a5b7c..a919d589da 100644 --- a/src/main/java/net/glowstone/net/message/play/entity/SpawnLightningStrikeMessage.java +++ b/src/main/java/net/glowstone/net/message/play/entity/SpawnLightningStrikeMessage.java @@ -8,8 +8,11 @@ @RequiredArgsConstructor public final class SpawnLightningStrikeMessage implements Message { - private final int id, mode; - private final double x, y, z; + private final int id; + private final int mode; + private final double x; + private final double y; + private final double z; public SpawnLightningStrikeMessage(int id, double x, double y, double z) { this(id, 1, x, y, z); diff --git a/src/main/java/net/glowstone/net/message/play/entity/SpawnMobMessage.java b/src/main/java/net/glowstone/net/message/play/entity/SpawnMobMessage.java index 97a3997a22..bd79a60df8 100644 --- a/src/main/java/net/glowstone/net/message/play/entity/SpawnMobMessage.java +++ b/src/main/java/net/glowstone/net/message/play/entity/SpawnMobMessage.java @@ -16,8 +16,15 @@ public final class SpawnMobMessage implements Message { private final int id; private final UUID uuid; //TODO: Handle UUID private final int type; - private final double x, y, z; - private final int rotation, pitch, headPitch, velX, velY, velZ; + private final double x; + private final double y; + private final double z; + private final int rotation; + private final int pitch; + private final int headPitch; + private final int velX; + private final int velY; + private final int velZ; private final List metadata; /** diff --git a/src/main/java/net/glowstone/net/message/play/entity/SpawnObjectMessage.java b/src/main/java/net/glowstone/net/message/play/entity/SpawnObjectMessage.java index 43434b29e7..1df1486b8b 100644 --- a/src/main/java/net/glowstone/net/message/play/entity/SpawnObjectMessage.java +++ b/src/main/java/net/glowstone/net/message/play/entity/SpawnObjectMessage.java @@ -22,8 +22,15 @@ public final class SpawnObjectMessage implements Message { private final int id; private final UUID uuid; // TODO: Handle UUID private final int type; - private final double x, y, z; - private final int pitch, yaw, data, velX, velY, velZ; + private final double x; + private final double y; + private final double z; + private final int pitch; + private final int yaw; + private final int data; + private final int velX; + private final int velY; + private final int velZ; public SpawnObjectMessage(int id, UUID uuid, int type, double x, double y, double z, int pitch, int yaw) { diff --git a/src/main/java/net/glowstone/net/message/play/entity/SpawnPaintingMessage.java b/src/main/java/net/glowstone/net/message/play/entity/SpawnPaintingMessage.java index 14fb8ca93b..35cb17a0f8 100644 --- a/src/main/java/net/glowstone/net/message/play/entity/SpawnPaintingMessage.java +++ b/src/main/java/net/glowstone/net/message/play/entity/SpawnPaintingMessage.java @@ -10,6 +10,9 @@ public final class SpawnPaintingMessage implements Message { private final int id; private final UUID uniqueId; private final String title; - private final int x, y, z, facing; + private final int x; + private final int y; + private final int z; + private final int facing; } diff --git a/src/main/java/net/glowstone/net/message/play/entity/SpawnPlayerMessage.java b/src/main/java/net/glowstone/net/message/play/entity/SpawnPlayerMessage.java index 00e8f79954..1dd79ec550 100644 --- a/src/main/java/net/glowstone/net/message/play/entity/SpawnPlayerMessage.java +++ b/src/main/java/net/glowstone/net/message/play/entity/SpawnPlayerMessage.java @@ -11,8 +11,11 @@ public final class SpawnPlayerMessage implements Message { private final int id; private final UUID uuid; - private final double x, y, z; - private final int rotation, pitch; + private final double x; + private final double y; + private final double z; + private final int rotation; + private final int pitch; private final List metadata; } diff --git a/src/main/java/net/glowstone/net/message/play/entity/SpawnXpOrbMessage.java b/src/main/java/net/glowstone/net/message/play/entity/SpawnXpOrbMessage.java index 0595602bad..f8079e0f3b 100644 --- a/src/main/java/net/glowstone/net/message/play/entity/SpawnXpOrbMessage.java +++ b/src/main/java/net/glowstone/net/message/play/entity/SpawnXpOrbMessage.java @@ -10,7 +10,9 @@ public final class SpawnXpOrbMessage implements Message { private final int id; - private final double x, y, z; + private final double x; + private final double y; + private final double z; private final short count; public SpawnXpOrbMessage(int id, Location location, short count) { diff --git a/src/main/java/net/glowstone/net/message/play/entity/VehicleMoveMessage.java b/src/main/java/net/glowstone/net/message/play/entity/VehicleMoveMessage.java index fd2e814aab..1dac1f92a6 100644 --- a/src/main/java/net/glowstone/net/message/play/entity/VehicleMoveMessage.java +++ b/src/main/java/net/glowstone/net/message/play/entity/VehicleMoveMessage.java @@ -7,9 +7,21 @@ @Data public class VehicleMoveMessage implements Message { - private final double x, y, z; - private final float yaw, pitch; + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + /** + * Creates a message. + * + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + * @param yaw the yaw angle + * @param pitch the pitch angle + */ public VehicleMoveMessage(double x, double y, double z, float yaw, float pitch) { this.x = x; this.y = y; @@ -18,6 +30,11 @@ public VehicleMoveMessage(double x, double y, double z, float yaw, float pitch) this.pitch = pitch; } + /** + * Copies this message's position and orientation to a {@link Location}. + * + * @param location the location to update + */ public void update(Location location) { location.setX(x); location.setY(y); diff --git a/src/main/java/net/glowstone/net/message/play/game/JoinGameMessage.java b/src/main/java/net/glowstone/net/message/play/game/JoinGameMessage.java index 48d42c65f4..29a9c8de7b 100644 --- a/src/main/java/net/glowstone/net/message/play/game/JoinGameMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/JoinGameMessage.java @@ -6,7 +6,11 @@ @Data public final class JoinGameMessage implements Message { - private final int id, mode, dimension, difficulty, maxPlayers; + private final int id; + private final int mode; + private final int dimension; + private final int difficulty; + private final int maxPlayers; private final String levelType; private final boolean reducedDebugInfo; diff --git a/src/main/java/net/glowstone/net/message/play/game/MapDataMessage.java b/src/main/java/net/glowstone/net/message/play/game/MapDataMessage.java index 47a79c02e4..5e28c08e26 100644 --- a/src/main/java/net/glowstone/net/message/play/game/MapDataMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/MapDataMessage.java @@ -12,7 +12,8 @@ @Data public final class MapDataMessage implements Message { - private final int id, scale; + private final int id; + private final int scale; private final List icons; private final Section section; @@ -21,16 +22,30 @@ public final class MapDataMessage implements Message { @EqualsAndHashCode public static class Icon { - public final int type, facing, x, y; + public final int type; + public final int facing; + public final int x; + public final int y; } @ToString @EqualsAndHashCode public static class Section { - public final int width, height, x, y; + public final int width; + public final int height; + public final int x; + public final int y; public final byte[] data; + /** + * Creates an instance. + * @param width the section width + * @param height the section height + * @param x the x offset + * @param y the y offset + * @param data the data + */ public Section(int width, int height, int x, int y, byte... data) { checkArgument(width * height == data.length, "width * height == data.length"); this.width = width; diff --git a/src/main/java/net/glowstone/net/message/play/game/MultiBlockChangeMessage.java b/src/main/java/net/glowstone/net/message/play/game/MultiBlockChangeMessage.java index 375967eded..88b073df62 100644 --- a/src/main/java/net/glowstone/net/message/play/game/MultiBlockChangeMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/MultiBlockChangeMessage.java @@ -7,7 +7,8 @@ @Data public final class MultiBlockChangeMessage implements Message { - private final int chunkX, chunkZ; + private final int chunkX; + private final int chunkZ; private final List records; } diff --git a/src/main/java/net/glowstone/net/message/play/game/NamedSoundEffectMessage.java b/src/main/java/net/glowstone/net/message/play/game/NamedSoundEffectMessage.java index 9ea0675f3c..a3acef204f 100644 --- a/src/main/java/net/glowstone/net/message/play/game/NamedSoundEffectMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/NamedSoundEffectMessage.java @@ -9,6 +9,9 @@ public final class NamedSoundEffectMessage implements Message { private final String sound; private final SoundCategory soundCategory; - private final double x, y, z; - private final float volume, pitch; + private final double x; + private final double y; + private final double z; + private final float volume; + private final float pitch; } diff --git a/src/main/java/net/glowstone/net/message/play/game/PlayEffectMessage.java b/src/main/java/net/glowstone/net/message/play/game/PlayEffectMessage.java index 78d2a335e6..3ac4fdbe6d 100644 --- a/src/main/java/net/glowstone/net/message/play/game/PlayEffectMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/PlayEffectMessage.java @@ -7,7 +7,9 @@ public final class PlayEffectMessage implements Message { private final int id; - private final int x, y, z; + private final int x; + private final int y; + private final int z; private final int data; private final boolean ignoreDistance; diff --git a/src/main/java/net/glowstone/net/message/play/game/PlayParticleMessage.java b/src/main/java/net/glowstone/net/message/play/game/PlayParticleMessage.java index 9fa36e4d8e..655d8b0813 100644 --- a/src/main/java/net/glowstone/net/message/play/game/PlayParticleMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/PlayParticleMessage.java @@ -8,8 +8,12 @@ public final class PlayParticleMessage implements Message { private final int particle; private final boolean longDistance; - private final float x, y, z; - private final float ofsX, ofsY, ofsZ; + private final float x; + private final float y; + private final float z; + private final float ofsX; + private final float ofsY; + private final float ofsZ; private final float data; private final int count; private final int[] extData; diff --git a/src/main/java/net/glowstone/net/message/play/game/PluginMessage.java b/src/main/java/net/glowstone/net/message/play/game/PluginMessage.java index b4fa246415..f31a0a0f39 100644 --- a/src/main/java/net/glowstone/net/message/play/game/PluginMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/PluginMessage.java @@ -15,6 +15,13 @@ public final class PluginMessage implements Message { private final String channel; private final byte[] data; + /** + * Creates a message whose contents are a string in UTF8. + * + * @param channel the plugin message channel + * @param text the contents as a string + * @return a message for {@code channel} containing a UTF8-encoded copy of {@code text} + */ public static PluginMessage fromString(String channel, String text) { ByteBuf buf = Unpooled.buffer(5 + text.length()); try { diff --git a/src/main/java/net/glowstone/net/message/play/game/PositionRotationMessage.java b/src/main/java/net/glowstone/net/message/play/game/PositionRotationMessage.java index 50abf1086c..7e98a767e5 100644 --- a/src/main/java/net/glowstone/net/message/play/game/PositionRotationMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/PositionRotationMessage.java @@ -9,9 +9,13 @@ @RequiredArgsConstructor public final class PositionRotationMessage implements Message { - private final double x, y, z; - private final float rotation, pitch; - private final int flags, teleportID; + private final double x; + private final double y; + private final double z; + private final float rotation; + private final float pitch; + private final int flags; + private final int teleportId; public PositionRotationMessage(double x, double y, double z, float rotation, float pitch) { this(x, y, z, rotation, pitch, 0, 0); diff --git a/src/main/java/net/glowstone/net/message/play/game/RespawnMessage.java b/src/main/java/net/glowstone/net/message/play/game/RespawnMessage.java index 744ffceb1c..0768656466 100644 --- a/src/main/java/net/glowstone/net/message/play/game/RespawnMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/RespawnMessage.java @@ -6,7 +6,9 @@ @Data public final class RespawnMessage implements Message { - private final int dimension, difficulty, mode; + private final int dimension; + private final int difficulty; + private final int mode; private final String levelType; } diff --git a/src/main/java/net/glowstone/net/message/play/game/SignEditorMessage.java b/src/main/java/net/glowstone/net/message/play/game/SignEditorMessage.java index 8d776eaf42..24c0485859 100644 --- a/src/main/java/net/glowstone/net/message/play/game/SignEditorMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/SignEditorMessage.java @@ -6,7 +6,9 @@ @Data public final class SignEditorMessage implements Message { - private final int x, y, z; + private final int x; + private final int y; + private final int z; } diff --git a/src/main/java/net/glowstone/net/message/play/game/SoundEffectMessage.java b/src/main/java/net/glowstone/net/message/play/game/SoundEffectMessage.java index d215009705..be1fa0654c 100644 --- a/src/main/java/net/glowstone/net/message/play/game/SoundEffectMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/SoundEffectMessage.java @@ -9,6 +9,9 @@ public class SoundEffectMessage implements Message { private final int sound; private final SoundCategory category; - private final double x, y, z; - private final float volume, pitch; + private final double x; + private final double y; + private final double z; + private final float volume; + private final float pitch; } diff --git a/src/main/java/net/glowstone/net/message/play/game/SpawnPositionMessage.java b/src/main/java/net/glowstone/net/message/play/game/SpawnPositionMessage.java index 68c84d4237..ce15429186 100644 --- a/src/main/java/net/glowstone/net/message/play/game/SpawnPositionMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/SpawnPositionMessage.java @@ -6,6 +6,8 @@ @Data public final class SpawnPositionMessage implements Message { - private final int x, y, z; + private final int x; + private final int y; + private final int z; } diff --git a/src/main/java/net/glowstone/net/message/play/game/TimeMessage.java b/src/main/java/net/glowstone/net/message/play/game/TimeMessage.java index 5939549c1f..1f3b92b497 100644 --- a/src/main/java/net/glowstone/net/message/play/game/TimeMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/TimeMessage.java @@ -6,6 +6,7 @@ @Data public final class TimeMessage implements Message { - private final long worldAge, time; + private final long worldAge; + private final long time; } diff --git a/src/main/java/net/glowstone/net/message/play/game/TitleMessage.java b/src/main/java/net/glowstone/net/message/play/game/TitleMessage.java index 97cc2970f6..824ccc801b 100644 --- a/src/main/java/net/glowstone/net/message/play/game/TitleMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/TitleMessage.java @@ -6,14 +6,25 @@ import net.glowstone.util.TextMessage; import net.md_5.bungee.api.chat.BaseComponent; +/** + * Documented at http://wiki.vg/Protocol#Title + */ @Data public final class TitleMessage implements Message { private final Action action; private final TextMessage text; - private final int fadeIn, stay, fadeOut; + private final int fadeIn; + private final int stay; + private final int fadeOut; - // TITLE, SUBTITLE + /** + * Creates an instance with a message. + * + * @param action should be {@link Action#TITLE}, {@link Action#SUBTITLE} or {@link + * Action#ACTION} + * @param text the new text + */ public TitleMessage(Action action, TextMessage text) { this.action = action; this.text = text; @@ -22,7 +33,14 @@ public TitleMessage(Action action, TextMessage text) { fadeOut = 0; } - // TIMES + /** + * Creates an instance with times. + * + * @param action should be {@link Action#TIMES} + * @param fadeIn the fade-in duration in ticks + * @param stay the delay between the end of fade-in and the start of fade-out, in ticks + * @param fadeOut the fade-out duration in ticks + */ public TitleMessage(Action action, int fadeIn, int stay, int fadeOut) { this.action = action; this.fadeIn = fadeIn; @@ -31,7 +49,11 @@ public TitleMessage(Action action, int fadeIn, int stay, int fadeOut) { text = null; } - // CLEAR, RESET + /** + * Creates an instance with no message or times. + * + * @param action should be {@link Action#CLEAR} or {@link Action#RESET} + */ public TitleMessage(Action action) { this.action = action; text = null; @@ -40,15 +62,23 @@ public TitleMessage(Action action) { fadeOut = 0; } + /** + * Converts a {@link Title} to 3 instances of {@link TitleMessage}. + * + * @param title the title to convert + * @return 3 messages: the first sets the title, the second sets the subtitle, and the third + * sets the fade/stay/fade durations + */ public static TitleMessage[] fromTitle(Title title) { TextMessage titleMessage = asTextMessage(BaseComponent.toLegacyText(title.getTitle())); TextMessage subTitleMessage = title.getSubtitle() != null ? asTextMessage( - BaseComponent.toLegacyText(title.getSubtitle())) : asTextMessage(null); + BaseComponent.toLegacyText(title.getSubtitle())) : asTextMessage(null); return new TitleMessage[]{ new TitleMessage(Action.TITLE, titleMessage), new TitleMessage(Action.SUBTITLE, subTitleMessage), - new TitleMessage(Action.TIMES, title.getFadeIn(), title.getStay(), title.getFadeOut()) + new TitleMessage(Action.TIMES, title.getFadeIn(), title.getStay(), title + .getFadeOut()) }; } @@ -62,6 +92,9 @@ private static TextMessage asTextMessage(String rawString) { public enum Action { TITLE, SUBTITLE, + /** + * Set text above the action bar. + */ ACTION, TIMES, CLEAR, diff --git a/src/main/java/net/glowstone/net/message/play/game/UnloadChunkMessage.java b/src/main/java/net/glowstone/net/message/play/game/UnloadChunkMessage.java index 0119ee913b..8d41fc4ed0 100644 --- a/src/main/java/net/glowstone/net/message/play/game/UnloadChunkMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/UnloadChunkMessage.java @@ -8,5 +8,6 @@ @AllArgsConstructor public class UnloadChunkMessage implements Message { - private final int chunkX, chunkZ; + private final int chunkX; + private final int chunkZ; } diff --git a/src/main/java/net/glowstone/net/message/play/game/UnlockRecipesMessage.java b/src/main/java/net/glowstone/net/message/play/game/UnlockRecipesMessage.java index b58e0eca18..456d9722ae 100644 --- a/src/main/java/net/glowstone/net/message/play/game/UnlockRecipesMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/UnlockRecipesMessage.java @@ -2,8 +2,10 @@ import com.flowpowered.network.Message; import lombok.Data; +import lombok.RequiredArgsConstructor; @Data +@RequiredArgsConstructor public final class UnlockRecipesMessage implements Message { public static final int ACTION_INIT = 0; @@ -11,17 +13,10 @@ public final class UnlockRecipesMessage implements Message { public static final int ACTION_REMOVE = 2; private final int action; - private final boolean bookOpen, filterOpen; - private final int[] recipes, allRecipes; // allRecipes is only set when action = ACTION_INIT (0) - - public UnlockRecipesMessage(int action, boolean bookOpen, boolean filterOpen, int[] recipes, - int[] allRecipes) { - this.action = action; - this.bookOpen = bookOpen; - this.filterOpen = filterOpen; - this.recipes = recipes; - this.allRecipes = allRecipes; - } + private final boolean bookOpen; + private final boolean filterOpen; + private final int[] recipes; + private final int[] allRecipes; // allRecipes is only set when action = ACTION_INIT (0) public UnlockRecipesMessage(int action, boolean bookOpen, boolean filterOpen, int[] recipes) { this(action, bookOpen, filterOpen, recipes, null); diff --git a/src/main/java/net/glowstone/net/message/play/game/UpdateBlockEntityMessage.java b/src/main/java/net/glowstone/net/message/play/game/UpdateBlockEntityMessage.java index 7313c4c888..6808723fb1 100644 --- a/src/main/java/net/glowstone/net/message/play/game/UpdateBlockEntityMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/UpdateBlockEntityMessage.java @@ -7,7 +7,10 @@ @Data public final class UpdateBlockEntityMessage implements Message { - private final int x, y, z, action; + private final int x; + private final int y; + private final int z; + private final int action; private final CompoundTag nbt; } diff --git a/src/main/java/net/glowstone/net/message/play/game/UpdateSignMessage.java b/src/main/java/net/glowstone/net/message/play/game/UpdateSignMessage.java index 2b37708959..7343080dbd 100644 --- a/src/main/java/net/glowstone/net/message/play/game/UpdateSignMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/UpdateSignMessage.java @@ -7,9 +7,20 @@ @Data public final class UpdateSignMessage implements Message { - private final int x, y, z; + private final int x; + private final int y; + private final int z; private final TextMessage[] message; + /** + * Creates a message. + * + * @param x the sign X coordinate + * @param y the sign Y coordinate + * @param z the sign Z coordinate + * @param message 4 messages, each containing a line of the sign's new contents + * @throws IllegalArgumentException if {@code message.length != 4} + */ public UpdateSignMessage(int x, int y, int z, TextMessage[] message) { if (message.length != 4) { throw new IllegalArgumentException(); @@ -21,6 +32,16 @@ public UpdateSignMessage(int x, int y, int z, TextMessage[] message) { this.message = message; } + /** + * Builds an UpdateSignMessage from 4 strings. + * + * @param x the sign X coordinate + * @param y the sign Y coordinate + * @param z the sign Z coordinate + * @param message 4 strings, each containing a line of the sign's new contents + * @return an UpdateSignMessage for the parameters + * @throws IllegalArgumentException if {@code message} isn't exactly 4 strings + */ public static UpdateSignMessage fromPlainText(int x, int y, int z, String... message) { if (message.length != 4) { throw new IllegalArgumentException(); diff --git a/src/main/java/net/glowstone/net/message/play/game/UserListHeaderFooterMessage.java b/src/main/java/net/glowstone/net/message/play/game/UserListHeaderFooterMessage.java index 8a86a1d87c..1284cbc072 100644 --- a/src/main/java/net/glowstone/net/message/play/game/UserListHeaderFooterMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/UserListHeaderFooterMessage.java @@ -7,6 +7,7 @@ @Data public final class UserListHeaderFooterMessage implements Message { - private final TextMessage header, footer; + private final TextMessage header; + private final TextMessage footer; } diff --git a/src/main/java/net/glowstone/net/message/play/game/UserListItemMessage.java b/src/main/java/net/glowstone/net/message/play/game/UserListItemMessage.java index a9f02f8711..0a556aa18d 100644 --- a/src/main/java/net/glowstone/net/message/play/game/UserListItemMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/UserListItemMessage.java @@ -8,12 +8,22 @@ import net.glowstone.entity.meta.profile.PlayerProfile; import net.glowstone.util.TextMessage; +/** + * Documented at http://wiki.vg/Protocol#Player_List_Item + */ @Data public final class UserListItemMessage implements Message { private final Action action; private final List entries; + /** + * Creates an instance. + * + * @param action the action code: 0 = add player; 1 = update gamemode; 2 = update latency; + * 3 = update display name; 4 = remove player + * @param entries the players to add, update or remove + */ public UserListItemMessage(Action action, List entries) { this.action = action; this.entries = entries; @@ -21,7 +31,7 @@ public UserListItemMessage(Action action, List entries) { for (Entry entry : entries) { if (entry.action != action) { throw new IllegalArgumentException( - "Entries must be " + action + ", not " + entry.action); + "Entries must be " + action + ", not " + entry.action); } } } @@ -36,11 +46,20 @@ public static Entry add(PlayerProfile profile) { return add(profile, 0, 0, null); } + /** + * Adds a player to this message. + * + * @param profile the player to add + * @param gameMode the player's game mode's value (see {@link org.bukkit.GameMode}) + * @param ping the player's ping time in milliseconds (TODO: is this up, down, or round-trip?) + * @param displayName the name to display for the player + * @return + */ public static Entry add(PlayerProfile profile, int gameMode, int ping, - TextMessage displayName) { + TextMessage displayName) { // TODO measure ping return new Entry(profile.getUniqueId(), profile, gameMode, ping, displayName, - Action.ADD_PLAYER); + Action.ADD_PLAYER); } public static UserListItemMessage addOne(PlayerProfile profile) { diff --git a/src/main/java/net/glowstone/net/message/play/game/WorldBorderMessage.java b/src/main/java/net/glowstone/net/message/play/game/WorldBorderMessage.java index 3a295e09e4..77faf7ad67 100644 --- a/src/main/java/net/glowstone/net/message/play/game/WorldBorderMessage.java +++ b/src/main/java/net/glowstone/net/message/play/game/WorldBorderMessage.java @@ -5,16 +5,21 @@ import lombok.Data; import lombok.RequiredArgsConstructor; +/** Documented at http://wiki.vg/Protocol#World_Border */ @Data @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public final class WorldBorderMessage implements Message { private final Action action; private final double radius; - private final double oldRadius, newRadius; + private final double oldRadius; + private final double newRadius; private final long speed; - private final double x, z; - private final int portalTeleportBoundary, warningTime, warningBlocks; + private final double x; + private final double z; + private final int portalTeleportBoundary; + private final int warningTime; + private final int warningBlocks; // SET_SIZE public WorldBorderMessage(Action action, double radius) { @@ -38,7 +43,12 @@ public WorldBorderMessage(Action action, double x, double z, double oldRadius, d warningBlocks); } - // SET_WARNING_TIME, SET_WARNING_BLOCKS + /** + * Creates an instance with a warning threshold. + * + * @param action should be {@link Action#SET_WARNING_TIME} or {@link Action#SET_WARNING_BLOCKS} + * @param warning the warning threshold, in blocks or seconds + */ public WorldBorderMessage(Action action, int warning) { if (action == Action.SET_WARNING_TIME) { warningTime = warning; diff --git a/src/main/java/net/glowstone/net/message/play/inv/OpenWindowMessage.java b/src/main/java/net/glowstone/net/message/play/inv/OpenWindowMessage.java index 0eb71fd391..36cecc47c4 100644 --- a/src/main/java/net/glowstone/net/message/play/inv/OpenWindowMessage.java +++ b/src/main/java/net/glowstone/net/message/play/inv/OpenWindowMessage.java @@ -12,7 +12,8 @@ public final class OpenWindowMessage implements Message { private final int id; private final String type; private final TextMessage title; - private final int slots, entityId; + private final int slots; + private final int entityId; public OpenWindowMessage(int id, String type, String title, int slots) { this(id, type, new TextMessage(title), slots, 0); diff --git a/src/main/java/net/glowstone/net/message/play/inv/SetWindowSlotMessage.java b/src/main/java/net/glowstone/net/message/play/inv/SetWindowSlotMessage.java index 568569b7c1..a5956ab4a6 100644 --- a/src/main/java/net/glowstone/net/message/play/inv/SetWindowSlotMessage.java +++ b/src/main/java/net/glowstone/net/message/play/inv/SetWindowSlotMessage.java @@ -7,7 +7,8 @@ @Data public final class SetWindowSlotMessage implements Message { - private final int id, slot; + private final int id; + private final int slot; private final ItemStack item; } diff --git a/src/main/java/net/glowstone/net/message/play/inv/TransactionMessage.java b/src/main/java/net/glowstone/net/message/play/inv/TransactionMessage.java index e16879d21c..4d4a38a3c9 100644 --- a/src/main/java/net/glowstone/net/message/play/inv/TransactionMessage.java +++ b/src/main/java/net/glowstone/net/message/play/inv/TransactionMessage.java @@ -6,7 +6,8 @@ @Data public final class TransactionMessage implements Message { - private final int id, transaction; + private final int id; + private final int transaction; private final boolean accepted; } diff --git a/src/main/java/net/glowstone/net/message/play/inv/WindowClickMessage.java b/src/main/java/net/glowstone/net/message/play/inv/WindowClickMessage.java index d020c6a6a9..042ae6b1f7 100644 --- a/src/main/java/net/glowstone/net/message/play/inv/WindowClickMessage.java +++ b/src/main/java/net/glowstone/net/message/play/inv/WindowClickMessage.java @@ -7,7 +7,11 @@ @Data public final class WindowClickMessage implements Message { - private final int id, slot, button, transaction, mode; + private final int id; + private final int slot; + private final int button; + private final int transaction; + private final int mode; private final ItemStack item; } diff --git a/src/main/java/net/glowstone/net/message/play/inv/WindowPropertyMessage.java b/src/main/java/net/glowstone/net/message/play/inv/WindowPropertyMessage.java index e4d2382237..e80ce97c33 100644 --- a/src/main/java/net/glowstone/net/message/play/inv/WindowPropertyMessage.java +++ b/src/main/java/net/glowstone/net/message/play/inv/WindowPropertyMessage.java @@ -6,6 +6,8 @@ @Data public final class WindowPropertyMessage implements Message { - private final int id, property, value; + private final int id; + private final int property; + private final int value; } diff --git a/src/main/java/net/glowstone/net/message/play/player/InteractEntityMessage.java b/src/main/java/net/glowstone/net/message/play/player/InteractEntityMessage.java index 4841bc0e73..7e5738e813 100644 --- a/src/main/java/net/glowstone/net/message/play/player/InteractEntityMessage.java +++ b/src/main/java/net/glowstone/net/message/play/player/InteractEntityMessage.java @@ -9,8 +9,11 @@ @RequiredArgsConstructor public final class InteractEntityMessage implements Message { - private final int id, action; - private final float targetX, targetY, targetZ; + private final int id; + private final int action; + private final float targetX; + private final float targetY; + private final float targetZ; private final int hand; // 0 = main hand, 1 = off hand public InteractEntityMessage(int id, int action) { diff --git a/src/main/java/net/glowstone/net/message/play/player/PlayerAbilitiesMessage.java b/src/main/java/net/glowstone/net/message/play/player/PlayerAbilitiesMessage.java index f39e525fe8..e4bc5ecb74 100644 --- a/src/main/java/net/glowstone/net/message/play/player/PlayerAbilitiesMessage.java +++ b/src/main/java/net/glowstone/net/message/play/player/PlayerAbilitiesMessage.java @@ -7,7 +7,8 @@ public final class PlayerAbilitiesMessage implements Message { private final int flags; - private final float flySpeed, walkSpeed; + private final float flySpeed; + private final float walkSpeed; } diff --git a/src/main/java/net/glowstone/net/message/play/player/PlayerActionMessage.java b/src/main/java/net/glowstone/net/message/play/player/PlayerActionMessage.java index 1f5ee6722a..5c93a0ead0 100644 --- a/src/main/java/net/glowstone/net/message/play/player/PlayerActionMessage.java +++ b/src/main/java/net/glowstone/net/message/play/player/PlayerActionMessage.java @@ -6,7 +6,9 @@ @Data public final class PlayerActionMessage implements Message { - private final int id, action, jumpBoost; + private final int id; + private final int action; + private final int jumpBoost; } diff --git a/src/main/java/net/glowstone/net/message/play/player/PlayerLookMessage.java b/src/main/java/net/glowstone/net/message/play/player/PlayerLookMessage.java index 09ce88ab12..fb3893c885 100644 --- a/src/main/java/net/glowstone/net/message/play/player/PlayerLookMessage.java +++ b/src/main/java/net/glowstone/net/message/play/player/PlayerLookMessage.java @@ -8,8 +8,16 @@ @EqualsAndHashCode(callSuper = true) public final class PlayerLookMessage extends PlayerUpdateMessage { - private final float yaw, pitch; + private final float yaw; + private final float pitch; + /** + * Creates a message to update the direction a player is facing. + * + * @param yaw the yaw angle + * @param pitch the pitch angle + * @param onGround whether the player is on the ground + */ public PlayerLookMessage(float yaw, float pitch, boolean onGround) { super(onGround); this.yaw = (yaw % 360 + 360) % 360; @@ -24,11 +32,11 @@ public void update(Location location) { @Override public String toString() { - return "PlayerLookMessage(" + - "yaw=" + yaw + - ", pitch=" + pitch + - ", onGround=" + isOnGround() + - ')'; + return "PlayerLookMessage(" + + "yaw=" + yaw + + ", pitch=" + pitch + + ", onGround=" + isOnGround() + + ')'; } } diff --git a/src/main/java/net/glowstone/net/message/play/player/PlayerPositionLookMessage.java b/src/main/java/net/glowstone/net/message/play/player/PlayerPositionLookMessage.java index 9a02208d9e..8801428382 100644 --- a/src/main/java/net/glowstone/net/message/play/player/PlayerPositionLookMessage.java +++ b/src/main/java/net/glowstone/net/message/play/player/PlayerPositionLookMessage.java @@ -8,9 +8,22 @@ @EqualsAndHashCode(callSuper = true) public final class PlayerPositionLookMessage extends PlayerUpdateMessage { - private final double x, y, z; - private final float yaw, pitch; - + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + + /** + * Creates a message to update a player's location and facing direction. + * + * @param x the player's X coordinate + * @param y the player's Y coordinate + * @param z the player's Z coordinate + * @param yaw the yaw angle + * @param pitch the pitch angle + * @param onGround whether the player is on the ground + */ public PlayerPositionLookMessage(boolean onGround, double x, double y, double z, float yaw, float pitch) { super(onGround); @@ -37,14 +50,14 @@ public boolean moved() { @Override public String toString() { - return "PlayerPositionLookMessage(" + - "onGround=" + isOnGround() + - ", x=" + x + - ", y=" + y + - ", z=" + z + - ", yaw=" + yaw + - ", pitch=" + pitch + - ')'; + return "PlayerPositionLookMessage(" + + "onGround=" + isOnGround() + + ", x=" + x + + ", y=" + y + + ", z=" + z + + ", yaw=" + yaw + + ", pitch=" + pitch + + ')'; } } diff --git a/src/main/java/net/glowstone/net/message/play/player/PlayerPositionMessage.java b/src/main/java/net/glowstone/net/message/play/player/PlayerPositionMessage.java index 45a4e3efc8..4ad14660ae 100644 --- a/src/main/java/net/glowstone/net/message/play/player/PlayerPositionMessage.java +++ b/src/main/java/net/glowstone/net/message/play/player/PlayerPositionMessage.java @@ -8,8 +8,18 @@ @EqualsAndHashCode(callSuper = true) public final class PlayerPositionMessage extends PlayerUpdateMessage { - private final double x, y, z; - + private final double x; + private final double y; + private final double z; + + /** + * Creates a message to update a player's location. + * + * @param x the player's X coordinate + * @param y the player's Y coordinate + * @param z the player's Z coordinate + * @param onGround whether the player is on the ground + */ public PlayerPositionMessage(boolean onGround, double x, double y, double z) { super(onGround); this.x = x; @@ -31,12 +41,12 @@ public boolean moved() { @Override public String toString() { - return "PlayerPositionMessage(" + - "onGround=" + isOnGround() + - ", x=" + x + - ", y=" + y + - ", z=" + z + - ')'; + return "PlayerPositionMessage(" + + "onGround=" + isOnGround() + + ", x=" + x + + ", y=" + y + + ", z=" + z + + ')'; } } diff --git a/src/main/java/net/glowstone/net/message/play/player/ResourcePackSendMessage.java b/src/main/java/net/glowstone/net/message/play/player/ResourcePackSendMessage.java index 3b4302a7dd..3def20da25 100644 --- a/src/main/java/net/glowstone/net/message/play/player/ResourcePackSendMessage.java +++ b/src/main/java/net/glowstone/net/message/play/player/ResourcePackSendMessage.java @@ -6,5 +6,6 @@ @Data public final class ResourcePackSendMessage implements Message { - private final String url, hash; + private final String url; + private final String hash; } diff --git a/src/main/java/net/glowstone/net/message/play/player/SteerBoatMessage.java b/src/main/java/net/glowstone/net/message/play/player/SteerBoatMessage.java index 1792408d08..15596648f7 100644 --- a/src/main/java/net/glowstone/net/message/play/player/SteerBoatMessage.java +++ b/src/main/java/net/glowstone/net/message/play/player/SteerBoatMessage.java @@ -6,5 +6,6 @@ @Data public class SteerBoatMessage implements Message { - private final boolean isRightPaddleTurning, isLeftPaddleTurning; + private final boolean isRightPaddleTurning; + private final boolean isLeftPaddleTurning; } diff --git a/src/main/java/net/glowstone/net/message/play/player/SteerVehicleMessage.java b/src/main/java/net/glowstone/net/message/play/player/SteerVehicleMessage.java index 77d07cfe9a..828e8db82c 100644 --- a/src/main/java/net/glowstone/net/message/play/player/SteerVehicleMessage.java +++ b/src/main/java/net/glowstone/net/message/play/player/SteerVehicleMessage.java @@ -6,8 +6,10 @@ @Data public final class SteerVehicleMessage implements Message { - private final float sideways, forward; - private final boolean jump, unmount; + private final float sideways; + private final float forward; + private final boolean jump; + private final boolean unmount; } diff --git a/src/main/java/net/glowstone/net/message/play/player/TeleportConfirmMessage.java b/src/main/java/net/glowstone/net/message/play/player/TeleportConfirmMessage.java index 567ff15765..ca5efb1a36 100644 --- a/src/main/java/net/glowstone/net/message/play/player/TeleportConfirmMessage.java +++ b/src/main/java/net/glowstone/net/message/play/player/TeleportConfirmMessage.java @@ -6,5 +6,5 @@ @Data public class TeleportConfirmMessage implements Message { - private final int teleportID; + private final int teleportId; } diff --git a/src/main/java/net/glowstone/net/message/play/player/UseBedMessage.java b/src/main/java/net/glowstone/net/message/play/player/UseBedMessage.java index 43019b37fa..2f81ebed6c 100644 --- a/src/main/java/net/glowstone/net/message/play/player/UseBedMessage.java +++ b/src/main/java/net/glowstone/net/message/play/player/UseBedMessage.java @@ -6,6 +6,9 @@ @Data public final class UseBedMessage implements Message { - private final int id, x, y, z; + private final int id; + private final int x; + private final int y; + private final int z; } diff --git a/src/main/java/net/glowstone/net/pipeline/MessageHandler.java b/src/main/java/net/glowstone/net/pipeline/MessageHandler.java index 065298dad4..82de5802ce 100644 --- a/src/main/java/net/glowstone/net/pipeline/MessageHandler.java +++ b/src/main/java/net/glowstone/net/pipeline/MessageHandler.java @@ -15,7 +15,7 @@ public final class MessageHandler extends SimpleChannelInboundHandler { /** - * The associated session + * The associated session. */ private final AtomicReference session = new AtomicReference<>(null); private final GameServer connectionManager; @@ -23,7 +23,8 @@ public final class MessageHandler extends SimpleChannelInboundHandler { /** * Creates a new network event handler. * - * @param connectionManager The connection manager to manage connections for this message handler. + * @param connectionManager The connection manager to manage connections for this message + * handler. */ public MessageHandler(GameServer connectionManager) { this.connectionManager = connectionManager; @@ -61,7 +62,4 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { session.get().onInboundThrowable(cause); } - public AtomicReference getSession() { - return session; - } } diff --git a/src/main/java/net/glowstone/net/protocol/GlowProtocol.java b/src/main/java/net/glowstone/net/protocol/GlowProtocol.java index 255852895d..f5130630dd 100644 --- a/src/main/java/net/glowstone/net/protocol/GlowProtocol.java +++ b/src/main/java/net/glowstone/net/protocol/GlowProtocol.java @@ -22,6 +22,12 @@ public abstract class GlowProtocol extends AbstractProtocol { private final CodecLookupService outboundCodecs; private final HandlerLookupService handlers; + /** + * Creates an instance. + * + * @param name the name of the protocol + * @param highestOpcode the highest opcode this protocol will use + */ public GlowProtocol(String name, int highestOpcode) { super(name); inboundCodecs = new CodecLookupService(highestOpcode + 1); @@ -29,7 +35,8 @@ public GlowProtocol(String name, int highestOpcode) { handlers = new HandlerLookupService(); } - protected , H extends MessageHandler> void inbound( + protected , + H extends MessageHandler> void inbound( int opcode, Class message, Class codec, Class handler) { try { inboundCodecs.bind(message, codec, opcode); diff --git a/src/main/java/net/glowstone/net/protocol/LoginProtocol.java b/src/main/java/net/glowstone/net/protocol/LoginProtocol.java index 5acab86d83..72fb0d6055 100644 --- a/src/main/java/net/glowstone/net/protocol/LoginProtocol.java +++ b/src/main/java/net/glowstone/net/protocol/LoginProtocol.java @@ -17,6 +17,9 @@ public final class LoginProtocol extends GlowProtocol { + /** + * Creates the instance. + */ public LoginProtocol() { super("LOGIN", 5); diff --git a/src/main/java/net/glowstone/net/protocol/PlayProtocol.java b/src/main/java/net/glowstone/net/protocol/PlayProtocol.java index 2f3da20b2a..4762c00ffb 100644 --- a/src/main/java/net/glowstone/net/protocol/PlayProtocol.java +++ b/src/main/java/net/glowstone/net/protocol/PlayProtocol.java @@ -241,6 +241,9 @@ public class PlayProtocol extends GlowProtocol { + /** + * Creates the instance for the game's main network protocol. + */ public PlayProtocol() { super("PLAY", 0x4F); diff --git a/src/main/java/net/glowstone/net/protocol/ProtocolType.java b/src/main/java/net/glowstone/net/protocol/ProtocolType.java index 9733b06f65..298aeb81b6 100644 --- a/src/main/java/net/glowstone/net/protocol/ProtocolType.java +++ b/src/main/java/net/glowstone/net/protocol/ProtocolType.java @@ -1,26 +1,23 @@ package net.glowstone.net.protocol; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + /** * Enumeration of the different Minecraft protocol states. */ +@Getter +@RequiredArgsConstructor public enum ProtocolType { HANDSHAKE(new HandshakeProtocol()), STATUS(new StatusProtocol()), LOGIN(new LoginProtocol()), PLAY(new PlayProtocol()); - private final GlowProtocol protocol; - - ProtocolType(GlowProtocol protocol) { - this.protocol = protocol; - } - /** * Get a GlowProtocol corresponding to this protocol type. * * @return A matching GlowProtocol. */ - public GlowProtocol getProtocol() { - return protocol; - } + private final GlowProtocol protocol; } diff --git a/src/main/java/net/glowstone/net/protocol/StatusProtocol.java b/src/main/java/net/glowstone/net/protocol/StatusProtocol.java index f297c024e0..13f5f6e1c4 100644 --- a/src/main/java/net/glowstone/net/protocol/StatusProtocol.java +++ b/src/main/java/net/glowstone/net/protocol/StatusProtocol.java @@ -11,6 +11,10 @@ public final class StatusProtocol extends GlowProtocol { + /** + * Creates the protocol instance for {@link StatusPingMessage}, {@link StatusRequestMessage} and + * {@link StatusResponseMessage}. + */ public StatusProtocol() { super("STATUS", 2); diff --git a/src/main/java/net/glowstone/net/query/QueryHandler.java b/src/main/java/net/glowstone/net/query/QueryHandler.java index 30b67385e1..d54cc16b83 100644 --- a/src/main/java/net/glowstone/net/query/QueryHandler.java +++ b/src/main/java/net/glowstone/net/query/QueryHandler.java @@ -31,7 +31,7 @@ public class QueryHandler extends SimpleChannelInboundHandler { private QueryServer queryServer; /** - * Whether the a plugin list should be included in responses. + * Whether the plugin list should be included in responses. */ private boolean showPlugins; diff --git a/src/main/java/net/glowstone/net/query/QueryServer.java b/src/main/java/net/glowstone/net/query/QueryServer.java index 28f9c2aa33..bee4266d1c 100644 --- a/src/main/java/net/glowstone/net/query/QueryServer.java +++ b/src/main/java/net/glowstone/net/query/QueryServer.java @@ -28,6 +28,14 @@ public class QueryServer extends GlowDatagramServer { */ private ChallengeTokenFlushTask flushTask; + /** + * Creates an instance for the specified server. + * + * @param server the associated GlowServer + * @param latch The countdown latch used during server startup to wait for network server + * binding. + * @param showPlugins whether the plugin list should be included in responses + */ public QueryServer(GlowServer server, CountDownLatch latch, boolean showPlugins) { super(server, latch); bootstrap.handler(new QueryHandler(this, showPlugins)); @@ -39,8 +47,10 @@ public QueryServer(GlowServer server, CountDownLatch latch, boolean showPlugins) * @param address The address. * @return Netty channel future for bind operation. */ + @Override public ChannelFuture bind(InetSocketAddress address) { - GlowServer.logger.info("Binding query to address " + address + "..."); + GlowServer.logger.info("Binding query to address " + + address.getAddress().getHostAddress() + ":" + address.getPort() + "..."); if (flushTask == null) { flushTask = new ChallengeTokenFlushTask(); flushTask.runTaskTimerAsynchronously(null, 600, 600); @@ -51,6 +61,7 @@ public ChannelFuture bind(InetSocketAddress address) { /** * Shut the query server down. */ + @Override public void shutdown() { super.shutdown(); if (flushTask != null) { @@ -90,13 +101,15 @@ public void flushChallengeTokens() { @Override public void onBindSuccess(InetSocketAddress address) { - GlowServer.logger.info("Successfully bound query to " + address + '.'); + GlowServer.logger.info("Successfully bound query to " + + address.getAddress().getHostAddress() + ":" + address.getPort() + '.'); super.onBindSuccess(address); } @Override public void onBindFailure(InetSocketAddress address, Throwable t) { - GlowServer.logger.warning("Failed to bind query to" + address + '.'); + GlowServer.logger.warning("Failed to bind query to " + + address.getAddress().getHostAddress() + ":" + address.getPort() + '.'); } /** diff --git a/src/main/java/net/glowstone/net/rcon/RconCommandSender.java b/src/main/java/net/glowstone/net/rcon/RconCommandSender.java index 105270b813..3561ae3b62 100644 --- a/src/main/java/net/glowstone/net/rcon/RconCommandSender.java +++ b/src/main/java/net/glowstone/net/rcon/RconCommandSender.java @@ -1,9 +1,9 @@ package net.glowstone.net.rcon; import java.util.Set; +import lombok.Getter; import net.glowstone.GlowServer; import net.md_5.bungee.api.chat.BaseComponent; -import org.bukkit.Server; import org.bukkit.command.RemoteConsoleCommandSender; import org.bukkit.permissions.PermissibleBase; import org.bukkit.permissions.Permission; @@ -13,6 +13,7 @@ public class RconCommandSender implements RemoteConsoleCommandSender { + @Getter private final GlowServer server; private final StringBuffer buffer = new StringBuffer(); private final PermissibleBase perm = new PermissibleBase(this); @@ -32,17 +33,20 @@ public RconCommandSender(GlowServer server) { this.server = server; } + /** + * Empties the buffer and returns its contents. + * + * @return the previous contents of the buffer. + */ public String flush() { - String result = buffer.toString(); - buffer.setLength(0); + String result; + synchronized (buffer) { + result = buffer.toString(); + buffer.setLength(0); + } return result; } - @Override - public Server getServer() { - return server; - } - @Override public String getName() { return "Rcon"; diff --git a/src/main/java/net/glowstone/net/rcon/RconHandler.java b/src/main/java/net/glowstone/net/rcon/RconHandler.java index 8109398e27..d9e6d815d1 100644 --- a/src/main/java/net/glowstone/net/rcon/RconHandler.java +++ b/src/main/java/net/glowstone/net/rcon/RconHandler.java @@ -21,6 +21,7 @@ public class RconHandler extends SimpleChannelInboundHandler { private static final byte TYPE_COMMAND = 2; private static final byte TYPE_LOGIN = 3; + // FIXME: This is a password stored in plain text! private final String password; private boolean loggedIn; @@ -35,6 +36,12 @@ public class RconHandler extends SimpleChannelInboundHandler { */ private RconCommandSender commandSender; + /** + * Creates a remote console handler. + * + * @param rconServer the associated server + * @param password the remote operator's password + */ public RconHandler(RconServer rconServer, String password) { this.rconServer = rconServer; this.password = password; @@ -72,6 +79,7 @@ private void handleLogin(ChannelHandlerContext ctx, String payload, int requestI sendResponse(ctx, requestId, TYPE_COMMAND, ""); GlowServer.logger.info("Rcon connection from [" + ctx.channel().remoteAddress() + "]"); } else { + // FIXME: Throttle online brute-force attacks! loggedIn = false; sendResponse(ctx, FAILURE, TYPE_COMMAND, ""); } diff --git a/src/main/java/net/glowstone/net/rcon/RconServer.java b/src/main/java/net/glowstone/net/rcon/RconServer.java index 33a8481f5c..faebac19a4 100644 --- a/src/main/java/net/glowstone/net/rcon/RconServer.java +++ b/src/main/java/net/glowstone/net/rcon/RconServer.java @@ -15,6 +15,14 @@ */ public class RconServer extends GlowSocketServer { + /** + * Creates an instance. + * + * @param server the associated GlowServer + * @param latch The countdown latch used during server startup to wait for network server + * binding. + * @param password the remote operator's password + */ public RconServer(GlowServer server, CountDownLatch latch, String password) { super(server, latch); bootstrap.childHandler(new ChannelInitializer() { @@ -33,25 +41,30 @@ public void initChannel(SocketChannel ch) throws Exception { * @param address The address. * @return Netty channel future for bind operation. */ + @Override public ChannelFuture bind(InetSocketAddress address) { - GlowServer.logger.info("Binding rcon to " + address + "..."); + GlowServer.logger.info("Binding rcon to " + + address.getAddress().getHostAddress() + ":" + address.getPort() + "..."); return super.bind(address); } @Override public void onBindSuccess(InetSocketAddress address) { - GlowServer.logger.info("Successfully bound rcon to " + address + '.'); + GlowServer.logger.info("Successfully bound rcon to " + + address.getAddress().getHostAddress() + ":" + address.getPort() + '.'); super.onBindSuccess(address); } @Override public void onBindFailure(InetSocketAddress address, Throwable t) { - GlowServer.logger.warning("Failed to bind rcon to " + address + '.'); + GlowServer.logger.warning("Failed to bind rcon to " + + address.getAddress().getHostAddress() + ":" + address.getPort() + '.'); } /** * Shut the Rcon server down. */ + @Override public void shutdown() { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); diff --git a/src/main/java/net/glowstone/scheduler/GlowScheduler.java b/src/main/java/net/glowstone/scheduler/GlowScheduler.java index 1ed0a7eef6..63c57b8c92 100644 --- a/src/main/java/net/glowstone/scheduler/GlowScheduler.java +++ b/src/main/java/net/glowstone/scheduler/GlowScheduler.java @@ -46,7 +46,7 @@ public final class GlowScheduler implements BukkitScheduler { private final ScheduledExecutorService executor = Executors .newSingleThreadScheduledExecutor(GlowThreadFactory.INSTANCE); /** - * Executor to handle execution of async tasks + * Executor to handle execution of async tasks. */ private final ExecutorService asyncTaskExecutor = Executors .newCachedThreadPool(GlowThreadFactory.INSTANCE); @@ -55,19 +55,19 @@ public final class GlowScheduler implements BukkitScheduler { */ private final ConcurrentMap tasks = new ConcurrentHashMap<>(); /** - * World tick scheduler + * World tick scheduler. */ private final WorldScheduler worlds; /** - * Tasks to be executed during the tick + * Tasks to be executed during the tick. */ private final Deque inTickTasks = new ConcurrentLinkedDeque<>(); /** - * Condition to wait on when processing in tick tasks + * Condition to wait on when processing in-tick tasks. */ private final Object inTickTaskCondition; /** - * Runnable to run at end of tick + * Runnable to run at end of tick. */ private final Runnable tickEndRun; /** @@ -79,7 +79,8 @@ public final class GlowScheduler implements BukkitScheduler { * Creates a new task scheduler. * * @param server The server that will use this scheduler. - * @param worlds The {@link WorldScheduler} this scheduler will use for ticking the server's worlds. + * @param worlds The {@link WorldScheduler} this scheduler will use for ticking the server's + * worlds. */ public GlowScheduler(GlowServer server, WorldScheduler worlds) { this.server = server; @@ -89,6 +90,9 @@ public GlowScheduler(GlowServer server, WorldScheduler worlds) { primaryThread = Thread.currentThread(); } + /** + * Starts running ticks. + */ public void start() { executor.scheduleAtFixedRate(() -> { try { @@ -134,6 +138,11 @@ public boolean isPrimaryThread() { return Thread.currentThread() == primaryThread; } + /** + * Schedules the given task for the start of the next tick. + * + * @param run the task to run + */ public void scheduleInTickExecution(Runnable run) { if (isPrimaryThread() || executor.isShutdown()) { run.run(); @@ -146,7 +155,8 @@ public void scheduleInTickExecution(Runnable run) { } /** - * Adds new tasks and updates existing tasks, removing them if necessary.
todo: Add watchdog system to make sure ticks advance + * Adds new tasks and updates existing tasks, removing them if necessary.
+ * todo: Add watchdog system to make sure ticks advance */ private void pulse() { primaryThread = Thread.currentThread(); @@ -167,6 +177,9 @@ private void pulse() { break; case STOP: it.remove(); + break; + default: + // do nothing } } try { @@ -331,6 +344,14 @@ public Future callSyncMethod(Plugin plugin, Callable task) { return future; } + /** + * Runs a task on the primary thread, and blocks waiting for it to finish. + * + * @param task the task to run + * @param the task's return type + * @return the task result + * @throws Exception if thrown by the task + */ public T syncIfNeeded(Callable task) throws Exception { if (isPrimaryThread()) { return task.call(); @@ -366,7 +387,7 @@ public boolean isQueued(int taskId) { } /** - * Returns active async tasks + * Returns active async tasks. * * @return active async tasks */ @@ -378,7 +399,7 @@ public List getActiveWorkers() { } /** - * Returns tasks that still have at least one run remaining + * Returns tasks that still have at least one run remaining. * * @return the tasks to be run */ diff --git a/src/main/java/net/glowstone/scheduler/GlowTask.java b/src/main/java/net/glowstone/scheduler/GlowTask.java index b929dad094..84d0cadc5b 100644 --- a/src/main/java/net/glowstone/scheduler/GlowTask.java +++ b/src/main/java/net/glowstone/scheduler/GlowTask.java @@ -5,6 +5,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; +import lombok.Getter; import net.glowstone.GlowServer; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitTask; @@ -25,11 +26,13 @@ public class GlowTask extends FutureTask implements BukkitTask, BukkitWork /** * The ID of this task. */ + @Getter private final int taskId; /** - * The Plugin that owns this task + * The Plugin that owns this task. */ + @Getter private final Plugin owner; /** @@ -42,8 +45,9 @@ public class GlowTask extends FutureTask implements BukkitTask, BukkitWork */ private final long period; /** - * A flag indicating whether this task is to be run asynchronously + * A flag indicating whether this task is to be run asynchronously. */ + @Getter private final boolean sync; /** * A description of the runnable assigned to this task. @@ -56,14 +60,18 @@ public class GlowTask extends FutureTask implements BukkitTask, BukkitWork /** * The thread this task has been last executed on, if this task is async. */ - private Thread executionThread; + @Getter + private Thread thread; /** - * Return the last state returned by {@link #shouldExecute()} + * The last execution state returned by {@link #shouldExecute()} (most likely the state the task + * is currently in). */ + @Getter private volatile TaskExecutionState lastExecutionState = TaskExecutionState.WAIT; /** - * Creates a new task with the specified number of ticks between consecutive calls to execute(). + * Creates a new task with the specified number of ticks between consecutive calls to + * execute(). * * @param owner The plugin which started the task. * @param task The runnable for this task. @@ -84,35 +92,12 @@ public GlowTask(Plugin owner, Runnable task, boolean sync, long delay, long peri @Override public String toString() { - return "GlowTask{" + - "id=" + taskId + - ", plugin=" + owner + - ", sync=" + sync + - ": " + description + - '}'; - } - - /** - * Gets the ID of this task. - */ - @Override - public int getTaskId() { - return taskId; - } - - @Override - public boolean isSync() { - return sync; - } - - @Override - public Plugin getOwner() { - return owner; - } - - @Override - public Thread getThread() { - return executionThread; + return "GlowTask{" + + "id=" + taskId + + ", plugin=" + owner + + ", sync=" + sync + + ": " + description + + '}'; } /** @@ -152,18 +137,9 @@ private TaskExecutionState shouldExecuteUpdate() { return TaskExecutionState.WAIT; } - /** - * Return the last execution state returned by {@link #shouldExecute()} - * - * @return the last state (most likely the state the task is currently in) - */ - public TaskExecutionState getLastExecutionState() { - return lastExecutionState; - } - @Override public void run() { - executionThread = Thread.currentThread(); + thread = Thread.currentThread(); if (period == -1) { super.run(); } else { diff --git a/src/main/java/net/glowstone/scheduler/PulseTask.java b/src/main/java/net/glowstone/scheduler/PulseTask.java index 8473355f81..1d227a1020 100644 --- a/src/main/java/net/glowstone/scheduler/PulseTask.java +++ b/src/main/java/net/glowstone/scheduler/PulseTask.java @@ -16,6 +16,14 @@ public class PulseTask extends BukkitRunnable { private long delay; private boolean single; + /** + * Creates a block update task. + * + * @param block the block to update + * @param async whether to run asynchronously + * @param delay the ticks to wait before running the task + * @param single if true, run this task only once; if false, repeat every {@code delay} ticks + */ public PulseTask(GlowBlock block, boolean async, long delay, boolean single) { this.location = block.getLocation(); this.originalMaterial = block.getType(); @@ -24,6 +32,9 @@ public PulseTask(GlowBlock block, boolean async, long delay, boolean single) { this.single = single; } + /** + * Schedules this task. + */ public void startPulseTask() { if (single) { if (async) { diff --git a/src/main/java/net/glowstone/scheduler/TaskExecutionState.java b/src/main/java/net/glowstone/scheduler/TaskExecutionState.java index b5da5fe63d..f8ec92665f 100644 --- a/src/main/java/net/glowstone/scheduler/TaskExecutionState.java +++ b/src/main/java/net/glowstone/scheduler/TaskExecutionState.java @@ -1,19 +1,19 @@ package net.glowstone.scheduler; /** - * Execution states for tasks + * Execution states for tasks. */ enum TaskExecutionState { /** - * This task should be run this tick + * This task should be run this tick. */ RUN, /** - * This task will run later, keep checking + * This task will run later, keep checking. */ WAIT, /** - * This task will never run again, stop trying + * This task will never run again, stop trying. */ STOP, } diff --git a/src/main/java/net/glowstone/scheduler/WorldScheduler.java b/src/main/java/net/glowstone/scheduler/WorldScheduler.java index bb47070fd4..9ca996f4e9 100644 --- a/src/main/java/net/glowstone/scheduler/WorldScheduler.java +++ b/src/main/java/net/glowstone/scheduler/WorldScheduler.java @@ -9,6 +9,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Phaser; import java.util.logging.Level; +import lombok.Getter; import net.glowstone.GlowServer; import net.glowstone.GlowWorld; @@ -19,6 +20,7 @@ */ public class WorldScheduler { + @Getter private final Object advanceCondition = new Object(); private final ExecutorService worldExecutor = Executors.newCachedThreadPool(); private final Phaser tickBegin = new Phaser(1); @@ -26,6 +28,11 @@ public class WorldScheduler { private final List worlds = new CopyOnWriteArrayList<>(); private volatile int currentTick = -1; + /** + * Returns an immutable list of the currently scheduled worlds. + * + * @return the scheduled worlds + */ public List getWorlds() { Builder ret = ImmutableList.builder(); for (WorldEntry entry : worlds) { @@ -34,6 +41,12 @@ public List getWorlds() { return ret.build(); } + /** + * Returns the world with a given name. + * + * @param name the name to look up + * @return the world with that name, or null if none match + */ public GlowWorld getWorld(String name) { for (WorldEntry went : worlds) { if (went.world.getName().equals(name)) { @@ -43,7 +56,14 @@ public GlowWorld getWorld(String name) { return null; } + /** + * Returns the world with a given UUID. + * + * @param uid the UUID to look up + * @return the world with that UUID, or null if none match + */ public GlowWorld getWorld(UUID uid) { + // FIXME: Unnecessary linear time for (WorldEntry went : worlds) { if (went.world.getUID().equals(uid)) { return went.world; @@ -52,6 +72,12 @@ public GlowWorld getWorld(UUID uid) { return null; } + /** + * Attempts to start scheduled ticks for a world. + * + * @param world the world to start ticking + * @return {@code world} if it is now ticking; null otherwise + */ public GlowWorld addWorld(GlowWorld world) { WorldEntry went = new WorldEntry(world); worlds.add(went); @@ -69,6 +95,12 @@ public GlowWorld addWorld(GlowWorld world) { } } + /** + * Stops scheduled ticks for a world. + * + * @param world the world to stop ticking + * @return whether the world had been scheduled + */ public boolean removeWorld(GlowWorld world) { for (WorldEntry entry : worlds) { if (entry.world.equals(world)) { @@ -110,10 +142,6 @@ void doTickEnd() { } } - public Object getAdvanceCondition() { - return advanceCondition; - } - private static class WorldEntry { private final GlowWorld world; diff --git a/src/main/java/net/glowstone/scheduler/package-info.java b/src/main/java/net/glowstone/scheduler/package-info.java index 28d7699e2d..dd46fecddf 100644 --- a/src/main/java/net/glowstone/scheduler/package-info.java +++ b/src/main/java/net/glowstone/scheduler/package-info.java @@ -4,15 +4,18 @@ *

Glowstone has 4 groups of threads: *

    *
  • World threads. One thread per world
  • - *
  • Event/scheduler thread. This thread contains all interaction with Bukkit API and synchronizes all other threads.
  • + *
  • Event/scheduler thread. This thread contains all interaction with Bukkit API and + * synchronizes all other threads.
  • *
  • Async task thread pool. Pool of threads used to execute async tasks
  • *
  • Netty thread pool. This thread pool is used by Netty for network read/write
  • *
* - *

Whenever a thread wishes to call an event or perform other interactions with Bukkit API, - * it calls the {@link net.glowstone.scheduler.GlowScheduler#syncIfNeeded(java.util.concurrent.Callable)}. + *

Whenever a thread wishes to call an event or perform other interactions with Bukkit API, it + * calls the {@link net.glowstone.scheduler.GlowScheduler#syncIfNeeded( + * java.util.concurrent.Callable)}. * - *

The scheduler thread synchronizes the world threads, so that each world thread begins a tick at the beginning of a scheduler pulse. + *

The scheduler thread synchronizes the world threads, so that each world thread begins a tick + * at the beginning of a scheduler pulse. * *

Operation order: *

    diff --git a/src/main/java/net/glowstone/scoreboard/GlowObjective.java b/src/main/java/net/glowstone/scoreboard/GlowObjective.java index a527ba4a59..e59e622a11 100644 --- a/src/main/java/net/glowstone/scoreboard/GlowObjective.java +++ b/src/main/java/net/glowstone/scoreboard/GlowObjective.java @@ -6,6 +6,7 @@ import java.util.HashMap; import java.util.Map.Entry; import java.util.Set; +import lombok.Getter; import net.glowstone.net.message.play.scoreboard.ScoreboardObjectiveMessage; import org.bukkit.OfflinePlayer; import org.bukkit.scoreboard.Criterias; @@ -22,10 +23,19 @@ public final class GlowObjective implements Objective { private final String criteria; private final HashMap scores = new HashMap<>(); DisplaySlot displaySlot; + @Getter private GlowScoreboard scoreboard; private String displayName; private RenderType renderType; + /** + * Creates a scoreboard objective. + * + * @param scoreboard the scoreboard to add to + * @param name the name of the objective + * @param criteria one of the constants from {@link Criterias}, or anything else if this score + * is only modified by commands and/or plugins. + */ public GlowObjective(GlowScoreboard scoreboard, String name, String criteria) { this.scoreboard = scoreboard; this.name = name; @@ -34,10 +44,12 @@ public GlowObjective(GlowScoreboard scoreboard, String name, String criteria) { displayName = name; } - public GlowScoreboard getScoreboard() { - return scoreboard; - } - + /** + * Removes this objective from the scoreboard. + * + * @throws IllegalStateException if this objective already isn't registered with a scoreboard + */ + @Override public void unregister() throws IllegalStateException { checkValid(); for (Entry entry : scores.entrySet()) { @@ -56,21 +68,32 @@ void checkValid() { //////////////////////////////////////////////////////////////////////////// // Properties + @Override public String getName() throws IllegalStateException { checkValid(); return name; } + @Override public String getCriteria() throws IllegalStateException { checkValid(); return criteria; } + @Override public String getDisplayName() throws IllegalStateException { checkValid(); return displayName; } + /** + * Sets the display name. + * + * @param displayName the new display name, up to 32 characters long + * @throws IllegalArgumentException if {@code displayName} is null or longer than 32 characters + * @throws IllegalStateException if this objective isn't registered with a scoreboard + */ + @Override public void setDisplayName(String displayName) throws IllegalStateException, IllegalArgumentException { checkValid(); @@ -82,11 +105,19 @@ public void setDisplayName(String displayName) scoreboard.broadcast(ScoreboardObjectiveMessage.update(name, displayName, renderType)); } + @Override public DisplaySlot getDisplaySlot() throws IllegalStateException { checkValid(); return displaySlot; } + /** + * Sets the {@link DisplaySlot} where this objective displays. + * + * @param slot the DisplaySlot, or null to hide the objective + * @throws IllegalStateException if this objective isn't registered with a scoreboard + */ + @Override public void setDisplaySlot(DisplaySlot slot) throws IllegalStateException { checkValid(); if (slot != displaySlot) { @@ -104,6 +135,13 @@ public RenderType getType() throws IllegalStateException { return renderType; } + /** + * Sets the {@link RenderType} for this objective. + * + * @param renderType the new render type + * @throws IllegalArgumentException if {@code renderType} is null + * @throws IllegalStateException if this objective isn't registered with a scoreboard + */ public void setType(RenderType renderType) throws IllegalStateException { checkValid(); checkNotNull(renderType, "RenderType cannot be null"); @@ -111,6 +149,7 @@ public void setType(RenderType renderType) throws IllegalStateException { scoreboard.broadcast(ScoreboardObjectiveMessage.update(name, displayName, renderType)); } + @Override public boolean isModifiable() throws IllegalStateException { checkValid(); return !criteria.equalsIgnoreCase(Criterias.HEALTH); @@ -119,19 +158,28 @@ public boolean isModifiable() throws IllegalStateException { //////////////////////////////////////////////////////////////////////////// // Score management + /** + * Returns a score, creating it if necessary. + * + * @param entry the key (e.g. player name or team name) + * @return the score for {@code entry} + * @throws IllegalArgumentException if {@code entry} is null + * @throws IllegalStateException if this objective isn't registered with a scoreboard + */ + @Override public Score getScore(String entry) throws IllegalArgumentException, IllegalStateException { checkNotNull(entry, "Entry cannot be null"); checkValid(); - GlowScore score = scores.get(entry); - if (score == null) { - score = new GlowScore(this, entry); - scores.put(entry, score); - scoreboard.getScoresForName(entry).add(score); - } - return score; + return scores.computeIfAbsent(entry, entryCopy -> { + GlowScore score = new GlowScore(this, entryCopy); + scores.put(entryCopy, score); + scoreboard.getScoresForName(entryCopy).add(score); + return score; + }); } + @Override @Deprecated public Score getScore(OfflinePlayer player) throws IllegalArgumentException, IllegalStateException { @@ -152,6 +200,14 @@ public void setRenderType(String renderType) { // TODO } + /** + * Returns whether a score is defined. + * + * @param entry the key (e.g. player name or team name) + * @return true if the score exists; false otherwise + * @throws IllegalArgumentException if {@code entry} is null + * @throws IllegalStateException if this objective isn't registered with a scoreboard + */ public boolean hasScore(String entry) throws IllegalArgumentException, IllegalStateException { checkNotNull(entry, "Entry cannot be null"); checkValid(); diff --git a/src/main/java/net/glowstone/scoreboard/GlowScore.java b/src/main/java/net/glowstone/scoreboard/GlowScore.java index 923563901f..9fafae2b9c 100644 --- a/src/main/java/net/glowstone/scoreboard/GlowScore.java +++ b/src/main/java/net/glowstone/scoreboard/GlowScore.java @@ -1,49 +1,51 @@ package net.glowstone.scoreboard; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; import net.glowstone.net.message.play.scoreboard.ScoreboardScoreMessage; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; -import org.bukkit.scoreboard.Objective; import org.bukkit.scoreboard.Score; import org.bukkit.scoreboard.Scoreboard; /** * Implementation/data holder for Scores. */ +@RequiredArgsConstructor public final class GlowScore implements Score { + @Getter private final GlowObjective objective; + @Getter private final String entry; private int score; + @Setter private boolean locked; - public GlowScore(GlowObjective objective, String entry) { - this.objective = objective; - this.entry = entry; - } - - public Objective getObjective() { - return objective; - } - + @Override public Scoreboard getScoreboard() { return objective.getScoreboard(); } - public String getEntry() { - return entry; - } - + @Override @Deprecated public OfflinePlayer getPlayer() { return Bukkit.getOfflinePlayer(entry); } + @Override public int getScore() throws IllegalStateException { objective.checkValid(); return score; } + /** + * Sets this score's value. + * @param score the new value + * @throws IllegalStateException if the objective is not registered on a scoreboard + */ + @Override public void setScore(int score) throws IllegalStateException { objective.checkValid(); this.score = score; @@ -60,8 +62,4 @@ public boolean isScoreSet() throws IllegalStateException { public boolean getLocked() { return locked; } - - public void setLocked(boolean locked) { - this.locked = locked; - } } diff --git a/src/main/java/net/glowstone/scoreboard/GlowScoreboard.java b/src/main/java/net/glowstone/scoreboard/GlowScoreboard.java index b36ab5ab1d..c552286714 100644 --- a/src/main/java/net/glowstone/scoreboard/GlowScoreboard.java +++ b/src/main/java/net/glowstone/scoreboard/GlowScoreboard.java @@ -218,6 +218,7 @@ void setPlayerTeam(OfflinePlayer player, GlowTeam team) { //////////////////////////////////////////////////////////////////////////// // Objectives + @Override public Objective registerNewObjective(String name, String criteria) throws IllegalArgumentException { checkNotNull(name, "Name cannot be null"); @@ -234,23 +235,28 @@ public Objective registerNewObjective(String name, String criteria) return objective; } + @Override public Objective getObjective(String name) throws IllegalArgumentException { return objectives.get(name); } + @Override public Objective getObjective(DisplaySlot slot) throws IllegalArgumentException { checkNotNull(slot, "Slot cannot be null"); return displaySlots.get(slot); } + @Override public Set getObjectivesByCriteria(String criteria) throws IllegalArgumentException { return ImmutableSet.copyOf(getForCriteria(criteria)); } + @Override public Set getObjectives() { return ImmutableSet.copyOf(objectives.values()); } + @Override public void clearSlot(DisplaySlot slot) throws IllegalArgumentException { checkNotNull(slot, "Slot cannot be null"); setDisplaySlot(slot, null); @@ -259,6 +265,7 @@ public void clearSlot(DisplaySlot slot) throws IllegalArgumentException { //////////////////////////////////////////////////////////////////////////// // Teams + @Override public Team registerNewTeam(String name) throws IllegalArgumentException { checkNotNull(name, "Name cannot be null"); checkArgument(!teams.containsKey(name), "Team \"" + name + "\" already exists"); @@ -269,6 +276,7 @@ public Team registerNewTeam(String name) throws IllegalArgumentException { return team; } + @Override public Team getPlayerTeam(OfflinePlayer player) throws IllegalArgumentException { checkNotNull(player, "Player cannot be null"); return entryTeams.get(player.getName()); @@ -280,11 +288,13 @@ public Team getEntryTeam(String entry) throws IllegalArgumentException { return entryTeams.get(entry); } + @Override public Team getTeam(String teamName) throws IllegalArgumentException { checkNotNull(teamName, "Team name cannot be null"); return teams.get(teamName); } + @Override public Set getTeams() { return ImmutableSet.copyOf(teams.values()); } @@ -292,10 +302,12 @@ public Set getTeams() { //////////////////////////////////////////////////////////////////////////// // Scores + @Override public Set getEntries() { return ImmutableSet.copyOf(scoreMap.keySet()); } + @Override public Set getScores(String entry) throws IllegalArgumentException { checkNotNull(entry, "Entry cannot be null"); @@ -307,12 +319,13 @@ public Set getScores(String entry) throws IllegalArgumentException { } } - @Deprecated + @Override public Set getScores(OfflinePlayer player) throws IllegalArgumentException { checkNotNull(player, "Player cannot be null"); return getScores(player.getName()); } + @Override public void resetScores(String entry) throws IllegalArgumentException { checkNotNull(entry, "Entry cannot be null"); @@ -323,13 +336,13 @@ public void resetScores(String entry) throws IllegalArgumentException { scoreMap.remove(entry); } - @Deprecated + @Override public void resetScores(OfflinePlayer player) throws IllegalArgumentException { checkNotNull(player, "Player cannot be null"); resetScores(player.getName()); } - @Deprecated + @Override public Set getPlayers() { Set result = getEntries().stream().map(Bukkit::getOfflinePlayer) .collect(Collectors.toSet()); diff --git a/src/main/java/net/glowstone/scoreboard/GlowScoreboardManager.java b/src/main/java/net/glowstone/scoreboard/GlowScoreboardManager.java index b95c22c9cf..2759ea0e43 100644 --- a/src/main/java/net/glowstone/scoreboard/GlowScoreboardManager.java +++ b/src/main/java/net/glowstone/scoreboard/GlowScoreboardManager.java @@ -16,6 +16,7 @@ public GlowScoreboardManager(GlowServer server) { this.server = server; } + @Override public GlowScoreboard getMainScoreboard() { if (mainScoreboard == null) { GlowScoreboard newScoreboard; @@ -30,6 +31,7 @@ public GlowScoreboard getMainScoreboard() { } + @Override public GlowScoreboard getNewScoreboard() { return new GlowScoreboard(); } diff --git a/src/main/java/net/glowstone/scoreboard/GlowTeam.java b/src/main/java/net/glowstone/scoreboard/GlowTeam.java index 9f7f9f7f44..71469f743e 100644 --- a/src/main/java/net/glowstone/scoreboard/GlowTeam.java +++ b/src/main/java/net/glowstone/scoreboard/GlowTeam.java @@ -9,12 +9,12 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import lombok.Getter; import net.glowstone.net.message.play.scoreboard.ScoreboardTeamMessage; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; import org.bukkit.scoreboard.NameTagVisibility; -import org.bukkit.scoreboard.Scoreboard; import org.bukkit.scoreboard.Team; /** @@ -24,6 +24,7 @@ public final class GlowTeam implements Team { private final String name; private final HashSet players = new HashSet<>(); + @Getter private GlowScoreboard scoreboard; // properties private String displayName; @@ -32,20 +33,24 @@ public final class GlowTeam implements Team { private Team.OptionStatus nameTagVisibility = Team.OptionStatus.ALWAYS; private Team.OptionStatus deathMessageVisibility = Team.OptionStatus.ALWAYS; private Team.OptionStatus collisionRule = Team.OptionStatus.ALWAYS; + @Getter private ChatColor color = ChatColor.RESET; private boolean friendlyFire; private boolean seeInvisible = true; + /** + * Creates a team. + * + * @param scoreboard the scoreboard for this team's scores + * @param name the team name + */ public GlowTeam(GlowScoreboard scoreboard, String name) { this.scoreboard = scoreboard; this.name = name; displayName = name; } - public Scoreboard getScoreboard() { - return scoreboard; - } - + @Override public void unregister() throws IllegalStateException { checkValid(); scoreboard.removeTeam(this); @@ -75,16 +80,19 @@ private void update() { //////////////////////////////////////////////////////////////////////////// // Properties + @Override public String getName() throws IllegalStateException { checkValid(); return name; } + @Override public String getDisplayName() throws IllegalStateException { checkValid(); return displayName; } + @Override public void setDisplayName(String displayName) throws IllegalStateException, IllegalArgumentException { checkNotNull(displayName, "Display name cannot be null"); @@ -93,11 +101,13 @@ public void setDisplayName(String displayName) update(); } + @Override public String getPrefix() throws IllegalStateException { checkValid(); return prefix; } + @Override public void setPrefix(String prefix) throws IllegalStateException, IllegalArgumentException { checkNotNull(prefix, "Prefix cannot be null"); checkValid(); @@ -105,11 +115,13 @@ public void setPrefix(String prefix) throws IllegalStateException, IllegalArgume update(); } + @Override public String getSuffix() throws IllegalStateException { checkValid(); return suffix; } + @Override public void setSuffix(String suffix) throws IllegalStateException, IllegalArgumentException { checkNotNull(suffix, "Suffix cannot be null"); checkValid(); @@ -117,35 +129,39 @@ public void setSuffix(String suffix) throws IllegalStateException, IllegalArgume update(); } + @Override public boolean allowFriendlyFire() throws IllegalStateException { checkValid(); return friendlyFire; } + @Override public void setAllowFriendlyFire(boolean enabled) throws IllegalStateException { checkValid(); friendlyFire = enabled; update(); } + @Override public boolean canSeeFriendlyInvisibles() throws IllegalStateException { checkValid(); return seeInvisible; } + @Override public void setCanSeeFriendlyInvisibles(boolean enabled) throws IllegalStateException { checkValid(); seeInvisible = enabled; update(); } - @Deprecated + @Override public NameTagVisibility getNameTagVisibility() throws IllegalStateException { checkValid(); return NameTagVisibility.valueOf(nameTagVisibility.name()); } - @Deprecated + @Override public void setNameTagVisibility(NameTagVisibility visibility) throws IllegalStateException { checkValid(); nameTagVisibility = OptionStatus.valueOf(visibility.name()); @@ -158,6 +174,13 @@ public NameTagVisibility getDeathMessageVisibility() throws IllegalStateExceptio return NameTagVisibility.valueOf(deathMessageVisibility.name()); } + /** + * Sets to whom death messages are visible. + * + * @param deathMessageVisibility the new death message visibility + * @throws IllegalStateException if this team is not registered with a scoreboard + * @throws IllegalArgumentException if {@code deathMessageVisibility} is null + */ @Deprecated public void setDeathMessageVisibility(NameTagVisibility deathMessageVisibility) throws IllegalStateException, IllegalArgumentException { @@ -243,11 +266,6 @@ public void addPlayer(OfflinePlayer player) players.add(player.getName()); } - @Override - public ChatColor getColor() { - return color; - } - @Override public void setColor(ChatColor color) throws IllegalArgumentException { if (color.isFormat()) { diff --git a/src/main/java/net/glowstone/scoreboard/NbtScoreboardIoReader.java b/src/main/java/net/glowstone/scoreboard/NbtScoreboardIoReader.java index 20e693e84c..90f952d5bb 100644 --- a/src/main/java/net/glowstone/scoreboard/NbtScoreboardIoReader.java +++ b/src/main/java/net/glowstone/scoreboard/NbtScoreboardIoReader.java @@ -7,7 +7,7 @@ import java.io.IOException; import java.util.List; import net.glowstone.util.nbt.CompoundTag; -import net.glowstone.util.nbt.NBTInputStream; +import net.glowstone.util.nbt.NbtInputStream; import net.glowstone.util.nbt.TagType; import org.bukkit.ChatColor; import org.bukkit.scoreboard.DisplaySlot; @@ -16,10 +16,17 @@ public class NbtScoreboardIoReader { + /** + * Loads the scoreboard status from an NBT file. + * + * @param path the file path + * @return the loaded scoreboard + * @throws IOException if the file cannot be read + */ public static GlowScoreboard readMainScoreboard(File path) throws IOException { CompoundTag root; - try (NBTInputStream nbt = new NBTInputStream(getDataInputStream(path), true)) { + try (NbtInputStream nbt = new NbtInputStream(getDataInputStream(path), true)) { root = nbt.readCompound().getCompound("data"); } @@ -88,10 +95,6 @@ private static void registerTeams(CompoundTag root, GlowScoreboard scoreboard) { } private static void registerTeam(CompoundTag data, GlowScoreboard scoreboard) { - boolean allowFriendlyFire = data.getByte("AllowFriendlyFire") == 1; - boolean seeFriendlyInvisibles = data.getByte("SeeFriendlyInvisibles") == 1; - Team.OptionStatus nameTagVisibility = Team.OptionStatus - .valueOf(data.getString("NameTagVisibility").toUpperCase()); Team.OptionStatus deathMessageVisibility = Team.OptionStatus.ALWAYS; switch (data.getString("DeathMessageVisibility")) { case "never": @@ -103,6 +106,9 @@ private static void registerTeam(CompoundTag data, GlowScoreboard scoreboard) { case "hideForOwnTeam": deathMessageVisibility = Team.OptionStatus.FOR_OWN_TEAM; break; + default: + // TODO: should this raise a warning? + // leave deathMessageVisibility at default } Team.OptionStatus collisionRule = Team.OptionStatus.ALWAYS; switch (data.getString("CollisionRule")) { @@ -115,30 +121,31 @@ private static void registerTeam(CompoundTag data, GlowScoreboard scoreboard) { case "pushOwnTeam": collisionRule = Team.OptionStatus.FOR_OWN_TEAM; break; + default: + // TODO: Should this raise a warning? + // leave collisionRule at default } String displayName = data.getString("DisplayName"); - String name = data.getString("Name"); - String prefix = data.getString("Prefix"); - String suffix = data.getString("Suffix"); ChatColor teamColor = null; if (data.containsKey("TeamColor")) { teamColor = ChatColor.valueOf(data.getString("TeamColor").toUpperCase()); } - List players = data.getList("Players", TagType.STRING); - - GlowTeam team = (GlowTeam) scoreboard.registerNewTeam(name); + GlowTeam team = (GlowTeam) scoreboard.registerNewTeam(data.getString("Name")); team.setDisplayName(displayName); - team.setPrefix(prefix); - team.setSuffix(suffix); - team.setAllowFriendlyFire(allowFriendlyFire); - team.setCanSeeFriendlyInvisibles(seeFriendlyInvisibles); + team.setPrefix(data.getString("Prefix")); + team.setSuffix(data.getString("Suffix")); + team.setAllowFriendlyFire(data.getByte("AllowFriendlyFire") == 1); + team.setCanSeeFriendlyInvisibles(data.getByte("SeeFriendlyInvisibles") == 1); + Team.OptionStatus nameTagVisibility = Team.OptionStatus + .valueOf(data.getString("NameTagVisibility").toUpperCase()); team.setOption(Team.Option.NAME_TAG_VISIBILITY, nameTagVisibility); team.setOption(Team.Option.DEATH_MESSAGE_VISIBILITY, deathMessageVisibility); team.setOption(Team.Option.COLLISION_RULE, collisionRule); if (teamColor != null) { team.setColor(teamColor); } + List players = data.getList("Players", TagType.STRING); players.forEach(team::addEntry); } diff --git a/src/main/java/net/glowstone/scoreboard/NbtScoreboardIoWriter.java b/src/main/java/net/glowstone/scoreboard/NbtScoreboardIoWriter.java index 6118f3446f..483d1d89dc 100644 --- a/src/main/java/net/glowstone/scoreboard/NbtScoreboardIoWriter.java +++ b/src/main/java/net/glowstone/scoreboard/NbtScoreboardIoWriter.java @@ -7,7 +7,7 @@ import java.util.ArrayList; import java.util.List; import net.glowstone.util.nbt.CompoundTag; -import net.glowstone.util.nbt.NBTOutputStream; +import net.glowstone.util.nbt.NbtOutputStream; import net.glowstone.util.nbt.TagType; import org.bukkit.scoreboard.DisplaySlot; import org.bukkit.scoreboard.Objective; @@ -16,12 +16,19 @@ public class NbtScoreboardIoWriter { + /** + * Saves a scoreboard to a compressed NBT file. + * + * @param path the file path to write to + * @param scoreboard the scoreboard to save + * @throws IOException if the file cannot be written + */ public static void writeMainScoreboard(File path, GlowScoreboard scoreboard) throws IOException { CompoundTag root = new CompoundTag(); CompoundTag data = new CompoundTag(); root.putCompound("data", data); - try (NBTOutputStream nbt = new NBTOutputStream(getDataOutputStream(path), true)) { + try (NbtOutputStream nbt = new NbtOutputStream(getDataOutputStream(path), true)) { writeObjectives(data, scoreboard); writeScores(data, scoreboard); writeTeams(data, scoreboard); diff --git a/src/main/java/net/glowstone/util/ClassPathAgent.java b/src/main/java/net/glowstone/util/ClassPathAgent.java index f10627daac..8944d01969 100644 --- a/src/main/java/net/glowstone/util/ClassPathAgent.java +++ b/src/main/java/net/glowstone/util/ClassPathAgent.java @@ -11,7 +11,12 @@ public static void agentmain(String agentArgs, Instrumentation instrumentation) inst = instrumentation; } - static void addJarFile(JarFile file) { + /** + * Adds a JAR file to the system class loader. + * + * @param file The JAR file to add to the class loader. + */ + public static void addJarFile(JarFile file) { if (inst != null) { inst.appendToSystemClassLoaderSearch(file); } diff --git a/src/main/java/net/glowstone/util/DynamicallyTypedMap.java b/src/main/java/net/glowstone/util/DynamicallyTypedMap.java new file mode 100644 index 0000000000..f3282cfee9 --- /dev/null +++ b/src/main/java/net/glowstone/util/DynamicallyTypedMap.java @@ -0,0 +1,33 @@ +package net.glowstone.util; + +/** + * A map whose values are of variable types known to those invoking the getters. + * + * @param the key type + */ +// TODO: Extend Map? +public interface DynamicallyTypedMap { + /** + * Retrieves an entry as a {@link String}. + * + * @param key the key to look up + * @return the value as a String + */ + String getString(K key); + + /** + * Retrieves an entry as an {@code int}. + * + * @param key the key to look up + * @return the value as an int + */ + int getInt(K key); + + /** + * Retrieves an entry as a {@code boolean}. + * + * @param key the key to look up + * @return the value as a boolean + */ + boolean getBoolean(K key); +} diff --git a/src/main/java/net/glowstone/util/DynamicallyTypedMapWithDoubles.java b/src/main/java/net/glowstone/util/DynamicallyTypedMapWithDoubles.java new file mode 100644 index 0000000000..3389829910 --- /dev/null +++ b/src/main/java/net/glowstone/util/DynamicallyTypedMapWithDoubles.java @@ -0,0 +1,11 @@ +package net.glowstone.util; + +public interface DynamicallyTypedMapWithDoubles extends DynamicallyTypedMapWithFloats { + /** + * Retrieves an entry as a {@code double}. + * + * @param key the key to look up + * @return the value as a {@code double} + */ + double getDouble(K key); +} diff --git a/src/main/java/net/glowstone/util/DynamicallyTypedMapWithFloats.java b/src/main/java/net/glowstone/util/DynamicallyTypedMapWithFloats.java new file mode 100644 index 0000000000..d341aff030 --- /dev/null +++ b/src/main/java/net/glowstone/util/DynamicallyTypedMapWithFloats.java @@ -0,0 +1,12 @@ +package net.glowstone.util; + +public interface DynamicallyTypedMapWithFloats extends DynamicallyTypedMap { + /** + * Retrieves an entry as a {@code float}. + * + * @param key the key to look up + * @return the value as a {@code float} + */ + float getFloat(K key); + +} diff --git a/src/main/java/net/glowstone/util/GameRuleManager.java b/src/main/java/net/glowstone/util/GameRuleManager.java index 78873ca54a..adbec508e4 100644 --- a/src/main/java/net/glowstone/util/GameRuleManager.java +++ b/src/main/java/net/glowstone/util/GameRuleManager.java @@ -6,7 +6,7 @@ /** * Container for the game rule map for worlds. */ -public final class GameRuleManager { +public final class GameRuleManager implements DynamicallyTypedMap { private final Map gameRules = new HashMap<>(); @@ -105,6 +105,11 @@ public boolean getBoolean(String rule) { return false; } + @Override + public int getInt(String key) { + return getInt(key, 0); + } + /** * Gets the game rule value as an integer. If the value cannot be parsed or does not exist then * the default will be returned. @@ -113,7 +118,7 @@ public boolean getBoolean(String rule) { * @param def the default value * @return the integer value of the rule, or the default */ - public int getInteger(String rule, int def) { + public int getInt(String rule, int def) { if (isGameRule(rule)) { String value = getString(rule); try { diff --git a/src/main/java/net/glowstone/util/GlowServerIcon.java b/src/main/java/net/glowstone/util/GlowServerIcon.java index b51c7380ed..9fa10d28a5 100644 --- a/src/main/java/net/glowstone/util/GlowServerIcon.java +++ b/src/main/java/net/glowstone/util/GlowServerIcon.java @@ -11,6 +11,7 @@ import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; +import lombok.Getter; import org.bukkit.util.CachedServerIcon; /** @@ -21,6 +22,7 @@ public final class GlowServerIcon implements CachedServerIcon { /** * The image data to be sent to the client, or null. */ + @Getter private final String data; /** @@ -59,12 +61,4 @@ public GlowServerIcon(BufferedImage image) throws Exception { data = "data:image/png;base64," + encoded.toString(Charsets.UTF_8); encoded.release(); } - - /** - * The image data to be sent to the client, or null. - */ - public String getData() { - return data; - } - } diff --git a/src/main/java/net/glowstone/util/GlowUnsafeValues.java b/src/main/java/net/glowstone/util/GlowUnsafeValues.java index 0417168215..d42f9751ab 100644 --- a/src/main/java/net/glowstone/util/GlowUnsafeValues.java +++ b/src/main/java/net/glowstone/util/GlowUnsafeValues.java @@ -16,7 +16,8 @@ * *

    In CraftBukkit, this uses Mojang identifiers, but here we just stick to Bukkit's. * - *

    The implementation may be a bit sketchy but this isn't a problem since the behavior of this class isn't strictly specified. + *

    The implementation may be a bit sketchy but this isn't a problem since the behavior of this + * class isn't strictly specified. */ @Deprecated public final class GlowUnsafeValues implements UnsafeValues { @@ -63,7 +64,8 @@ public Achievement getAchievementFromInternalName(String name) { } @Override - public List tabCompleteInternalStatisticOrAchievementName(String token, List completions) { + public List tabCompleteInternalStatisticOrAchievementName( + String token, List completions) { Statistic[] stats = Statistic.values(); Achievement[] achievements = Achievement.values(); List names = new ArrayList<>(stats.length + achievements.length); diff --git a/src/main/java/net/glowstone/util/ImmutableItemStack.java b/src/main/java/net/glowstone/util/ImmutableItemStack.java index 0c58389e3b..2525375663 100644 --- a/src/main/java/net/glowstone/util/ImmutableItemStack.java +++ b/src/main/java/net/glowstone/util/ImmutableItemStack.java @@ -1,5 +1,6 @@ package net.glowstone.util; +import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -8,44 +9,52 @@ public class ImmutableItemStack extends ItemStack { - private ItemMeta originalMeta = null; + @Getter // TODO: Defensive copy + private final ItemMeta itemMeta; public ImmutableItemStack(int type) { super(type); - originalMeta = Bukkit.getItemFactory().getItemMeta(getType()).clone(); + itemMeta = Bukkit.getItemFactory().getItemMeta(getType()).clone(); } public ImmutableItemStack(Material type) { super(type); + itemMeta = null; } public ImmutableItemStack(int type, int amount) { super(type, amount); + itemMeta = null; } public ImmutableItemStack(Material type, int amount) { super(type, amount); + itemMeta = null; } public ImmutableItemStack(int type, int amount, short damage) { super(type, amount, damage); + itemMeta = null; } public ImmutableItemStack(Material type, int amount, short damage) { super(type, amount, damage); + itemMeta = null; } public ImmutableItemStack(int type, int amount, short damage, Byte data) { super(type, amount, damage, data); + itemMeta = null; } public ImmutableItemStack(Material type, int amount, short damage, Byte data) { super(type, amount, damage, data); + itemMeta = null; } public ImmutableItemStack(ItemStack stack) throws IllegalArgumentException { super(stack); - originalMeta = stack.getItemMeta().clone(); + itemMeta = stack.getItemMeta().clone(); } @Deprecated @@ -78,9 +87,4 @@ public void setData(MaterialData data) { @Override public void setDurability(short durability) { } - - @Override - public ItemMeta getItemMeta() { - return originalMeta; - } } diff --git a/src/main/java/net/glowstone/util/LibraryManager.java b/src/main/java/net/glowstone/util/LibraryManager.java deleted file mode 100644 index 2a1ffa3364..0000000000 --- a/src/main/java/net/glowstone/util/LibraryManager.java +++ /dev/null @@ -1,122 +0,0 @@ -package net.glowstone.util; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.jar.JarFile; -import java.util.logging.Level; -import javax.net.ssl.HttpsURLConnection; -import net.glowstone.GlowServer; - -/** - * Simple library manager which downloads external dependencies. - */ -public final class LibraryManager { - - /** - * The Maven repository to download from. - */ - final String repository; - - /** - * The directory to store downloads in. - */ - final File directory; - - private final ExecutorService downloaderService = Executors.newCachedThreadPool(); - - public LibraryManager() { - // todo: allow configuration of repository, libraries, and directory - repository = "https://repo.glowstone.net/service/local/repositories/central/content/"; - directory = new File("lib"); - } - - public void run() { - if (!directory.isDirectory() && !directory.mkdirs()) { - GlowServer.logger.log(Level.SEVERE, "Could not create libraries directory: " + directory); - } - - downloaderService.execute(new LibraryDownloader("org.xerial", "sqlite-jdbc", "3.21.0", "")); - downloaderService.execute(new LibraryDownloader("mysql", "mysql-connector-java", "5.1.44", "")); - downloaderService.execute(new LibraryDownloader("org.apache.logging.log4j", "log4j-api", "2.8.1", "")); - downloaderService.execute(new LibraryDownloader("org.apache.logging.log4j", "log4j-core", "2.8.1", "")); - downloaderService.shutdown(); - try { - if (!downloaderService.awaitTermination(1, TimeUnit.MINUTES)) { - downloaderService.shutdownNow(); - } - } catch (InterruptedException e) { - GlowServer.logger.log(Level.SEVERE, "Library Manager thread interrupted: ", e); - } - } - - private class LibraryDownloader implements Runnable { - - private final String group; - private final String library; - private final String version; - private String checksum; - - LibraryDownloader(String group, String library, String version, String checksum) { - this.group = group; - this.library = library; - this.version = version; - this.checksum = checksum; - } - - @Override - public void run() { - // check if we already have it - File file = new File(directory, getLibrary()); - if (!checksum(file, checksum)) { - // download it - GlowServer.logger.info("Downloading " + library + ' ' + version + "..."); - try { - URL downloadUrl = new URL(repository + group.replace('.', '/') + '/' + library + '/' + version + '/' + library + '-' + version + ".jar"); - HttpsURLConnection connection = (HttpsURLConnection) downloadUrl.openConnection(); - connection.setRequestProperty("User-Agent", "Mozilla/5.0"); - - try (ReadableByteChannel input = Channels.newChannel(connection.getInputStream()); FileOutputStream output = new FileOutputStream(file)) { - output.getChannel().transferFrom(input, 0, Long.MAX_VALUE); - GlowServer.logger.info("Downloaded " + library + ' ' + version + '.'); - } - } catch (IOException e) { - GlowServer.logger.log(Level.WARNING, "Failed to download: " + library + ' ' + version, e); - file.delete(); - return; - } - } - - // hack it onto the classpath - try { - String[] javaVersion = System.getProperty("java.version").split("-")[0].split("\\."); - if (Integer.parseInt(javaVersion[0]) >= 9) { - ClassPathAgent.addJarFile(new JarFile(file)); - } else { - Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); - method.setAccessible(true); - method.invoke(ClassLoader.getSystemClassLoader(), file.toURI().toURL()); - } - } catch (ReflectiveOperationException | IOException e) { - GlowServer.logger.log(Level.WARNING, "Failed to add to classpath: " + library + " " + version, e); - } - } - - String getLibrary() { - return library + '-' + version + ".jar"; - } - - boolean checksum(File file, String checksum) { - // TODO: actually check checksum - return file.exists(); - } - } -} diff --git a/src/main/java/net/glowstone/util/NibbleArray.java b/src/main/java/net/glowstone/util/NibbleArray.java index 95f1ae3252..15bd60a19d 100644 --- a/src/main/java/net/glowstone/util/NibbleArray.java +++ b/src/main/java/net/glowstone/util/NibbleArray.java @@ -3,15 +3,24 @@ import static com.google.common.base.Preconditions.checkArgument; import java.util.Arrays; +import lombok.Getter; /** * An array of nibbles (4-bit values) stored efficiently as a byte array of half the size. * - *

    The even indices are stored in the least significant nibble and the odd indices in the most significant bits. For example, [1 5 8 15] is stored as [0x51 0xf8]. + *

    The even indices are stored in the least significant nibble and the odd indices in the most + * significant bits. For example, [1 5 8 15] is stored as [0x51 0xf8]. */ public final class NibbleArray { - private final byte[] data; + /** + * Get the raw bytes of this nibble array. Modifying the returned array will modify the internal + * representation of this nibble array. + * + * @return The raw bytes. + */ + @Getter + private final byte[] rawData; /** * Construct a new NibbleArray with the given size in nibbles. @@ -24,7 +33,8 @@ public NibbleArray(int size) { } /** - * Construct a new NibbleArray with the given size in nibble, filled with the specified nibble value. + * Construct a new NibbleArray with the given size in nibble, filled with the specified nibble + * value. * * @param size The number of nibbles in the array. * @param value The value to fill the array with. @@ -32,7 +42,7 @@ public NibbleArray(int size) { */ public NibbleArray(int size, byte value) { checkArgument(size > 0 && size % 2 == 0, "size must be positive even number, not " + size); - data = new byte[size / 2]; + rawData = new byte[size / 2]; if (value != 0) { fill(value); } @@ -41,10 +51,10 @@ public NibbleArray(int size, byte value) { /** * Construct a new NibbleArray using the given underlying bytes. No copy is created. * - * @param data The raw data to use. + * @param rawData The raw data to use. */ - public NibbleArray(byte... data) { - this.data = data; + public NibbleArray(byte... rawData) { + this.rawData = rawData; } /** @@ -53,7 +63,7 @@ public NibbleArray(byte... data) { * @return The size in nibbles. */ public int size() { - return 2 * data.length; + return 2 * rawData.length; } /** @@ -62,7 +72,7 @@ public int size() { * @return The size in bytes. */ public int byteSize() { - return data.length; + return rawData.length; } /** @@ -72,7 +82,7 @@ public int byteSize() { * @return The value of the nibble at that index. */ public byte get(int index) { - byte val = data[index / 2]; + byte val = rawData[index / 2]; if (index % 2 == 0) { return (byte) (val & 0x0f); } else { @@ -89,11 +99,11 @@ public byte get(int index) { public void set(int index, byte value) { value &= 0xf; int half = index / 2; - byte previous = data[half]; + byte previous = rawData[half]; if (index % 2 == 0) { - data[half] = (byte) (previous & 0xf0 | value); + rawData[half] = (byte) (previous & 0xf0 | value); } else { - data[half] = (byte) (previous & 0x0f | value << 4); + rawData[half] = (byte) (previous & 0x0f | value << 4); } } @@ -104,16 +114,7 @@ public void set(int index, byte value) { */ public void fill(byte value) { value &= 0xf; - Arrays.fill(data, (byte) (value << 4 | value)); - } - - /** - * Get the raw bytes of this nibble array. Modifying the returned array will modify the internal representation of this nibble array. - * - * @return The raw bytes. - */ - public byte[] getRawData() { - return data; + Arrays.fill(rawData, (byte) (value << 4 | value)); } /** @@ -123,8 +124,10 @@ public byte[] getRawData() { * @throws IllegalArgumentException If source is not the correct length. */ public void setRawData(byte... source) { - checkArgument(source.length == data.length, "expected byte array of length " + data.length + ", not " + source.length); - System.arraycopy(source, 0, data, 0, source.length); + checkArgument( + source.length == rawData.length, + "expected byte array of length " + rawData.length + ", not " + source.length); + System.arraycopy(source, 0, rawData, 0, source.length); } /** @@ -133,6 +136,6 @@ public void setRawData(byte... source) { * @return The snapshot NibbleArray. */ public NibbleArray snapshot() { - return new NibbleArray(data.clone()); + return new NibbleArray(rawData.clone()); } } diff --git a/src/main/java/net/glowstone/util/OpenCompute.java b/src/main/java/net/glowstone/util/OpenCompute.java index a0e443728e..e2684f32cd 100644 --- a/src/main/java/net/glowstone/util/OpenCompute.java +++ b/src/main/java/net/glowstone/util/OpenCompute.java @@ -12,18 +12,30 @@ import java.io.InputStream; import java.util.HashMap; import java.util.logging.Level; +import lombok.Getter; import net.glowstone.GlowServer; public class OpenCompute { + private static final ClassLoader CLASS_LOADER = OpenCompute.class.getClassLoader(); private static File openCLDir; + @Getter private static CLPlatform platform; + @Getter private static CLContext context; + @Getter private static CLDevice device; + @Getter private static CLCommandQueue queue; private static HashMap programs; private static HashMap> kernels; + /** + * Returns an OpenCL program, loading it synchronously if it's not in cache. + * + * @param name the program filename + * @return the OpenCL program, or null if there isn't a valid program with that name + */ public static CLProgram getProgram(String name) { if (programs.containsKey(name)) { return programs.get(name); @@ -36,15 +48,18 @@ public static CLProgram getProgram(String name) { programs.put(name, program); return program; } catch (IOException ex) { - GlowServer.logger.log(Level.WARNING, "Could not load custom OpenCL program. Trying builtins.", ex); + GlowServer.logger.log(Level.WARNING, + "Could not load custom OpenCL program.", ex); } } else { - try (InputStream input = OpenCompute.class.getClassLoader().getResourceAsStream("builtin/opencl/" + name)) { + try (InputStream input = CLASS_LOADER + .getResourceAsStream("builtin/opencl/" + name)) { CLProgram program = context.createProgram(input).build(); programs.put(name, program); return program; } catch (IOException ex) { - GlowServer.logger.log(Level.WARNING, "Could not load builtin OpenCL program.", ex); + GlowServer.logger.log(Level.WARNING, + "Could not load builtin OpenCL program.", ex); } } } @@ -56,6 +71,14 @@ public static CLKernel getKernel(CLProgram program, String name) { return getKernel(program, name, false); } + /** + * Returns a {@link CLKernel} that is part of the given {@link CLProgram}. + * + * @param program the {@link CLProgram} that contains the kernel + * @param name the name of the kernel + * @param threaded if true, always create a new {@link CLKernel} instance + * @return the {@link CLKernel} + */ public static CLKernel getKernel(CLProgram program, String name, boolean threaded) { if (kernels.containsKey(program)) { HashMap kernel = kernels.get(program); @@ -74,6 +97,12 @@ public static CLKernel getKernel(CLProgram program, String name, boolean threade } } + /** + * Initializes the {@link CLContext}, {@link CLDevice} and {@link CLCommandQueue} for the given + * {@link CLPlatform}. + * + * @param platform the {@link CLPlatform} to use + */ public static void initContext(CLPlatform platform) { openCLDir = new File("opencl"); @@ -92,32 +121,23 @@ public static void initContext(CLPlatform platform) { GlowServer.logger.info("OpenCL: Using " + platform + " on device " + device + "."); } - public static CLPlatform getPlatform() { - return platform; - } - - public static CLContext getContext() { - return context; - } - - public static CLDevice getDevice() { - return device; - } - - public static CLCommandQueue getQueue() { - return queue; - } - + /** + * Calculates the number of work groups. + * + * @param size the total number of local work units + * @return the number of work groups + */ public static int getGlobalSize(int size) { - int globalSize = size; - int localWorkSize = getLocalSize(); - int r = globalSize % localWorkSize; - if (r != 0) { - globalSize += localWorkSize - r; - } - return globalSize; + return getGlobalSize(size, getLocalSize()); } + /** + * Calculates the number of work groups. + * + * @param size the total number of local work units + * @param localWorkSize the number of local work units per work group + * @return the number of work groups + */ public static int getGlobalSize(int size, int localWorkSize) { int globalSize = size; int r = globalSize % localWorkSize; @@ -127,14 +147,29 @@ public static int getGlobalSize(int size, int localWorkSize) { return globalSize; } + /** + * Calculates the number of local work units per work group. + * + * @return the size of the work groups + */ public static int getLocalSize() { return Math.min(device.getMaxWorkGroupSize(), 256); } + /** + * Calculates the number of local work units per work group, applying a specified maximum. + * + * @param max the maximum size allowed + * @return the size of the work groups + */ public static int getLocalSize(int max) { return Math.min(device.getMaxWorkGroupSize(), max); } + /** + * Static de-initializer. Clears all references to {@link CLProgram}, {@link CLKernel} and + * {@link CLContext} instances. + */ public static void release() { programs.clear(); programs = null; diff --git a/src/main/java/net/glowstone/util/Position.java b/src/main/java/net/glowstone/util/Position.java index f10a873367..e2618040ef 100644 --- a/src/main/java/net/glowstone/util/Position.java +++ b/src/main/java/net/glowstone/util/Position.java @@ -31,9 +31,13 @@ public final class Position { /** - * Common Rotation values used blocks such as Signs, Skulls, and Banners. The order relates to the data/tag that is applied to the block on placing. + * Common Rotation values used blocks such as Signs, Skulls, and Banners. The order relates to + * the data/tag that is applied to the block on placing. */ - public static final List ROTATIONS = ImmutableList.of(NORTH, NORTH_NORTH_EAST, NORTH_EAST, EAST_NORTH_EAST, EAST, EAST_SOUTH_EAST, SOUTH_EAST, SOUTH_SOUTH_EAST, SOUTH, SOUTH_SOUTH_WEST, SOUTH_WEST, WEST_SOUTH_WEST, WEST, WEST_NORTH_WEST, NORTH_WEST, NORTH_NORTH_WEST); + public static final List ROTATIONS = ImmutableList + .of(NORTH, NORTH_NORTH_EAST, NORTH_EAST, EAST_NORTH_EAST, EAST, EAST_SOUTH_EAST, + SOUTH_EAST, SOUTH_SOUTH_EAST, SOUTH, SOUTH_SOUTH_WEST, SOUTH_WEST, + WEST_SOUTH_WEST, WEST, WEST_NORTH_WEST, NORTH_WEST, NORTH_NORTH_WEST); private Position() { } @@ -76,7 +80,8 @@ public static int getIntHeadYaw(float headYaw) { * @return A boolean. */ public static boolean hasMoved(Location first, Location second) { - return first.getX() != second.getX() || first.getY() != second.getY() || first.getZ() != second.getZ(); + return first.getX() != second.getX() || first.getY() != second.getY() + || first.getZ() != second.getZ(); } /** @@ -155,7 +160,9 @@ public static byte getDirection(BlockFace rotation) { * @return the serialized position value */ public static long getPosition(BlockVector vector) { - return (((long) vector.getBlockX() & 0x3FFFFFF) << 38) | (((long) vector.getBlockY() & 0xFFF) << 26) | ((long) vector.getBlockZ() & 0x3FFFFFF); + return (((long) vector.getBlockX() & 0x3FFFFFF) << 38) | ( + ((long) vector.getBlockY() & 0xFFF) << 26) | ((long) vector.getBlockZ() + & 0x3FFFFFF); } /** diff --git a/src/main/java/net/glowstone/util/RayUtil.java b/src/main/java/net/glowstone/util/RayUtil.java index 622de964c4..cfa6be82ea 100644 --- a/src/main/java/net/glowstone/util/RayUtil.java +++ b/src/main/java/net/glowstone/util/RayUtil.java @@ -5,6 +5,12 @@ public class RayUtil { + /** + * Maps {0, 0, 0} to {0, 1, 0} and all other vectors to their normalized form. + * + * @param ray the ray to transform + * @return a ray of length 1 + */ public static Vector getVelocityRay(Vector ray) { Vector velocityRay = ray.clone(); if (velocityRay.lengthSquared() == 0) { diff --git a/src/main/java/net/glowstone/util/RectangularRegion.java b/src/main/java/net/glowstone/util/RectangularRegion.java new file mode 100644 index 0000000000..6081759392 --- /dev/null +++ b/src/main/java/net/glowstone/util/RectangularRegion.java @@ -0,0 +1,237 @@ +package net.glowstone.util; + +import com.google.common.base.Preconditions; +import com.google.common.collect.AbstractIterator; +import java.util.Iterator; +import lombok.Getter; +import org.bukkit.Location; +import org.jetbrains.annotations.NotNull; + +@Getter +public class RectangularRegion { + private final Location lowCorner; + private final Location highCorner; + private final int widthX; + private final int widthY; + private final int widthZ; + + /** + * Creates a new region bounded by the two opposing locations. + * @param from The first bounding corner. + * @param to The second bounding corner. + */ + public RectangularRegion(Location from, Location to) { + Preconditions.checkArgument( + from.getWorld() == to.getWorld(), + "The given locations do not have matching worlds." + ); + this.lowCorner = new Location( + from.getWorld(), + Double.min(from.getX(), to.getX()), + Double.min(from.getY(), to.getY()), + Double.min(from.getZ(), to.getZ()) + ); + this.highCorner = new Location( + from.getWorld(), + Double.max(from.getX(), to.getX()), + Double.max(from.getY(), to.getY()), + Double.max(from.getZ(), to.getZ()) + ); + this.widthX = highCorner.getBlockX() - lowCorner.getBlockX(); + this.widthY = highCorner.getBlockY() - lowCorner.getBlockY(); + this.widthZ = highCorner.getBlockZ() - lowCorner.getBlockZ(); + } + + /** + * Creates a new region at the given corner with the same dimensions as this region. + * @param lowCorner The corner to base the new region off of. + * @return The new region. + */ + public RectangularRegion moveTo(Location lowCorner) { + return new RectangularRegion( + lowCorner, + new Location( + lowCorner.getWorld(), + lowCorner.getBlockX() + widthX, + lowCorner.getBlockY() + widthY, + lowCorner.getBlockZ() + widthZ + ) + ); + } + + /** + * Returns an iterable over all block locations within the region, with the iterable's + * directionality determined by the given arguments. + * @param directionX The direction of iteration along the X axis. + * @param directionY The direction of iteration along the Y axis. + * @param directionZ The direction of iteration along the Z axis. + * @return The new iterable. + */ + public Iterable blockLocations(IterationDirection directionX, + IterationDirection directionY, + IterationDirection directionZ) { + return new LocationIterable(lowCorner, directionX.iterable(widthX), + directionY.iterable(widthY), directionZ.iterable(widthZ)); + } + + private static class LocationIterable implements Iterable { + private final Location lowCorner; + private final Iterable iterableX; + private final Iterable iterableY; + private final Iterable iterableZ; + + private LocationIterable(Location lowCorner, Iterable iterableX, + Iterable iterableY, Iterable iterableZ) { + this.lowCorner = lowCorner; + this.iterableX = iterableX; + this.iterableY = iterableY; + this.iterableZ = iterableZ; + } + + @NotNull + @Override + public Iterator iterator() { + return new LocationIterator(lowCorner, iterableX, iterableY, iterableZ); + } + } + + private static class LocationIterator extends AbstractIterator { + private final Location lowCorner; + private final Iterator iteratorX; + private final Iterable iterableY; + private final Iterable iterableZ; + + private Iterator iteratorY; + private Iterator iteratorZ; + + private int x; + private int y; + + private LocationIterator(Location lowCorner, Iterable iterableX, + Iterable iterableY, Iterable iterableZ) { + this.lowCorner = lowCorner; + + this.iterableY = iterableY; + this.iterableZ = iterableZ; + + this.iteratorX = iterableX.iterator(); + this.iteratorY = iterableY.iterator(); + this.iteratorZ = iterableZ.iterator(); + + this.x = this.iteratorX.next(); + this.y = this.iteratorY.next(); + } + + @Override + protected Location computeNext() { + if (iteratorZ.hasNext()) { + return getLocation(); + } + if (iteratorY.hasNext()) { + iteratorZ = iterableZ.iterator(); + y = iteratorY.next(); + return getLocation(); + } + if (iteratorX.hasNext()) { + iteratorY = iterableY.iterator(); + iteratorZ = iterableZ.iterator(); + x = iteratorX.next(); + y = iteratorY.next(); + return getLocation(); + } + return endOfData(); + } + + private Location getLocation() { + return new Location(lowCorner.getWorld(), lowCorner.getBlockX() + x, + lowCorner.getBlockY() + y, lowCorner.getBlockZ() + iteratorZ.next()); + } + } + + public enum IterationDirection { + FORWARDS { + @Override + public Iterable iterable(int max) { + return new ForwardsAxisIterable(max); + } + }, + BACKWARDS { + @Override + public Iterable iterable(int max) { + return new BackwardsAxisIterable(max); + } + }; + + public abstract Iterable iterable(int max); + } + + private static class ForwardsAxisIterable implements Iterable { + private final int max; + + private ForwardsAxisIterable(int max) { + this.max = max; + } + + @NotNull + @Override + public Iterator iterator() { + return new ForwardsAxisIterator(max); + } + } + + private static class ForwardsAxisIterator extends AbstractIterator { + private final int max; + private int current; + + public ForwardsAxisIterator(int max) { + this.max = max; + this.current = 0; + } + + @Override + protected Integer computeNext() { + if (current <= max) { + // Could use a post-increment operator here, but this is a bit more clear in + // getting the meaning across. + int retval = current; + current++; + return retval; + } + return endOfData(); + } + } + + private static class BackwardsAxisIterable implements Iterable { + private final int max; + + private BackwardsAxisIterable(int max) { + this.max = max; + } + + @NotNull + @Override + public Iterator iterator() { + return new BackwardsAxisIterator(max); + } + } + + private static class BackwardsAxisIterator extends AbstractIterator { + private int current; + + public BackwardsAxisIterator(int length) { + this.current = length; + } + + @Override + protected Integer computeNext() { + if (current >= 0) { + // Could use a post-decrement operator here, but this is a bit more clear in + // getting the meaning across. + int retval = current; + current--; + return retval; + } + return endOfData(); + } + } +} diff --git a/src/main/java/net/glowstone/util/ReflectionProcessor.java b/src/main/java/net/glowstone/util/ReflectionProcessor.java index a26b8bb98b..2888c6677a 100644 --- a/src/main/java/net/glowstone/util/ReflectionProcessor.java +++ b/src/main/java/net/glowstone/util/ReflectionProcessor.java @@ -13,18 +13,17 @@ public class ReflectionProcessor { /** * Creates a new reflection processor instance. * - *

    The processor is able to parse referenced contexts with the following syntax: - *

      - *
    1. $ to reference the first context (equivalent to $1)
    2. - *
    3. $x to reference a specific context, where 'x' is the index of the context (starting from 1)
    4. - *
    + *

    The processor is able to parse referenced contexts with the following syntax:

    1. $ + * to reference the first context (equivalent to $1)
    2. $x to reference a specific + * context, where 'x' is the index of the context (starting from 1)
    * *

    To reference a static method/field call, specifying the full package is required. * * @param line the reflection line. * @param context the context(s) of the reflection line - * - * @see OneLineReflection README + * @see + * OneLineReflection + * README */ public ReflectionProcessor(String line, Object... context) { this.line = line; @@ -45,11 +44,13 @@ public Object process() { if (section.equals("$") || section.equals("this")) { // Context #1 cxt = context[0]; - } else if (section.length() > 0 && section.charAt(0) == '$' && section.substring(1, section.length()).matches("[0-9]+")) { + } else if (section.length() > 0 && section.charAt(0) == '$' && section + .substring(1, section.length()).matches("[0-9]+")) { // Context #X int index = Integer.valueOf(section.replace("$", "")) - 1; cxt = context[index]; - } else if (section.length() > 0 && section.charAt(0) == '\"' && section.length() > 0 && section.charAt(section.length() - 1) == '\"') { + } else if (section.length() > 0 && section.charAt(0) == '\"' && section.length() > 0 + && section.charAt(section.length() - 1) == '\"') { // String literal section = section.substring(1, section.length() - 1); if (i == sections.length - 1) { @@ -208,7 +209,8 @@ private Object invokeField(Object context, String name) { boolean isEnum = ((Class) context).isEnum(); if (isEnum) { try { - return getMethod("valueOf", (Class) context, String.class).invoke(null, name); + return getMethod("valueOf", (Class) context, String.class) + .invoke(null, name); } catch (Exception expected) { } } @@ -237,7 +239,8 @@ private Class invokeClass(String name) { /** * Gets the parameters inside a method parentheses enclosure. * - * @param section the method and its parameters, which are enclosed in parentheses and separated with commas (,) + * @param section the method and its parameters, which are enclosed in parentheses and + * separated with commas (,) * @return the parameters */ private String[] getMethodParams(String section) { diff --git a/src/main/java/net/glowstone/util/SoundInfo.java b/src/main/java/net/glowstone/util/SoundInfo.java index e17c2b118d..c361731ceb 100644 --- a/src/main/java/net/glowstone/util/SoundInfo.java +++ b/src/main/java/net/glowstone/util/SoundInfo.java @@ -1,5 +1,7 @@ package net.glowstone.util; +import lombok.Data; +import lombok.RequiredArgsConstructor; import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.Player; @@ -7,10 +9,15 @@ /** * A class that encapsulates relevant data for playing sounds (volume and pitch). */ +@Data +@RequiredArgsConstructor public class SoundInfo { + /** The Bukkit sound enum constant. */ private final Sound sound; + /** The volume. */ private final float volume; + /** The pitch multiplier. */ private final float pitch; /** @@ -22,19 +29,6 @@ public SoundInfo(Sound sound) { this(sound, 1F, 1F); } - /** - * Constructs a new GlowSound with the given sound, volume and pitch. - * - * @param sound The Bukkit sound enum constant - * @param volume Volume of sound - * @param pitch Pitch of sound - */ - public SoundInfo(Sound sound, float volume, float pitch) { - this.sound = sound; - this.volume = volume; - this.pitch = pitch; - } - /** * Plays the sound to all players at the given location. * @@ -53,16 +47,4 @@ public void play(Location location) { public void playTo(Player player, Location location) { player.playSound(location, sound, volume, pitch); } - - public Sound getSound() { - return sound; - } - - public float getVolume() { - return volume; - } - - public float getPitch() { - return pitch; - } } diff --git a/src/main/java/net/glowstone/util/SoundUtil.java b/src/main/java/net/glowstone/util/SoundUtil.java index e49e50150c..63df4cbbe5 100644 --- a/src/main/java/net/glowstone/util/SoundUtil.java +++ b/src/main/java/net/glowstone/util/SoundUtil.java @@ -10,19 +10,41 @@ public class SoundUtil { - public static void playSoundAtLocationExcept(Location location, Sound sound, float volume, float pitch, GlowPlayer... exclude) { + /** + * Plays a sound with a random pitch, but excludes one player from hearing it. + * + * @param location the sound location + * @param sound the sound to play + * @param volume the volume multiplier + * @param pitch the pitch modifier + * @param exclude the player not to play the sound for + */ + public static void playSoundAtLocationExcept(Location location, Sound sound, float volume, + float pitch, GlowPlayer... exclude) { if (location == null || sound == null) { return; } GlowWorld world = (GlowWorld) location.getWorld(); double radiusSquared = volume * volume * 256; world.getRawPlayers().stream().filter(player -> - player.getLocation().distanceSquared(location) <= radiusSquared - && !Arrays.asList(exclude).contains(player)) - .forEach(player -> player.playSound(location, sound, volume, pitch)); + player.getLocation().distanceSquared(location) <= radiusSquared + && !Arrays.asList(exclude).contains(player)) + .forEach(player -> player.playSound(location, sound, volume, pitch)); } - public static void playSoundPitchRange(Location location, Sound sound, float volume, float pitchBase, float pitchRange, boolean allowNegative, GlowPlayer... exclude) { + /** + * Plays a sound with a random pitch, but excludes one player from hearing it. + * + * @param location the sound location + * @param sound the sound to play + * @param volume the volume multiplier + * @param pitchBase if {@code allowNegative}, the average pitch modifier; otherwise, the minimum + * @param pitchRange the maximum deviation of the pitch modifier compared to {@code pitchBase} + * @param allowNegative if true, distribution is triangular rather than uniform + * @param exclude the player not to play the sound for + */ + public static void playSoundPitchRange(Location location, Sound sound, float volume, + float pitchBase, float pitchRange, boolean allowNegative, GlowPlayer... exclude) { ThreadLocalRandom rand = ThreadLocalRandom.current(); float pitch = pitchBase; if (allowNegative) { @@ -33,7 +55,8 @@ public static void playSoundPitchRange(Location location, Sound sound, float vol playSoundAtLocationExcept(location, sound, volume, pitch, exclude); } - public static void playSoundPitchRange(Location location, Sound sound, float volume, float pitchBase, float pitchRange, GlowPlayer... exclude) { + public static void playSoundPitchRange(Location location, Sound sound, float volume, + float pitchBase, float pitchRange, GlowPlayer... exclude) { playSoundPitchRange(location, sound, volume, pitchBase, pitchRange, true, exclude); } @@ -43,7 +66,8 @@ public static float randomReal(float range) { } /** - * Convert a string to a SoundCategory. The comparison is done on the name and is not case-sensitive. + * Convert a string to a SoundCategory. The comparison is done on the name and is not + * case-sensitive. * * @param category The string name of the category * @return The matching SoundCategory, null if none. @@ -52,13 +76,11 @@ public static SoundCategory buildSoundCategory(final String category) { if (category == null) { return null; } - for (final SoundCategory soundCategory : SoundCategory.values()) { if (category.equalsIgnoreCase(soundCategory.name())) { return soundCategory; } } - return null; } } diff --git a/src/main/java/net/glowstone/util/StatisticMap.java b/src/main/java/net/glowstone/util/StatisticMap.java index 7f5f368448..52711886c3 100644 --- a/src/main/java/net/glowstone/util/StatisticMap.java +++ b/src/main/java/net/glowstone/util/StatisticMap.java @@ -41,15 +41,19 @@ private String name(Statistic stat) { private String name(Statistic stat, Material mat) { if (mat.isBlock()) { - checkArgument(stat.getType() == Type.BLOCK, "Statistic " + stat + " is not a block statistic"); + checkArgument( + stat.getType() == Type.BLOCK, + "Statistic " + stat + " is not a block statistic"); } else { - checkArgument(stat.getType() == Type.ITEM, "Statistic " + stat + " is not an item statistic"); + checkArgument( + stat.getType() == Type.ITEM, "Statistic " + stat + " is not an item statistic"); } throw new UnsupportedOperationException("Not yet implemented"); } private String name(Statistic stat, EntityType type) { - checkArgument(stat.getType() == Type.ENTITY, "Statistic " + stat + " is not an entity statistic"); + checkArgument( + stat.getType() == Type.ENTITY, "Statistic " + stat + " is not an entity statistic"); throw new UnsupportedOperationException("Not yet implemented"); } @@ -104,6 +108,7 @@ public void add(Statistic stat, EntityType entityType, int modify) { } public Map getValues() { + // TODO: Replace with facade return values; } } diff --git a/src/main/java/net/glowstone/util/TaxicabBlockIterator.java b/src/main/java/net/glowstone/util/TaxicabBlockIterator.java index 27f7473041..c6aa0f8ff9 100644 --- a/src/main/java/net/glowstone/util/TaxicabBlockIterator.java +++ b/src/main/java/net/glowstone/util/TaxicabBlockIterator.java @@ -11,7 +11,8 @@ public class TaxicabBlockIterator implements Iterator { - private static final BlockFace[] VALID_FACES = new BlockFace[]{BlockFace.DOWN, BlockFace.UP, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST, BlockFace.EAST}; + private static final BlockFace[] VALID_FACES = new BlockFace[]{BlockFace.DOWN, BlockFace.UP, + BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST, BlockFace.EAST}; private final Queue pendingAnalysis = new LinkedList<>(); private final Queue nextValidBlocks = new LinkedList<>(); @@ -23,6 +24,11 @@ public class TaxicabBlockIterator implements Iterator { private int maxBlocks = Integer.MAX_VALUE; private Validator validator; + /** + * Creates an instance. + * + * @param origin the origin to start iterating around + */ public TaxicabBlockIterator(Block origin) { pendingAnalysis.add(origin); pendingAnalysis.add(DistanceMarker.INSTANCE); @@ -51,19 +57,24 @@ public boolean hasNext() { return false; } - // Keep going till the valid block queue contains something, we reach the distance limit, or we empty the pending analysis queue. - // Note that the pending analysis queue will always contain at least one element: the end of distance marker. - while (nextValidBlocks.isEmpty() && currentDistance <= maxDistance && pendingAnalysis.size() >= 2) { + // Keep going till the valid block queue contains something, we reach the distance limit, + // or we empty the pending analysis queue. + // Note that the pending analysis queue will always contain at least one element: the end + // of distance marker. + while (nextValidBlocks.isEmpty() && currentDistance <= maxDistance + && pendingAnalysis.size() >= 2) { Object object = pendingAnalysis.remove(); - // If we find the end of distance marker, we'll increase the distance, and then we'll re-add it to the end. + // If we find the end of distance marker, we'll increase the distance, and then we'll + // re-add it to the end. if (object == DistanceMarker.INSTANCE) { pendingAnalysis.add(object); currentDistance++; continue; } - // If it wasn't the EoD marker, it must be a block. We'll look now for valid blocks around it. + // If it wasn't the EoD marker, it must be a block. We'll look now for valid blocks + // around it. Block block = (Block) object; for (BlockFace face : VALID_FACES) { Block near = block.getRelative(face); diff --git a/src/main/java/net/glowstone/util/TextMessage.java b/src/main/java/net/glowstone/util/TextMessage.java index 7d58cd197c..14781145ea 100644 --- a/src/main/java/net/glowstone/util/TextMessage.java +++ b/src/main/java/net/glowstone/util/TextMessage.java @@ -21,7 +21,8 @@ public final class TextMessage { /** * The formatting ChatColors. */ - private static final ChatColor[] FORMATTING = {ChatColor.MAGIC, ChatColor.BOLD, ChatColor.STRIKETHROUGH, ChatColor.UNDERLINE, ChatColor.ITALIC}; + private static final ChatColor[] FORMATTING = {ChatColor.MAGIC, ChatColor.BOLD, + ChatColor.STRIKETHROUGH, ChatColor.UNDERLINE, ChatColor.ITALIC}; /** * The JSON structure of this text message. @@ -29,7 +30,8 @@ public final class TextMessage { private final JSONObject object; /** - * Construct a new chat message from a simple text string. Handles style and colors in the original string, converting them to the new format. + * Construct a new chat message from a simple text string. Handles style and colors in the + * original string, converting them to the new format. * * @param text The text of the message. */ @@ -175,7 +177,8 @@ private static JSONObject convert(String text) { } @SuppressWarnings("unchecked") - private static void append(List items, StringBuilder current, ChatColor color, Set formatting) { + private static void append(List items, StringBuilder current, ChatColor color, + Set formatting) { if (current.length() == 0) { return; } diff --git a/src/main/java/net/glowstone/util/UuidUtils.java b/src/main/java/net/glowstone/util/UuidUtils.java index 5ff27a5d4f..bf34093d60 100644 --- a/src/main/java/net/glowstone/util/UuidUtils.java +++ b/src/main/java/net/glowstone/util/UuidUtils.java @@ -10,9 +10,17 @@ public final class UuidUtils { private UuidUtils() { } + /** + * Parses a UUID from a hexadecimal string without hyphens. + * + * @param str a 32-digit hexadecimal string + * @return {@code str} as a UUID + */ public static UUID fromFlatString(String str) { // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - return new UUID(Long.parseUnsignedLong(str.substring(0, 16), 16), Long.parseUnsignedLong(str.substring(16), 16)); + return new UUID( + Long.parseUnsignedLong(str.substring(0, 16), 16), + Long.parseUnsignedLong(str.substring(16), 16)); } public static String toFlatString(UUID uuid) { diff --git a/src/main/java/net/glowstone/util/VariableValueArray.java b/src/main/java/net/glowstone/util/VariableValueArray.java index ef7dcad063..b5624fb376 100644 --- a/src/main/java/net/glowstone/util/VariableValueArray.java +++ b/src/main/java/net/glowstone/util/VariableValueArray.java @@ -1,21 +1,35 @@ package net.glowstone.util; +import lombok.Getter; + public final class VariableValueArray implements Cloneable { + @Getter private final long[] backing; + @Getter private final int capacity; + @Getter private final int bitsPerValue; private final long valueMask; + /** + * Creates an instance. + * + * @param bitsPerValue the number of bits into which each value must fit + * @param capacity the number of entries + */ public VariableValueArray(int bitsPerValue, int capacity) { if (capacity < 0) { - throw new IllegalArgumentException(String.format("capacity (%s) must not be negative", capacity)); + throw new IllegalArgumentException(String + .format("capacity (%s) must not be negative", capacity)); } if (bitsPerValue < 1) { - throw new IllegalArgumentException(String.format("bitsPerValue (%s) must not be less than 1", bitsPerValue)); + throw new IllegalArgumentException(String + .format("bitsPerValue (%s) must not be less than 1", bitsPerValue)); } if (bitsPerValue > 64) { - throw new IllegalArgumentException(String.format("bitsPerValue (%s) must not be greater than 64", bitsPerValue)); + throw new IllegalArgumentException(String + .format("bitsPerValue (%s) must not be greater than 64", bitsPerValue)); } backing = new long[(int) Math.ceil((bitsPerValue * capacity) / 64.0)]; this.bitsPerValue = bitsPerValue; @@ -38,22 +52,17 @@ public static int calculateNeededBits(int number) { return count; } - public long[] getBacking() { - return backing; - } - - public int getCapacity() { - return capacity; - } - - public int getBitsPerValue() { - return bitsPerValue; - } - public long getLargestPossibleValue() { return valueMask; } + /** + * Returns a value. + * + * @param index the entry to look up + * @return the entry value + * @throws IndexOutOfBoundsException if {@code index} is out of range + */ public int get(int index) { checkIndex(index); @@ -71,14 +80,24 @@ public int get(int index) { return (int) (value & valueMask); } + /** + * Sets a value. + * + * @param index the entry to set + * @param value the value to set it to + * @throws IndexOutOfBoundsException if {@code index} is out of range + * @throws IllegalArgumentException if {@code value} is out of range + */ public void set(int index, int value) { checkIndex(index); if (value < 0) { - throw new IllegalArgumentException(String.format("value (%s) must not be negative", value)); + throw new IllegalArgumentException(String + .format("value (%s) must not be negative", value)); } if (value > valueMask) { - throw new IllegalArgumentException(String.format("value (%s) must not be greater than %s", value, valueMask)); + throw new IllegalArgumentException(String + .format("value (%s) must not be greater than %s", value, valueMask)); } index *= bitsPerValue; @@ -96,25 +115,35 @@ public void set(int index, int value) { private void checkIndex(int index) { if (index < 0) { - throw new IndexOutOfBoundsException(String.format("index (%s) must not be negative", index)); + throw new IndexOutOfBoundsException(String + .format("index (%s) must not be negative", index)); } if (index >= capacity) { - throw new IndexOutOfBoundsException(String.format("index (%s) must not be greater than the capacity (%s)", index, capacity)); + throw new IndexOutOfBoundsException(String + .format("index (%s) must not be greater than the capacity (%s)", index, + capacity)); } } /** - * Creates a new VariableValueArray with the contents of this one, and the given bits per value. + * Creates a new VariableValueArray with the contents of this one, and the given bits per + * value. * - * @param newBitsPerValue The new value. Must be larger than the current value ( {@link #getBitsPerValue()}). + * @param newBitsPerValue The new value. Must be larger than the current value ( {@link + * #getBitsPerValue()}). * @return A new VariableValueArray - * @throws IllegalArgumentException If newBitsPerValue is less than or equal to the current bits per value. Setting it to the same size would be a waste of resources, and decreasing could lead to data loss. + * @throws IllegalArgumentException If newBitsPerValue is less than or equal to the + * current bits per value. Setting it to the same size would be a waste of resources, + * and decreasing could lead to data loss. */ public VariableValueArray increaseBitsPerValueTo(int newBitsPerValue) { if (newBitsPerValue < this.bitsPerValue) { - throw new IllegalArgumentException("Cannot decrease bits per value! (was " + this.bitsPerValue + ", new size " + newBitsPerValue + ")"); + throw new IllegalArgumentException( + "Cannot decrease bits per value! (was " + this.bitsPerValue + ", new size " + + newBitsPerValue + ")"); } else if (newBitsPerValue == this.bitsPerValue) { - throw new IllegalArgumentException("Cannot resize to the same size! (size was " + newBitsPerValue + ")"); + throw new IllegalArgumentException( + "Cannot resize to the same size! (size was " + newBitsPerValue + ")"); } VariableValueArray returned = new VariableValueArray(newBitsPerValue, this.capacity); diff --git a/src/main/java/net/glowstone/util/WeightedRandom.java b/src/main/java/net/glowstone/util/WeightedRandom.java index 9a662701a8..1d34ea535e 100644 --- a/src/main/java/net/glowstone/util/WeightedRandom.java +++ b/src/main/java/net/glowstone/util/WeightedRandom.java @@ -4,6 +4,14 @@ public final class WeightedRandom { + /** + * Selects a random item from a weighted distribution. + * + * @param random the PRNG to use + * @param possibilities the distribution to sample from + * @param the type of each of the {@code possibilities} + * @return a random item + */ public static T getRandom(Random random, Iterable possibilities) { int weights = 0; for (T possibility : possibilities) { @@ -18,10 +26,10 @@ public static T getRandom(Random random, Iterable possibil return t; } } - return null; } + @FunctionalInterface public interface Choice { int getWeight(); diff --git a/src/main/java/net/glowstone/util/bans/GlowBanEntry.java b/src/main/java/net/glowstone/util/bans/GlowBanEntry.java index c380cbfca1..353401b1d5 100644 --- a/src/main/java/net/glowstone/util/bans/GlowBanEntry.java +++ b/src/main/java/net/glowstone/util/bans/GlowBanEntry.java @@ -3,6 +3,8 @@ import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; import net.glowstone.util.bans.JsonListFile.BaseEntry; import org.bukkit.BanEntry; import org.bukkit.BanList.Type; @@ -15,10 +17,15 @@ final class GlowBanEntry implements BaseEntry, BanEntry, Cloneable { private final GlowBanList list; + @Getter private final String target; private Date created; private Date expires; + @Getter + @Setter private String source; + @Getter + @Setter private String reason; GlowBanEntry(GlowBanList list, String target, String reason, Date created, Date expires, @@ -60,11 +67,6 @@ public Map write() { return result; } - @Override - public String getTarget() { - return target; - } - @Override public Date getCreated() { return copy(created); @@ -75,16 +77,6 @@ public void setCreated(Date created) { this.created = copy(created); } - @Override - public String getSource() { - return source; - } - - @Override - public void setSource(String source) { - this.source = source; - } - @Override public Date getExpiration() { return copy(expires); @@ -95,16 +87,6 @@ public void setExpiration(Date expiration) { expires = copy(expiration); } - @Override - public String getReason() { - return reason; - } - - @Override - public void setReason(String reason) { - this.reason = reason; - } - @Override public void save() { list.putEntry(this); diff --git a/src/main/java/net/glowstone/util/bans/UuidListFile.java b/src/main/java/net/glowstone/util/bans/UuidListFile.java index 1f2374aadd..f627ff4189 100644 --- a/src/main/java/net/glowstone/util/bans/UuidListFile.java +++ b/src/main/java/net/glowstone/util/bans/UuidListFile.java @@ -1,12 +1,14 @@ package net.glowstone.util.bans; import java.io.File; -import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; import net.glowstone.entity.meta.profile.PlayerProfile; import net.glowstone.entity.meta.profile.ProfileCache; import org.bukkit.OfflinePlayer; @@ -16,53 +18,88 @@ */ public final class UuidListFile extends JsonListFile { + private Map entriesByUuid = new ConcurrentHashMap<>(); + + @Override + public void load() { + super.load(); + for (BaseEntry entry : entries) { + entriesByUuid.put(((Entry) entry).uuid, (Entry) entry); + } + } + public UuidListFile(File file) { super(file); } + /** + * Returns a {@link PlayerProfile} for each player whose UUID is in the list file. + * + * @return a list of {@link PlayerProfile} instances + */ public List getProfiles() { - List result = new ArrayList<>(entries.size()); - for (BaseEntry baseEntry : entries) { - Entry entry = (Entry) baseEntry; - PlayerProfile profile = ProfileCache.getProfile(entry.uuid).join(); - if (profile.getName() == null) { - profile = new PlayerProfile(entry.fallbackName, entry.uuid); - } - result.add(profile); - } - return result; + return entries + .stream() + .parallel() + .map(entry -> { + try { + return ProfileCache.getProfile(((Entry) entry).uuid).get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + }) + .collect(Collectors.toList()); } - public boolean containsUUID(UUID uuid) { - for (BaseEntry baseEntry : entries) { - if (uuid.equals(((Entry) baseEntry).uuid)) { - return true; - } - } - return false; + /** + * Searches for a UUID. + * + * @param uuid the UUID to search for + * @return true if the UUID is present; false otherwise + */ + public boolean containsUuid(UUID uuid) { + return entriesByUuid.containsKey(uuid); } + /** + * Checks whether the player with a given UUID is in this list. + * + * @param profile the player whose UUID will be looked up + * @return whether the player is on this list + */ public boolean containsProfile(PlayerProfile profile) { - for (BaseEntry baseEntry : entries) { - if (profile.getUniqueId().equals(((Entry) baseEntry).uuid)) { - return true; - } - } - return false; + return containsUuid(profile.getUniqueId()); } + /** + * If the given player is not already on this list, adds that player and saves the change to + * disk. + * + * @param player the player to add + */ public void add(OfflinePlayer player) { - if (!containsUUID(player.getUniqueId())) { - entries.add(new Entry(player.getUniqueId(), player.getName())); + UUID playerUuid = player.getUniqueId(); + if (!containsUuid(playerUuid)) { + Entry newEntry = new Entry(playerUuid, player.getName()); + entries.add(newEntry); + entriesByUuid.put(playerUuid, newEntry); save(); } } + /** + * If the given player is on this list, removes that player and saves the change to disk. + * + * @param profile the player to remove + */ public void remove(PlayerProfile profile) { + UUID playerUuid = profile.getUniqueId(); + entriesByUuid.remove(playerUuid); + // FIXME: Unnecessary linear time Iterator iter = entries.iterator(); boolean modified = false; while (iter.hasNext()) { - if (((Entry) iter.next()).uuid.equals(profile.getUniqueId())) { + if (((Entry) iter.next()).uuid.equals(playerUuid)) { iter.remove(); modified = true; } diff --git a/src/main/java/net/glowstone/util/collection/SuperCollection.java b/src/main/java/net/glowstone/util/collection/SuperCollection.java index 22f82eca9d..28c4bf99fd 100644 --- a/src/main/java/net/glowstone/util/collection/SuperCollection.java +++ b/src/main/java/net/glowstone/util/collection/SuperCollection.java @@ -4,28 +4,61 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; +import lombok.Getter; +import lombok.Setter; /** - * Generic super collection. This is an abstract collection which delegates (ie redirects operations) to other collections (its children). - * This class is employed to reduce the overhead of copying objects from several collections to create a new larger one. + * Generic super collection. This is an abstract collection which delegates (ie redirects + * operations) to other collections (its children). This class is employed to reduce the overhead of + * copying objects from several collections to create a new larger one. * - *

    This class is a generic collection which serves as a base for other super collections. - * It handles non-indexed accesses to collections like additions, removals, contains... + *

    This class is a generic collection which serves as a base for other super collections. It + * handles non-indexed accesses to collections like additions, removals, contains... * - *

    Note that because this collection holds references to other collections, modifications to children will be reflected here. - * Also, modifications to this collection will affect its children. + *

    Note that because this collection holds references to other collections, modifications to + * children will be reflected here. Also, modifications to this collection will affect its + * children. * - *

    If you need a collection that has the very same contents but isn't affected by operations to children, - * you can employ the {@link #asClone()} method, which returns a new collection with the same contents. + *

    If you need a collection that has the very same contents but isn't affected by operations to + * children, you can employ the {@link #asClone()} method, which returns a new collection with the + * same contents. * - *

    Since there are several children and not all may return the same return value for certain operations, - * you can control how this class behaves by means of the {@link #setResultMode(ResultMode)} method. - * It defaults to ANY, so operations that return booleans will return true as long as at least one children succeeded. + *

    Since there are several children and not all may return the same return value for certain + * operations, you can control how this class behaves by means of the {@link + * #setResultMode(ResultMode)} method. It defaults to ANY, so operations that return booleans will + * return true as long as at least one children succeeded. */ public abstract class SuperCollection implements Collection { private final List> parents; + /** + * Current result mode. + * + *

    If mode is set to ANY, operations will return "true" as long as the parents returned + * "true" at least once. + * + *

    If mode is set to ALL, operations will only return "true" if all parents also returned + * "true". + * + * @param resultMode Result mode. + * @return Result mode. + */ + @Getter + @Setter private ResultMode resultMode = ResultMode.ANY; + /** + * Determines how this collection will behave to additions. + * + *

    If mode is set to ALL, the addition will be performed on every parent. Default for sets. + * + *

    If mode is set to LAST, the operation will be performed on the last parent only. Default + * for lists. + * + * @param additionMode Addition mode. + * @return Addition mode. + */ + @Getter + @Setter private AdditionMode additionMode; public SuperCollection(AdditionMode additionMode) { @@ -43,53 +76,10 @@ public SuperCollection(List> parents, AdditionMode addit * @return Parent list. */ public List> getParents() { + // TODO: Replace with facade return parents; } - /** - * Returns current result mode. - * - * @return Result mode. - */ - public ResultMode getResultMode() { - return resultMode; - } - - /** - * Sets what will this collection returns for certain operations. - * - *

    If mode is set to ANY, operations will return "true" as long as the parents returned "true" at least once. - * - *

    If mode is set to ALL, operations will only return "true" if all parents also returned "true". - * - * @param resultMode Result mode. - */ - public void setResultMode(ResultMode resultMode) { - this.resultMode = resultMode; - } - - /** - * Returns current addition mode. - * - * @return Addition mode. - */ - public AdditionMode getAdditionMode() { - return additionMode; - } - - /** - * Sets how this collection will behave to additions. - * - *

    If mode is set to ALL, the addition will be performed on every parent. Default for sets. - * - *

    If mode is set to LAST, the operation will be performed on the last parent only. Default for lists. - * - * @param additionMode Addition mode. - */ - public void setAdditionMode(AdditionMode additionMode) { - this.additionMode = additionMode; - } - /** * Returns a new collection with the same contents as the parents. * @@ -111,9 +101,9 @@ protected boolean resultBoolean(int modified) { case ALL: return modified >= parents.size(); + default: + return false; } - - return false; } @Override @@ -132,9 +122,10 @@ public boolean add(E object) { case LAST: return parents.get(parents.size() - 1).add(object); + default: + throw new IllegalStateException( + "This SuperCollection has an invalid addition mode!"); } - - throw new IllegalStateException("This SuperCollection has an invalid addition mode!"); } @Override @@ -154,9 +145,10 @@ public boolean addAll(Collection objects) { case LAST: return parents.get(parents.size() - 1).addAll(objects); + default: + throw new IllegalStateException( + "This SuperCollection has an invalid addition mode!"); } - - throw new IllegalStateException("This SuperCollection has an invalid addition mode!"); } @Override @@ -292,7 +284,9 @@ public T[] toArray(T[] array) { @Override public String toString() { - // This is as other methods that call the asClone method, but since it's only used for eventual debugging, its performance doesn't really matter, so don't lose your time overriding and implementing it in subclasses. + // This is as other methods that call the asClone method, but since it's only used for + // eventual debugging, its performance doesn't really matter, so don't lose your time + // overriding and implementing it in subclasses. return asClone().toString(); } diff --git a/src/main/java/net/glowstone/util/collection/SuperList.java b/src/main/java/net/glowstone/util/collection/SuperList.java index 59b27ccd57..43da4e3cf8 100644 --- a/src/main/java/net/glowstone/util/collection/SuperList.java +++ b/src/main/java/net/glowstone/util/collection/SuperList.java @@ -220,7 +220,8 @@ public int size() { @Override public List subList(int fromIndex, int toIndex) { - // Kinda slow. If this is ever going to be used heavily, you'll probably want to implement a "SubList" class, since neither Java nor Guava provides a public implementation. + // Kinda slow. If this is ever going to be used heavily, you'll probably want to implement a + // "SubList" class, since neither Java nor Guava provides a public implementation. return asClone().subList(fromIndex, toIndex); } } diff --git a/src/main/java/net/glowstone/util/collection/SuperListIterator.java b/src/main/java/net/glowstone/util/collection/SuperListIterator.java index 307c91bb8c..983e616537 100644 --- a/src/main/java/net/glowstone/util/collection/SuperListIterator.java +++ b/src/main/java/net/glowstone/util/collection/SuperListIterator.java @@ -21,6 +21,12 @@ public SuperListIterator(ListIterator> parentIterator) { this.parentIterator = parentIterator; } + /** + * Creates an instance. + * + * @param parents a list of lists to iterate in a flattened manner + * @param index the initial index + */ public SuperListIterator(List> parents, int index) { this(parents); this.index = index; diff --git a/src/main/java/net/glowstone/util/config/ServerConfig.java b/src/main/java/net/glowstone/util/config/ServerConfig.java index 6b12aa0175..e60d8512c4 100644 --- a/src/main/java/net/glowstone/util/config/ServerConfig.java +++ b/src/main/java/net/glowstone/util/config/ServerConfig.java @@ -1,7 +1,9 @@ package net.glowstone.util.config; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.ImmutableList; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -9,11 +11,21 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.URL; +import java.nio.file.Paths; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.function.Predicate; import java.util.logging.Level; +import lombok.Getter; import net.glowstone.GlowServer; +import net.glowstone.util.DynamicallyTypedMap; +import net.glowstone.util.library.Library; +import net.glowstone.util.library.LibraryManager.HashAlgorithm; +import org.bukkit.Difficulty; +import org.bukkit.GameMode; +import org.bukkit.WorldType; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; @@ -23,12 +35,13 @@ /** * Utilities for handling the server configuration files. */ -public final class ServerConfig { +public final class ServerConfig implements DynamicallyTypedMap { /** * The directory configurations are stored in. */ - private final File configDir; + @Getter + private final File directory; /** * The main configuration file. @@ -53,24 +66,24 @@ public final class ServerConfig { /** * Initialize a new ServerConfig and associated settings. * - * @param configDir The config directory, or null for default. + * @param directory The config directory, or null for default. * @param configFile The config file, or null for default. * @param parameters The command-line parameters used as overrides. */ - public ServerConfig(File configDir, File configFile, Map parameters) { - checkNotNull(configDir); + public ServerConfig(File directory, File configFile, Map parameters) { + checkNotNull(directory); checkNotNull(configFile); checkNotNull(parameters); - this.configDir = configDir; + this.directory = directory; this.configFile = configFile; this.parameters = parameters; config.options().indent(4).copyHeader(true).header( - "glowstone.yml is the main configuration file for a Glowstone server\n" - + "It contains everything from server.properties and bukkit.yml in a\n" - + "normal CraftBukkit installation.\n\n" - + "For help, join us on Discord: https://discord.gg/TFJqhsC"); + "glowstone.yml is the main configuration file for a Glowstone server\n" + + "It contains everything from server.properties and bukkit.yml in a\n" + + "normal CraftBukkit installation.\n\n" + + "For help, join us on Discord: https://discord.gg/TFJqhsC"); } //////////////////////////////////////////////////////////////////////////// @@ -102,6 +115,7 @@ public void set(Key key, Object value) { //////////////////////////////////////////////////////////////////////////// // Value getters + @Override public String getString(Key key) { if (parameters.containsKey(key)) { return parameters.get(key).toString(); @@ -111,6 +125,7 @@ public String getString(Key key) { return string; } + @Override public int getInt(Key key) { if (parameters.containsKey(key)) { return (Integer) parameters.get(key); @@ -120,6 +135,7 @@ public int getInt(Key key) { return integer; } + @Override public boolean getBoolean(Key key) { if (parameters.containsKey(key)) { return (Boolean) parameters.get(key); @@ -129,9 +145,35 @@ public boolean getBoolean(Key key) { return bool; } + /** + * Retrieves a section as a list of maps. + * + * @param key the key to look up + * @return the value as a list of maps + */ + @SuppressWarnings("unchecked") + public List> getMapList(Key key) { + if (parameters.containsKey(key)) { + return (List>) parameters.get(key); + } + // there's no get or default method for the getMapList method, so using contains. + if (!config.contains(key.path)) { + parameters.put(key, key.def); + return (List>) key.def; + } + return config.getMapList(key.path); + } + //////////////////////////////////////////////////////////////////////////// // Fancy stuff + /** + * Returns the file that contains a given setting. If it doesn't exist, it is created and + * populated with defaults. + * + * @param key the configuration setting + * @return the file containing that setting + */ public ConfigurationSection getConfigFile(Key key) { String filename = getString(key); if (extraConfig.containsKey(filename)) { @@ -168,17 +210,18 @@ public ConfigurationSection getWorlds() { return config.getConfigurationSection("worlds"); } - public File getDirectory() { - return configDir; - } - public File getFile(String filename) { - return new File(configDir, filename); + return new File(directory, filename); } //////////////////////////////////////////////////////////////////////////// // Load and internals + /** + * Loads the server config from disk. If it doesn't exist, the default config is written, + * creating the folder if necessary. If it's in the old bukkit.yml format and/or incomplete, it + * is converted to canonical form and saved. + */ public void load() { // load extra config files again next time they're needed extraConfig.clear(); @@ -190,8 +233,8 @@ public void load() { GlowServer.logger.info("Creating default config: " + configFile); // create config directory - if (!configDir.isDirectory() && !configDir.mkdirs()) { - GlowServer.logger.severe("Cannot create directory: " + configDir); + if (!directory.isDirectory() && !directory.mkdirs()) { + GlowServer.logger.severe("Cannot create directory: " + directory); return; } @@ -220,6 +263,16 @@ public void load() { if (!config.contains(key.path)) { config.set(key.path, key.def); changed = true; + } else if (key.validator != null) { + // validate existing values + Object val = config.get(key.path); + if (!key.validator.test(val)) { + GlowServer.logger.warning( + "Invalid config value for '" + key.path + "' (" + val + "), " + + "resetting to default (" + key.def + ")"); + config.set(key.path, key.def); + changed = true; + } } } } @@ -237,7 +290,7 @@ private void copyDefaults(String source, File dest) { } try (final InputStream in = resource.openStream(); - final OutputStream out = new FileOutputStream(dest)) { + final OutputStream out = new FileOutputStream(dest)) { byte[] buf = new byte[2048]; int len; while ((len = in.read(buf)) > 0) { @@ -258,7 +311,7 @@ private void report(File file, InvalidConfigurationException e) { GlowServer.logger.severe("Config file " + file + " isn't valid!"); } else { GlowServer.logger - .log(Level.SEVERE, "Cannot load " + file + ": " + e.getCause().getClass(), e); + .log(Level.SEVERE, "Cannot load " + file + ": " + e.getCause().getClass(), e); } } @@ -308,7 +361,8 @@ private boolean migrate() { config.set(key.path, Integer.parseInt(value)); } catch (NumberFormatException e) { GlowServer.logger.log(Level.WARNING, - "Could not migrate " + key.migratePath + " from " + serverProps, e); + "Could not migrate " + key.migratePath + " from " + + serverProps, e); continue; } } else if (key.def instanceof Boolean) { @@ -324,21 +378,38 @@ private boolean migrate() { return migrateStatus; } + private static final List> DEFAULT_LIBRARIES_VALUE = + ImmutableList.>builder() + .add(new Library("org.xerial", "sqlite-jdbc", "3.21.0", HashAlgorithm.SHA1, + "347e4d1d3e1dff66d389354af8f0021e62344584").toConfigMap()) + .add(new Library("mysql", "mysql-connector-java", "5.1.44", HashAlgorithm.SHA1, + "61b6b998192c85bb581c6be90e03dcd4b9079db4").toConfigMap()) + .add(new Library("org.apache.logging.log4j", "log4j-api", "2.8.1", + HashAlgorithm.SHA1, "e801d13612e22cad62a3f4f3fe7fdbe6334a8e72") + .toConfigMap()) + .add(new Library("org.apache.logging.log4j", "log4j-core", "2.8.1", + HashAlgorithm.SHA1, "4ac28ff2f1ddf05dae3043a190451e8c46b73c31") + .toConfigMap()) + .add(new Library("org.apache.commons", "commons-lang3", "3.5", + HashAlgorithm.SHA1, "6c6c702c89bfff3cd9e80b04d668c5e190d588c6") + .toConfigMap()) + .build(); + /** * An enum containing configuration keys used by the server. */ public enum Key { // server SERVER_IP("server.ip", "", Migrate.PROPS, "server-ip"), - SERVER_PORT("server.port", 25565, Migrate.PROPS, "server-port"), + SERVER_PORT("server.port", 25565, Migrate.PROPS, "server-port", Validators.PORT), SERVER_NAME("server.name", "Glowstone Server", Migrate.PROPS, "server-name"), LOG_FILE("server.log-file", "logs/log-%D.txt"), ONLINE_MODE("server.online-mode", true, Migrate.PROPS, "online-mode"), - MAX_PLAYERS("server.max-players", 20, Migrate.PROPS, "max-players"), + MAX_PLAYERS("server.max-players", 20, Migrate.PROPS, "max-players", Validators.POSITIVE), WHITELIST("server.whitelisted", false, Migrate.PROPS, "white-list"), MOTD("server.motd", "A Glowstone server", Migrate.PROPS, "motd"), SHUTDOWN_MESSAGE("server.shutdown-message", "Server shutting down.", Migrate.BUKKIT, - "settings.shutdown-message"), + "settings.shutdown-message"), ALLOW_CLIENT_MODS("server.allow-client-mods", true), // console @@ -348,14 +419,17 @@ public enum Key { CONSOLE_LOG_DATE("console.log-date-format", "yyyy/MM/dd HH:mm:ss"), // game props - GAMEMODE("game.gamemode", "SURVIVAL", Migrate.PROPS, "gamemode"), + GAMEMODE("game.gamemode", "SURVIVAL", Migrate.PROPS, "gamemode", Validators + .forEnum(GameMode.class)), FORCE_GAMEMODE("game.gamemode-force", false, Migrate.PROPS, "force-gamemode"), - DIFFICULTY("game.difficulty", "NORMAL", Migrate.PROPS, "difficulty"), + DIFFICULTY("game.difficulty", "NORMAL", Migrate.PROPS, "difficulty", Validators + .forEnum(Difficulty.class)), HARDCORE("game.hardcore", false, Migrate.PROPS, "hardcore"), PVP_ENABLED("game.pvp", true, Migrate.PROPS, "pvp"), - MAX_BUILD_HEIGHT("game.max-build-height", 256, Migrate.PROPS, "max-build-height"), + MAX_BUILD_HEIGHT("game.max-build-height", 256, Migrate.PROPS, "max-build-height", + Validators.POSITIVE), ANNOUNCE_ACHIEVEMENTS("game.announce-achievements", true, Migrate.PROPS, - "announce-player-achievements"), + "announce-player-achievements"), // server.properties keys ALLOW_FLIGHT("game.allow-flight", false, Migrate.PROPS, "allow-flight"), @@ -365,69 +439,88 @@ public enum Key { RESOURCE_PACK_HASH("game.resource-pack-hash", "", Migrate.PROPS, "resource-pack-hash"), SNOOPER_ENABLED("server.snooper-enabled", false, Migrate.PROPS, "snooper-enabled"), PREVENT_PROXY("server.prevent-proxy-connections", true, Migrate.PROPS, - "prevent-proxy-connections"), + "prevent-proxy-connections"), // critters SPAWN_MONSTERS("creatures.enable.monsters", true, Migrate.PROPS, "spawn-monsters"), SPAWN_ANIMALS("creatures.enable.animals", true, Migrate.PROPS, "spawn-animals"), SPAWN_NPCS("creatures.enable.npcs", true, Migrate.PROPS, "spawn-npcs"), - MONSTER_LIMIT("creatures.limit.monsters", 70, Migrate.BUKKIT, "spawn-limits.monsters"), - ANIMAL_LIMIT("creatures.limit.animals", 15, Migrate.BUKKIT, "spawn-limits.animals"), + MONSTER_LIMIT("creatures.limit.monsters", 70, Migrate.BUKKIT, "spawn-limits.monsters", + Validators.ABSOLUTE), + ANIMAL_LIMIT("creatures.limit.animals", 15, Migrate.BUKKIT, "spawn-limits.animals", + Validators.ABSOLUTE), WATER_ANIMAL_LIMIT("creatures.limit.water", 5, Migrate.BUKKIT, - "spawn-limits.water-animals"), - AMBIENT_LIMIT("creatures.limit.ambient", 15, Migrate.BUKKIT, "spawn-limits.ambient"), - MONSTER_TICKS("creatures.ticks.monsters", 1, Migrate.BUKKIT, "ticks-per.monster-spawns"), - ANIMAL_TICKS("creatures.ticks.animal", 400, Migrate.BUKKIT, "ticks-per.animal-spawns"), + "spawn-limits.water-animals", Validators.ABSOLUTE), + AMBIENT_LIMIT("creatures.limit.ambient", 15, Migrate.BUKKIT, "spawn-limits.ambient", + Validators.ABSOLUTE), + MONSTER_TICKS("creatures.ticks.monsters", 1, Migrate.BUKKIT, "ticks-per.monster-spawns", + Validators.ABSOLUTE), + ANIMAL_TICKS("creatures.ticks.animal", 400, Migrate.BUKKIT, "ticks-per.animal-spawns", + Validators.ABSOLUTE), // folders - PLUGIN_FOLDER("folders.plugins", "plugins"), - UPDATE_FOLDER("folders.update", "update", Migrate.BUKKIT, "settings.update-folder"), - WORLD_FOLDER("folders.worlds", "worlds", Migrate.BUKKIT, "settings.world-container"), + PLUGIN_FOLDER("folders.plugins", "plugins", Validators.PATH), + UPDATE_FOLDER("folders.update", "update", Migrate.BUKKIT, "settings.update-folder", + Validators.PATH), + WORLD_FOLDER("folders.worlds", "worlds", Migrate.BUKKIT, "settings.world-container", + Validators.PATH), + LIBRARIES_FOLDER("folders.libraries", "lib", Validators.PATH), // files PERMISSIONS_FILE("files.permissions", "permissions.yml", Migrate.BUKKIT, - "settings.permissions-file"), - COMMANDS_FILE("files.commands", "commands.yml"), - HELP_FILE("files.help", "help.yml"), + "settings.permissions-file", Validators.PATH), + COMMANDS_FILE("files.commands", "commands.yml", Validators.PATH), + HELP_FILE("files.help", "help.yml", Validators.PATH), // advanced CONNECTION_THROTTLE("advanced.connection-throttle", 4000, Migrate.BUKKIT, - "settings.connection-throttle"), - //PING_PACKET_LIMIT("advanced.ping-packet-limit", 100, Migrate.BUKKIT, "settings.ping-packet-limit"), - PLAYER_IDLE_TIMEOUT("advanced.idle-timeout", 0, Migrate.PROPS, "player-idle-timeout"), + "settings.connection-throttle", Validators.ABSOLUTE), + //PING_PACKET_LIMIT( + // "advanced.ping-packet-limit", 100, Migrate.BUKKIT, "settings.ping-packet-limit"), + PLAYER_IDLE_TIMEOUT("advanced.idle-timeout", 0, Migrate.PROPS, "player-idle-timeout", + Validators.ABSOLUTE), WARN_ON_OVERLOAD("advanced.warn-on-overload", true, Migrate.BUKKIT, - "settings.warn-on-overload"), + "settings.warn-on-overload"), EXACT_LOGIN_LOCATION("advanced.exact-login-location", false, Migrate.BUKKIT, - "settings.use-exact-login-location"), + "settings.use-exact-login-location"), PLUGIN_PROFILING("advanced.plugin-profiling", false, Migrate.BUKKIT, - "settings.plugin-profiling"), + "settings.plugin-profiling"), WARNING_STATE("advanced.deprecated-verbose", "false", Migrate.BUKKIT, - "settings.deprecated-verbose"), + "settings.deprecated-verbose"), COMPRESSION_THRESHOLD("advanced.compression-threshold", 256, Migrate.PROPS, - "network-compression-threshold"), + "network-compression-threshold", Validators.ABSOLUTE.or((value) -> value == -1)), PROXY_SUPPORT("advanced.proxy-support", false), - PLAYER_SAMPLE_COUNT("advanced.player-sample-count", 12), + PLAYER_SAMPLE_COUNT("advanced.player-sample-count", 12, Validators.ABSOLUTE), GRAPHICS_COMPUTE("advanced.graphics-compute.enable", false), GRAPHICS_COMPUTE_ANY_DEVICE("advanced.graphics-compute.use-any-device", false), - REGION_CACHE_SIZE("advanced.region-file.cache-size", 256), + REGION_CACHE_SIZE("advanced.region-file.cache-size", 256, Validators.ABSOLUTE), REGION_COMPRESSION("advanced.region-file.compression", true), - PROFILE_LOOKUP_TIMEOUT("advanced.profile-lookup-timeout", 5), + PROFILE_LOOKUP_TIMEOUT("advanced.profile-lookup-timeout", 5, Validators.ABSOLUTE), + LIBRARY_CHECKSUM_VALIDATION("advanced.library-checksum-validation", true), + LIBRARY_REPOSITORY_URL("advanced.library-repository-url", + "https://repo.glowstone.net/service/local/repositories/central/content/"), + LIBRARY_DOWNLOAD_ATTEMPTS("advanced.library-download-attempts", 2, Validators.POSITIVE), + SUGGEST_PLAYER_NAMES_WHEN_NULL_TAB_COMPLETIONS( + "advanced.suggest-player-name-when-null-tab-completions", true), // query rcon etc QUERY_ENABLED("extras.query-enabled", false, Migrate.PROPS, "enable-query"), - QUERY_PORT("extras.query-port", 25614, Migrate.PROPS, "query.port"), + QUERY_PORT("extras.query-port", 25614, Migrate.PROPS, "query.port", Validators.PORT), QUERY_PLUGINS("extras.query-plugins", true, Migrate.BUKKIT, "settings.query-plugins"), RCON_ENABLED("extras.rcon-enabled", false, Migrate.PROPS, "enable-rcon"), RCON_PASSWORD("extras.rcon-password", "glowstone", Migrate.PROPS, "rcon.password"), - RCON_PORT("extras.rcon-port", 25575, Migrate.PROPS, "rcon.port"), + RCON_PORT("extras.rcon-port", 25575, Migrate.PROPS, "rcon.port", Validators.PORT), RCON_COLORS("extras.rcon-colors", true), // level props LEVEL_NAME("world.name", "world", Migrate.PROPS, "level-name"), LEVEL_SEED("world.seed", "", Migrate.PROPS, "level-seed"), - LEVEL_TYPE("world.level-type", "DEFAULT", Migrate.PROPS, "level-type"), - SPAWN_RADIUS("world.spawn-radius", 16, Migrate.PROPS, "spawn-protection"), - VIEW_DISTANCE("world.view-distance", 8, Migrate.PROPS, "view-distance"), + LEVEL_TYPE("world.level-type", "DEFAULT", Migrate.PROPS, "level-type", Validators + .WORLD_TYPE), + SPAWN_RADIUS("world.spawn-radius", 16, Migrate.PROPS, "spawn-protection", Validators + .ABSOLUTE), + VIEW_DISTANCE("world.view-distance", 8, Migrate.PROPS, "view-distance", Validators + .POSITIVE), GENERATE_STRUCTURES("world.gen-structures", true, Migrate.PROPS, "generate-structures"), ALLOW_NETHER("world.allow-nether", true, Migrate.PROPS, "allow-nether"), ALLOW_END("world.allow-end", true, Migrate.BUKKIT, "settings.allow-end"), @@ -441,22 +534,36 @@ public enum Key { DB_URL("database.url", "jdbc:sqlite:config/database.db", Migrate.BUKKIT, "database.url"), DB_USERNAME("database.username", "glowstone", Migrate.BUKKIT, "database.username"), DB_PASSWORD("database.password", "nether", Migrate.BUKKIT, "database.password"), - DB_ISOLATION("database.isolation", "SERIALIZABLE", Migrate.BUKKIT, "database.isolation"),; + DB_ISOLATION("database.isolation", "SERIALIZABLE", Migrate.BUKKIT, "database.isolation"), + // libraries + LIBRARIES("libraries", DEFAULT_LIBRARIES_VALUE),; + + @Getter private final String path; private final Object def; private final Migrate migrate; private final String migratePath; + private final Predicate validator; Key(String path, Object def) { this(path, def, null, null); } + Key(String path, Object def, Predicate validator) { + this(path, def, null, null, validator); + } + Key(String path, Object def, Migrate migrate, String migratePath) { + this(path, def, migrate, migratePath, null); + } + + Key(String path, Object def, Migrate migrate, String migratePath, Predicate validator) { this.path = path; this.def = def; this.migrate = migrate; this.migratePath = migratePath; + this.validator = validator; } @Override @@ -465,8 +572,88 @@ public String toString() { } } + /** + * A predicate wrapper to check if a value is a valid element of an enum. + * + *

    See {@link Validators#forEnum(Class)} + * + * @param the type of the enum + */ + static final class EnumPredicate implements Predicate { + final Class enumClass; + + EnumPredicate(Class enumClass) { + checkNotNull(enumClass); + checkArgument(enumClass.isEnum()); + this.enumClass = enumClass; + } + + @Override + public boolean test(String value) { + if (value == null || value.isEmpty()) { + return false; + } + try { + Enum.valueOf(enumClass, value); + } catch (Exception e) { + return false; + } + return true; + } + } + + static class Validators { + /** + * Checks if the value is positive (over zero). + */ + static final Predicate POSITIVE = (number) -> number > 0; + /** + * Checks if the value is zero. + */ + static final Predicate ZERO = (number) -> number == 0; + /** + * Checks if the value is greater than (positive) or equal to zero. + */ + static final Predicate ABSOLUTE = POSITIVE.or(ZERO); + /** + * Checks if the value is a valid port number. + */ + static final Predicate PORT = POSITIVE.and((number) -> number < 49151); + /** + * Checks if the value is a valid {@link WorldType} name. + */ + static final Predicate WORLD_TYPE = (value) -> WorldType.getByName(value) != null; + + /** + * Creates a {@link EnumPredicate} that checks if the value is a member of the given enum + * class. + * + * @param enumClass the enum class + * @param the type of the enum + * @return the predicate + */ + static EnumPredicate forEnum(Class enumClass) { + return new EnumPredicate<>(enumClass); + } + + /** + * Checks if the value is a valid file/directory path. + * + *

    Note that the behavior of this predicate may be platform-dependent. + */ + static final Predicate PATH = (value) -> { + try { + if (Paths.get(value) == null) { + return false; + } + } catch (Exception ex) { + return false; + } + return true; + }; + } + private enum Migrate { BUKKIT, PROPS } - } diff --git a/src/main/java/net/glowstone/util/config/WorldConfig.java b/src/main/java/net/glowstone/util/config/WorldConfig.java index 3401d827f8..d11ae2fce4 100644 --- a/src/main/java/net/glowstone/util/config/WorldConfig.java +++ b/src/main/java/net/glowstone/util/config/WorldConfig.java @@ -7,7 +7,9 @@ import java.util.HashMap; import java.util.Map; import java.util.logging.Level; +import lombok.Getter; import net.glowstone.GlowServer; +import net.glowstone.util.DynamicallyTypedMapWithDoubles; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.yaml.snakeyaml.error.YAMLException; @@ -15,12 +17,13 @@ /** * Utilities for handling the server configuration files. */ -public final class WorldConfig { +public final class WorldConfig implements DynamicallyTypedMapWithDoubles { /** * The directory configurations are stored in. */ - private final File configDir; + @Getter + private final File directory; /** * The main configuration file. @@ -30,6 +33,7 @@ public final class WorldConfig { /** * The actual configuration data. */ + @Getter private final YamlConfiguration config = new YamlConfiguration(); /** @@ -40,15 +44,15 @@ public final class WorldConfig { /** * Initialize a new ServerConfig and associated settings. * - * @param configDir The config directory, or null for default. + * @param directory The config directory, or null for default. * @param configFile The config file, or null for default. */ - public WorldConfig(File configDir, File configFile) { - checkNotNull(configDir); + public WorldConfig(File directory, File configFile) { + checkNotNull(directory); checkNotNull(configFile); checkNotNull(cache); - this.configDir = configDir; + this.directory = directory; this.configFile = configFile; } @@ -81,6 +85,7 @@ public void set(Key key, Object value) { //////////////////////////////////////////////////////////////////////////// // Value getters + @Override public String getString(Key key) { if (cache.containsKey(key)) { return cache.get(key).toString(); @@ -90,6 +95,7 @@ public String getString(Key key) { return string; } + @Override public int getInt(Key key) { if (cache.containsKey(key)) { return (Integer) cache.get(key); @@ -99,6 +105,7 @@ public int getInt(Key key) { return integer; } + @Override public double getDouble(Key key) { if (cache.containsKey(key)) { return (Double) cache.get(key); @@ -108,6 +115,12 @@ public double getDouble(Key key) { return doub; } + @Override + public float getFloat(Key key) { + return (float) getDouble(key); + } + + @Override public boolean getBoolean(Key key) { if (cache.containsKey(key)) { return (Boolean) cache.get(key); @@ -117,16 +130,13 @@ public boolean getBoolean(Key key) { return bool; } - //////////////////////////////////////////////////////////////////////////// - // Fancy stuff - - public File getDirectory() { - return configDir; - } - //////////////////////////////////////////////////////////////////////////// // Load and internals + /** + * Loads the configuration from disk if it exists. Creates it if it doesn't exist, creating the + * folder if necessary. Completes and saves the configuration if it's incomplete. + */ public void load() { boolean changed = false; @@ -135,8 +145,8 @@ public void load() { GlowServer.logger.info("Creating default world config: " + configFile); // create config directory - if (!configDir.isDirectory() && !configDir.mkdirs()) { - GlowServer.logger.severe("Cannot create directory: " + configDir); + if (!directory.isDirectory() && !directory.mkdirs()) { + GlowServer.logger.severe("Cannot create directory: " + directory); return; } @@ -177,14 +187,10 @@ private void report(File file, InvalidConfigurationException e) { GlowServer.logger.severe("Config file " + file + " isn't valid!"); } else { GlowServer.logger - .log(Level.SEVERE, "Cannot load " + file + ": " + e.getCause().getClass(), e); + .log(Level.SEVERE, "Cannot load " + file + ": " + e.getCause().getClass(), e); } } - public YamlConfiguration getConfig() { - return config; - } - /** * An enum containing configuration keys used by the server. */ diff --git a/src/main/java/net/glowstone/util/library/Library.java b/src/main/java/net/glowstone/util/library/Library.java new file mode 100644 index 0000000000..6b3f45b75e --- /dev/null +++ b/src/main/java/net/glowstone/util/library/Library.java @@ -0,0 +1,195 @@ +package net.glowstone.util.library; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; +import lombok.Getter; +import net.glowstone.util.library.LibraryManager.HashAlgorithm; + +/** + * Represents a library that will be injected into the classpath at runtime. + */ +public class Library { + private static final String ARTIFACT_ID_KEY = "artifact-id"; + private static final String CHECKSUM_KEY = "checksum"; + private static final String CHECKSUM_TYPE_KEY = "type"; + private static final String CHECKSUM_VALUE_KEY = "value"; + private static final String GROUP_ID_KEY = "group-id"; + private static final String REPOSITORY_KEY = "repository"; + private static final String VERSION_KEY = "version"; + + /** + * Extracts the needed information from a map of key-value pairs inside a config file to + * download a {@link Library} and inject it at runtime. + * + * @param configMap The Map that was extracted from a config file. + * @return A {@link Library} instance populated with whatever information we could extract. + */ + @SuppressWarnings("unchecked") + public static Library fromConfigMap(Map configMap) { + String group = (String) configMap.get(GROUP_ID_KEY); + String artifact = (String) configMap.get(ARTIFACT_ID_KEY); + String version = (String) configMap.get(VERSION_KEY); + String repository = (String) configMap.get(REPOSITORY_KEY); + HashAlgorithm checksumType = null; + String checksumValue = null; + + Map checksum = (Map) configMap.get(CHECKSUM_KEY); + if (checksum != null) { + checksumType = HashAlgorithm.getAlgorithm((String) checksum.get(CHECKSUM_TYPE_KEY)); + checksumValue = (String) checksum.get(CHECKSUM_VALUE_KEY); + } + + return new Library(group, artifact, version, repository, checksumType, + checksumValue); + } + + /** + * The group ID of the library in a maven-style repo. Parts of the group ID must be separated + * by periods. + */ + @Getter + private final String groupId; + + /** + * The artifact ID of the library in a maven-style repo. + */ + @Getter + private final String artifactId; + + /** + * The version number of the library in a maven-style repo. + */ + @Getter + private final String version; + + /** + * The optional URL for this library, for use in cases where the library is not part of the + * default Maven repo. + */ + @Getter + private final String repository; + + /** + * The algorithm used to generate the checksum for this library, if one was specified. + */ + @Getter + private final HashAlgorithm checksumType; + + /** + * The checksum itself, validated against the library to make sure the library is intact. + */ + @Getter + private final String checksumValue; + + /** + * Creates a {@link Library} instance with the specified group ID, artifact ID, and version. + * + * @param groupId The group ID of the library, separated by periods. + * @param artifactId The artifact ID of the library. + * @param version The version of the library. + */ + public Library(String groupId, String artifactId, String version) { + this(groupId, artifactId, version, null, null, null); + } + + /** + * Creates a {@link Library} instance with the specified group ID, artifact ID, version, and + * repository. + * + * @param groupId The group ID of the library, separated by periods. + * @param artifactId The artifact ID of the library. + * @param version The version of the library. + * @param repository The URL of the library's repository. + */ + public Library(String groupId, String artifactId, String version, String repository) { + this(groupId, artifactId, version, repository, null, null); + } + + /** + * Creates a {@link Library} instance with the specified group ID, artifact ID, version, and + * checksum. + * + * @param groupId The group ID of the library, separated by periods. + * @param artifactId The artifact ID of the library. + * @param version The version of the library. + * @param checksumType The type of hash the checksum is using. + * @param checksumValue The checksum to validate the downloaded library against. + */ + public Library(String groupId, String artifactId, String version, HashAlgorithm checksumType, + String checksumValue) { + this(groupId, artifactId, version, null, checksumType, checksumValue); + } + + /** + * Creates a {@link Library} instance with the specified group ID, artifact ID, version, + * repository, and checksum. + * + * @param groupId The group ID of the library, separated by periods. + * @param artifactId The artifact ID of the library. + * @param version The version of the library. + * @param repository The URL of the library's repository. + * @param checksumType The type of hash the checksum is using. + * @param checksumValue The checksum to validate the downloaded library against. + */ + public Library(String groupId, String artifactId, String version, + String repository, HashAlgorithm checksumType, String checksumValue) { + this.groupId = groupId; + this.artifactId = artifactId; + this.version = version; + this.repository = repository; + this.checksumType = checksumType; + this.checksumValue = checksumValue; + } + + /** + * Converts the {@link Library} instance to a map that can be serialized and saved into a + * config file. + * + * @return A map that is able to be serialized into a config. + */ + public Map toConfigMap() { + // Using LinkedHashMap to keep the props in order when written into the config file. + Map configMap = new LinkedHashMap<>(); + configMap.put(GROUP_ID_KEY, groupId); + configMap.put(ARTIFACT_ID_KEY, artifactId); + configMap.put(VERSION_KEY, version); + + if (repository != null) { + configMap.put(REPOSITORY_KEY, repository); + } + + if (checksumType != null && checksumValue != null) { + Map checksumMap = new LinkedHashMap<>(); + checksumMap.put(CHECKSUM_TYPE_KEY, checksumType.getName()); + checksumMap.put(CHECKSUM_VALUE_KEY, checksumValue); + configMap.put(CHECKSUM_KEY, checksumMap); + } + + return configMap; + } + + @Override + public String toString() { + return groupId + ":" + artifactId + ":" + version; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Library library = (Library) o; + return Objects.equals(groupId, library.groupId) + && Objects.equals(artifactId, library.artifactId) + && Objects.equals(version, library.version); + } + + @Override + public int hashCode() { + return Objects.hash(groupId, artifactId, version); + } +} diff --git a/src/main/java/net/glowstone/util/library/LibraryManager.java b/src/main/java/net/glowstone/util/library/LibraryManager.java new file mode 100644 index 0000000000..f4dc904df7 --- /dev/null +++ b/src/main/java/net/glowstone/util/library/LibraryManager.java @@ -0,0 +1,314 @@ +package net.glowstone.util.library; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.collect.Maps; +import com.google.common.hash.HashFunction; +import com.google.common.hash.Hashing; +import com.google.common.io.Files; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.jar.JarFile; +import java.util.logging.Level; +import javax.net.ssl.HttpsURLConnection; +import lombok.Getter; +import net.glowstone.GlowServer; +import net.glowstone.util.ClassPathAgent; +import net.glowstone.util.config.ServerConfig; + +/** + * Simple library manager which downloads external dependencies. + */ +public final class LibraryManager { + /** + * The Maven repository to download from. + */ + private final String defaultRepository; + + /** + * The directory to store downloads in. + */ + private final File directory; + + /** + * Whether the checksum of each library should be verified after being downloaded. + */ + private final boolean validateChecksum; + + /** + * The maximum amount of attempts to download each library. + */ + private final int maxDownloadAttempts; + + private final Collection libraries; + + private final ExecutorService downloaderService = Executors.newCachedThreadPool(); + + /** + * Creates the instance. + * + * @param defaultRepository the repository to download the libraries from + * @param directoryName the name of the directory to download the libraries to + * @param validateChecksum whether or not checksum validation is enabled + */ + public LibraryManager(String defaultRepository, String directoryName, boolean validateChecksum, + int maxDownloadAttempts, Collection libraries) { + checkNotNull(defaultRepository); + checkNotNull(directoryName); + this.defaultRepository = defaultRepository; + this.directory = new File(directoryName); + this.validateChecksum = validateChecksum; + this.maxDownloadAttempts = maxDownloadAttempts; + this.libraries = libraries; + } + + /** + * Downloads the libraries. + */ + public void run() { + if (!directory.isDirectory() && !directory.mkdirs()) { + GlowServer.logger + .log(Level.SEVERE, "Could not create libraries directory: " + directory); + } + + for (Library library : libraries) { + downloaderService.execute(new LibraryDownloader(library)); + } + + downloaderService.shutdown(); + try { + if (!downloaderService.awaitTermination(1, TimeUnit.MINUTES)) { + downloaderService.shutdownNow(); + } + } catch (InterruptedException e) { + GlowServer.logger.log(Level.SEVERE, "Library Manager thread interrupted: ", e); + } + } + + private class LibraryDownloader implements Runnable { + private final Library library; + private final String repository; + + /** + * Creates an instance of the downloader for a library. + * + * @param library a {@link Library} instance representing a library + */ + LibraryDownloader(Library library) { + this.library = library; + + String repository = library.getRepository(); + if (repository == null) { + repository = defaultRepository; + } + if (!repository.endsWith("/")) { + repository += "/"; + } + this.repository = repository; + } + + @Override + public void run() { + // check if we already have it + File file = new File(directory, getLibrary()); + if (!file.exists()) { + int attempts = 0; + while (attempts < maxDownloadAttempts) { + attempts++; + // download it + GlowServer.logger.info("Downloading " + library.toString() + "..."); + try { + URL downloadUrl = new URL( + repository + library.getGroupId().replace('.', '/') + '/' + + library.getArtifactId() + '/' + library.getVersion() + + '/' + library.getArtifactId() + '-' + + library.getVersion() + ".jar"); + HttpsURLConnection connection = (HttpsURLConnection) downloadUrl + .openConnection(); + connection.setRequestProperty("User-Agent", "Mozilla/5.0"); + + try (ReadableByteChannel input = Channels + .newChannel(connection.getInputStream()); + FileOutputStream output = new FileOutputStream(file)) { + output.getChannel().transferFrom(input, 0, Long.MAX_VALUE); + GlowServer.logger.info("Downloaded " + library.toString() + '.'); + } + + if (validateChecksum && library.getChecksumType() != null + && library.getChecksumValue() != null + && !checksum(file, library)) { + GlowServer.logger.severe("The checksum for the library '" + getLibrary() + + "' does not match. " + + (attempts == maxDownloadAttempts + ? "Restart the server to attempt downloading it again." + : "Attempting download again (" + + (attempts + 1) + "/" + maxDownloadAttempts + ")")); + file.delete(); + if (attempts == maxDownloadAttempts) { + return; + } + continue; + } + // everything's fine + break; + } catch (IOException e) { + GlowServer.logger.log(Level.WARNING, + "Failed to download: " + library.toString(), e); + file.delete(); + if (attempts == maxDownloadAttempts) { + GlowServer.logger.warning("Restart the server to attempt downloading '" + + getLibrary() + "' again."); + return; + } + GlowServer.logger + .warning("Attempting download of '" + getLibrary() + "' again (" + + (attempts + 1) + "/" + maxDownloadAttempts + ")"); + } + } + } else if (validateChecksum && library.getChecksumType() != null + && library.getChecksumValue() != null + && !checksum(file, library)) { + // The file is already downloaded, but validate the checksum as a warning only + GlowServer.logger.warning("The checksum for the library '" + getLibrary() + + "' does not match. " + + "Remove the library and restart the server to download it again."); + GlowServer.logger + .warning("Additionally, you can disable this warning in the server " + + "configuration, under '" + + ServerConfig.Key.LIBRARY_CHECKSUM_VALIDATION.getPath() + "'."); + } + + // hack it onto the classpath + try { + String[] javaVersion = System.getProperty("java.version").split("-")[0] + .split("\\."); + if (Integer.parseInt(javaVersion[0]) >= 9) { + ClassPathAgent.addJarFile(new JarFile(file)); + } else { + Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + method.setAccessible(true); + method.invoke(ClassLoader.getSystemClassLoader(), file.toURI().toURL()); + } + } catch (Exception e) { + GlowServer.logger.log(Level.WARNING, + "Failed to add to classpath: " + library.toString(), e); + } + } + + /** + * Gets the name of the file the library will be saved to. + * + * @return the name of the file the library will be saved to + */ + String getLibrary() { + return library.getArtifactId() + '-' + library.getVersion() + ".jar"; + } + + /** + * Computes and validates the checksum of a file. + * + *

    If the file does not exist, the checksum will be automatically invalidated. + * + *

    If the reference checksum or the algorithm are empty or null, the checksum will be + * automatically validated. + * + * @param file the file. + * @param library the {@link Library} instance containing the algorithm and the + * checksum. + * @return true if the checksum was validated, false otherwise. + */ + boolean checksum(File file, Library library) { + checkNotNull(file); + if (!file.exists()) { + return false; + } + HashAlgorithm algorithm = library.getChecksumType(); + String checksum = library.getChecksumValue(); + if (algorithm == null || checksum == null || checksum.isEmpty()) { + // assume everything is OK if no reference checksum is provided + return true; + } + // get the file digest + String digest; + try { + digest = Files.hash(file, algorithm.getFunction()).toString(); + } catch (IOException ex) { + GlowServer.logger.log(Level.SEVERE, + "Failed to compute digest for '" + file.getName() + "'", ex); + return false; + } + return digest.equals(checksum); + } + } + + /** + * An enum containing the supported hash algorithms. + */ + public enum HashAlgorithm { + /** + * The SHA-1 hash algorithm. + */ + SHA1(Hashing.sha1(), "sha1"), + /** + * The MD5 hash algorithm. + */ + MD5(Hashing.md5(), "md5"); + + /** + * The hash function for this algorithm. + */ + @Getter + private final HashFunction function; + /** + * The name of the algorithm, used in configuration files. + */ + @Getter + private final String name; + + private static final Map BY_NAME = Maps.newHashMap(); + + /** + * Represents a hash algorithm. + * + * @param function the {@link HashFunction} used to calculate the hash + * @param name the name of the algorithm + */ + HashAlgorithm(HashFunction function, String name) { + checkNotNull(function); + checkNotNull(name); + + this.function = function; + this.name = name; + } + + /** + * Gets the hash algorithm corresponding to the given name. + * + * @param name the name of the algorithm + * @return the corresponding algorithm, or null if none exists + */ + public static HashAlgorithm getAlgorithm(String name) { + checkNotNull(name); + + return BY_NAME.get(name.toLowerCase()); + } + + static { + // add the algorithms to the map + for (HashAlgorithm algorithm : values()) { + BY_NAME.put(algorithm.getName(), algorithm); + } + } + } +} diff --git a/src/main/java/net/glowstone/util/loot/LootItem.java b/src/main/java/net/glowstone/util/loot/LootItem.java index 2e4ec941be..07df54eb5a 100644 --- a/src/main/java/net/glowstone/util/loot/LootItem.java +++ b/src/main/java/net/glowstone/util/loot/LootItem.java @@ -11,6 +11,11 @@ public class LootItem { private final DefaultLootItem defaultItem; private final ConditionalLootItem[] conditionalItems; + /** + * Reads a LootItem from its JSON form. + * + * @param object a LootItem in JSON form + */ public LootItem(JSONObject object) { defaultItem = new DefaultLootItem((JSONObject) object.get("default")); if (object.containsKey("conditions")) { diff --git a/src/main/java/net/glowstone/util/loot/LootRandomValues.java b/src/main/java/net/glowstone/util/loot/LootRandomValues.java index f70528b8f5..8b137ff519 100644 --- a/src/main/java/net/glowstone/util/loot/LootRandomValues.java +++ b/src/main/java/net/glowstone/util/loot/LootRandomValues.java @@ -19,12 +19,23 @@ public class LootRandomValues { private final Optional reflectiveCount; private final Map probabilities = new HashMap<>(); + /** + * Creates an instance for a given range. + * + * @param min the minimum number + * @param max the maximum number + */ public LootRandomValues(int min, int max) { this.min = Optional.of(min); this.max = Optional.of(max); this.reflectiveCount = Optional.empty(); } + /** + * Reads an instance from its JSON form. + * + * @param object a LootRandomValues instance in JSON form + */ public LootRandomValues(JSONObject object) { if (!object.containsKey("count")) { this.min = Optional.empty(); diff --git a/src/main/java/net/glowstone/util/loot/LootingManager.java b/src/main/java/net/glowstone/util/loot/LootingManager.java index e4cd027d68..340a242e71 100644 --- a/src/main/java/net/glowstone/util/loot/LootingManager.java +++ b/src/main/java/net/glowstone/util/loot/LootingManager.java @@ -20,6 +20,11 @@ public class LootingManager { private static final Map entities = new HashMap<>(); + /** + * Registers the built-in loot data. + * + * @throws Exception if some loot data is missing or invalid + */ public static void load() throws Exception { String baseDir = "builtin/loot/entities/"; register(EntityType.BAT, baseDir + "bat.json"); @@ -90,6 +95,12 @@ private static void register(EntityType type, String location) throws Exception } } + /** + * Returns items and experience that the given entity drops when killed. + * + * @param entity the entity + * @return a {@link LootData} instance whose contents the entity can drop + */ public static LootData generate(GlowLivingEntity entity) { if (!entities.containsKey(entity.getType())) { return new LootData(InventoryUtil.NO_ITEMS_COLLECTION, 0); diff --git a/src/main/java/net/glowstone/util/loot/LootingUtil.java b/src/main/java/net/glowstone/util/loot/LootingUtil.java index 8c64b09296..d70cbc0a78 100644 --- a/src/main/java/net/glowstone/util/loot/LootingUtil.java +++ b/src/main/java/net/glowstone/util/loot/LootingUtil.java @@ -29,6 +29,13 @@ public static boolean isNot(Object a, Object b) { return !is(a, b); } + /** + * Evaluates a condition for an entity. + * + * @param entity the entity + * @param condition the condition string to evaluate + * @return true if the condition is satisfied; false otherwise + */ public static boolean conditionValue(GlowLivingEntity entity, String condition) { if (condition.equals("ENTITY_ONFIRE")) { return entity.getFireTicks() > 0; diff --git a/src/main/java/net/glowstone/util/loot/ProbableValue.java b/src/main/java/net/glowstone/util/loot/ProbableValue.java index df9b589e9f..2280284e01 100644 --- a/src/main/java/net/glowstone/util/loot/ProbableValue.java +++ b/src/main/java/net/glowstone/util/loot/ProbableValue.java @@ -8,11 +8,21 @@ import org.json.simple.JSONArray; import org.json.simple.JSONObject; +/** + * Probability distribution with a list of possible values. + */ @Data public class ProbableValue { private final Map possibilities = new HashMap<>(); + /** + * Reads a distribution from a JSON object. + * + * @param json a JSON object + * @param type the JSON property of {@code json} to read, which is either an instance of + * {@code T} or an array of objects of the form {@code {'chance': 0.123, 'value': T}} + */ public ProbableValue(JSONObject json, String type) { Object o = json.get(type); if (o instanceof JSONArray) { @@ -28,6 +38,12 @@ public ProbableValue(JSONObject json, String type) { } } + /** + * Samples a value from this distribution. + * + * @param random the PRNG to use + * @return a random value + */ public T generate(Random random) { if (possibilities.size() == 1 && (Double) Arrays.asList(possibilities.values().toArray()).get(0) == 1.0) { diff --git a/src/main/java/net/glowstone/util/mojangson/Mojangson.java b/src/main/java/net/glowstone/util/mojangson/Mojangson.java index 924ee13380..151d3bc492 100644 --- a/src/main/java/net/glowstone/util/mojangson/Mojangson.java +++ b/src/main/java/net/glowstone/util/mojangson/Mojangson.java @@ -40,9 +40,11 @@ private Mojangson() { } /** - * Detects the Tag type of the Mojangson string, and parses it. Convenience method for other parse methods. + * Detects the Tag type of the Mojangson string, and parses it. Convenience method for other + * parse methods. * - *

    This method will fall back to an IntTag if it could not find an appropriate Tag type, and to String if the value could not be parsed as an Integer either. + *

    This method will fall back to an IntTag if it could not find an appropriate Tag type, and + * to String if the value could not be parsed as an Integer either. * * @param mojangson The Mojangson string * @return The parsed NBT Tag @@ -50,7 +52,7 @@ private Mojangson() { */ public static Tag parseTag(String mojangson) throws MojangsonParseException { if (mojangson.startsWith(String.valueOf(STRING_QUOTES.getSymbol())) && mojangson - .endsWith(String.valueOf(STRING_QUOTES.getSymbol()))) { + .endsWith(String.valueOf(STRING_QUOTES.getSymbol()))) { return parseString(mojangson); } if (mojangson.endsWith(String.valueOf(BYTE_SUFFIX.getSymbol()))) { @@ -69,11 +71,11 @@ public static Tag parseTag(String mojangson) throws MojangsonParseException { return parseShort(mojangson); } if (mojangson.startsWith(String.valueOf(ARRAY_START.getSymbol())) && mojangson - .endsWith(String.valueOf(ARRAY_END.getSymbol()))) { + .endsWith(String.valueOf(ARRAY_END.getSymbol()))) { return parseArray(mojangson); } if (mojangson.startsWith(String.valueOf(COMPOUND_START.getSymbol())) && mojangson - .endsWith(String.valueOf(COMPOUND_END.getSymbol()))) { + .endsWith(String.valueOf(COMPOUND_END.getSymbol()))) { return parseCompound(mojangson); } try { @@ -83,11 +85,13 @@ public static Tag parseTag(String mojangson) throws MojangsonParseException { return parseLong(mojangson); // Could be a long if the number is too large } catch (MojangsonParseException e1) { try { + // Could be a decimal number without a type assignation, defaults to double return parseDouble( - mojangson); // Could be a decimal number without a type assignation, defaults to double + mojangson); } catch (MojangsonParseException e2) { + // Couldn't find anything matching it, assuming it is a String. return parseString( - mojangson); // Couldn't find anything matching it, assuming it is a String. + mojangson); } } } @@ -98,14 +102,15 @@ public static Tag parseTag(String mojangson) throws MojangsonParseException { * * @param mojangson The Mojangson string * @return the parsed IntTag NBT value - * @throws MojangsonParseException if the Mojangson string could not be parsed as an Integer value. + * @throws MojangsonParseException if the Mojangson string could not be parsed as an + * Integer value. */ public static IntTag parseInt(String mojangson) throws MojangsonParseException { try { return new IntTag(Integer.valueOf(mojangson)); } catch (NumberFormatException nfe) { throw new MojangsonParseException("\'" + mojangson + "\'", - MojangsonParseException.ParseExceptionReason.INVALID_FORMAT_NUM); + MojangsonParseException.ParseExceptionReason.INVALID_FORMAT_NUM); } } @@ -131,7 +136,8 @@ public static StringTag parseString(String mojangson) { * * @param mojangson The Mojangson string * @return the parsed LongTag NBT value - * @throws MojangsonParseException if the Mojangson string could not be parsed as a Long value. + * @throws MojangsonParseException if the Mojangson string could not be parsed as a Long + * value. */ public static LongTag parseLong(String mojangson) throws MojangsonParseException { Character lastChar = mojangson.charAt(mojangson.length() - 1); @@ -143,7 +149,7 @@ public static LongTag parseLong(String mojangson) throws MojangsonParseException return new LongTag(Long.valueOf(mojangson)); } catch (NumberFormatException nfe) { throw new MojangsonParseException("\'" + mojangson + "\'", - MojangsonParseException.ParseExceptionReason.INVALID_FORMAT_NUM); + MojangsonParseException.ParseExceptionReason.INVALID_FORMAT_NUM); } } @@ -152,12 +158,13 @@ public static LongTag parseLong(String mojangson) throws MojangsonParseException * * @param mojangson The Mojangson string * @return the parsed DoubleTag NBT value - * @throws MojangsonParseException if the Mojangson string could not be parsed as a Double value. + * @throws MojangsonParseException if the Mojangson string could not be parsed as a + * Double value. */ public static DoubleTag parseDouble(String mojangson) throws MojangsonParseException { Character lastChar = mojangson.charAt(mojangson.length() - 1); if (lastChar.toString().toLowerCase().charAt(0) == MojangsonToken.DOUBLE_SUFFIX - .getSymbol()) { + .getSymbol()) { mojangson = mojangson.substring(0, mojangson.length() - 1); } @@ -165,7 +172,7 @@ public static DoubleTag parseDouble(String mojangson) throws MojangsonParseExcep return new DoubleTag(Double.valueOf(mojangson)); } catch (NumberFormatException nfe) { throw new MojangsonParseException("\'" + mojangson + "\'", - MojangsonParseException.ParseExceptionReason.INVALID_FORMAT_NUM); + MojangsonParseException.ParseExceptionReason.INVALID_FORMAT_NUM); } } @@ -174,12 +181,13 @@ public static DoubleTag parseDouble(String mojangson) throws MojangsonParseExcep * * @param mojangson The Mojangson string * @return the parsed FloatTag NBT value - * @throws MojangsonParseException if the Mojangson string could not be parsed as a Flaot value. + * @throws MojangsonParseException if the Mojangson string could not be parsed as a + * Flaot value. */ public static FloatTag parseFloat(String mojangson) throws MojangsonParseException { Character lastChar = mojangson.charAt(mojangson.length() - 1); if (lastChar.toString().toLowerCase().charAt(0) == MojangsonToken.FLOAT_SUFFIX - .getSymbol()) { + .getSymbol()) { mojangson = mojangson.substring(0, mojangson.length() - 1); } @@ -187,7 +195,7 @@ public static FloatTag parseFloat(String mojangson) throws MojangsonParseExcepti return new FloatTag(Float.valueOf(mojangson)); } catch (NumberFormatException nfe) { throw new MojangsonParseException("\'" + mojangson + "\'", - MojangsonParseException.ParseExceptionReason.INVALID_FORMAT_NUM); + MojangsonParseException.ParseExceptionReason.INVALID_FORMAT_NUM); } } @@ -196,12 +204,13 @@ public static FloatTag parseFloat(String mojangson) throws MojangsonParseExcepti * * @param mojangson The Mojangson string * @return the parsed ShortTag NBT value - * @throws MojangsonParseException if the Mojangson string could not be parsed as a Short value. + * @throws MojangsonParseException if the Mojangson string could not be parsed as a + * Short value. */ public static ShortTag parseShort(String mojangson) throws MojangsonParseException { Character lastChar = mojangson.charAt(mojangson.length() - 1); if (lastChar.toString().toLowerCase().charAt(0) == MojangsonToken.SHORT_SUFFIX - .getSymbol()) { + .getSymbol()) { mojangson = mojangson.substring(0, mojangson.length() - 1); } @@ -209,7 +218,7 @@ public static ShortTag parseShort(String mojangson) throws MojangsonParseExcepti return new ShortTag(Short.valueOf(mojangson)); } catch (NumberFormatException nfe) { throw new MojangsonParseException("\'" + mojangson + "\'", - MojangsonParseException.ParseExceptionReason.INVALID_FORMAT_NUM); + MojangsonParseException.ParseExceptionReason.INVALID_FORMAT_NUM); } } @@ -218,7 +227,8 @@ public static ShortTag parseShort(String mojangson) throws MojangsonParseExcepti * * @param mojangson The Mojangson string * @return the parsed ByteTag NBT value - * @throws MojangsonParseException if the Mojangson string could not be parsed as a Byte value. + * @throws MojangsonParseException if the Mojangson string could not be parsed as a Byte + * value. */ public static ByteTag parseByte(String mojangson) throws MojangsonParseException { Character lastChar = mojangson.charAt(mojangson.length() - 1); @@ -230,7 +240,7 @@ public static ByteTag parseByte(String mojangson) throws MojangsonParseException return new ByteTag(Byte.valueOf(mojangson)); } catch (NumberFormatException nfe) { throw new MojangsonParseException("\'" + mojangson + "\'", - MojangsonParseException.ParseExceptionReason.INVALID_FORMAT_NUM); + MojangsonParseException.ParseExceptionReason.INVALID_FORMAT_NUM); } } @@ -239,7 +249,8 @@ public static ByteTag parseByte(String mojangson) throws MojangsonParseException * * @param mojangson The Mojangson string * @return the parsed CompoundTag NBT value - * @throws MojangsonParseException if the Mojangson string could not be parsed as a Compound value. + * @throws MojangsonParseException if the Mojangson string could not be parsed as a + * Compound value. */ public static CompoundTag parseCompound(String mojangson) throws MojangsonParseException { final int parseCompoundStart = 0; // Parsing context magic value @@ -249,7 +260,9 @@ public static CompoundTag parseCompound(String mojangson) throws MojangsonParseE int context = parseCompoundStart; // The current context of the parser String tmpkey = ""; // Temporary key being parsed, in its raw form String tmpval = ""; // Temporary value - int scope = 0; // The scope level of the compound, this allows coherent nested arrays and compounds. + int scope + = 0; // The scope level of the compound, this allows coherent nested arrays and + // compounds. boolean inString = false; // The current character is part of a string inclusion CompoundTag tag = new CompoundTag(); @@ -265,18 +278,18 @@ public static CompoundTag parseCompound(String mojangson) throws MojangsonParseE } } if ((character == COMPOUND_START.getSymbol() || character == ARRAY_START.getSymbol()) - && !inString) { + && !inString) { scope++; } if ((character == COMPOUND_END.getSymbol() || character == ARRAY_END.getSymbol()) - && !inString) { + && !inString) { scope--; } if (context == parseCompoundStart) { if (character != COMPOUND_START.getSymbol()) { throw new MojangsonParseException( - "Index: " + index + ", symbol: \'" + character + "\'", - MojangsonParseException.ParseExceptionReason.UNEXPECTED_SYMBOL); + "Index: " + index + ", symbol: \'" + character + "\'", + MojangsonParseException.ParseExceptionReason.UNEXPECTED_SYMBOL); } context++; continue; @@ -291,7 +304,7 @@ public static CompoundTag parseCompound(String mojangson) throws MojangsonParseE } if (context == parseCompoundPairValue) { if ((character == ELEMENT_SEPERATOR.getSymbol() || character == COMPOUND_END - .getSymbol()) && scope <= 1 && !inString) { + .getSymbol()) && scope <= 1 && !inString) { context = parseCompoundPairKey; tag.getValue().put(tmpkey, parseTag(tmpval)); tmpkey = tmpval = ""; @@ -307,8 +320,10 @@ public static CompoundTag parseCompound(String mojangson) throws MojangsonParseE * Parses an Array value from a Mojangson string. * * @param mojangson The Mojangson string - * @return a ByteArrayTag value if the array contains byte values, an IntArrayTag value if the array contains int values or a ListTag with the array's elements. - * @throws MojangsonParseException if the Mojangson string could not be parsed as an Array value. + * @return a ByteArrayTag value if the array contains byte values, an IntArrayTag value if the + * array contains int values or a ListTag with the array's elements. + * @throws MojangsonParseException if the Mojangson string could not be parsed as an + * Array value. */ public static Tag parseArray(String mojangson) throws MojangsonParseException { final int parseArrayStart = 0; // Parsing context magic value @@ -316,7 +331,10 @@ public static Tag parseArray(String mojangson) throws MojangsonParseException { int context = parseArrayStart; // The current context of the parser String tmpval = ""; // Temporary value being parsed, in its raw form - int scope = 0; // The scope level of the array, this allows coherent nested arrays and compounds. + + // The scope level of the array, this allows coherent nested arrays and compounds. + int scope = 0; + boolean inString = false; // The current character is part of a string inclusion TagType tagType = null; // The element content type. List values = new ArrayList<>(); @@ -333,25 +351,25 @@ public static Tag parseArray(String mojangson) throws MojangsonParseException { } } if ((character == COMPOUND_START.getSymbol() || character == ARRAY_START.getSymbol()) - && !inString) { + && !inString) { scope++; } if ((character == COMPOUND_END.getSymbol() || character == ARRAY_END.getSymbol()) - && !inString) { + && !inString) { scope--; } if (context == parseArrayStart) { if (character != ARRAY_START.getSymbol()) { throw new MojangsonParseException( - "Index: " + index + ", symbol: \'" + character + "\'", - MojangsonParseException.ParseExceptionReason.UNEXPECTED_SYMBOL); + "Index: " + index + ", symbol: \'" + character + "\'", + MojangsonParseException.ParseExceptionReason.UNEXPECTED_SYMBOL); } context++; continue; } if (context == parseArrayElement) { if ((character == ELEMENT_SEPERATOR.getSymbol() || character == ARRAY_END - .getSymbol()) && scope <= 1 && !inString) { + .getSymbol()) && scope <= 1 && !inString) { if (tmpval.length() == 0) { continue; } @@ -361,8 +379,8 @@ public static Tag parseArray(String mojangson) throws MojangsonParseException { tagType = val.getType(); } else if (tagType != val.getType()) { throw new MojangsonParseException( - "Index: " + index + ", value: \'" + tmpval + "\'", - MojangsonParseException.ParseExceptionReason.INCOMPATIBLE_TYPE); + "Index: " + index + ", value: \'" + tmpval + "\'", + MojangsonParseException.ParseExceptionReason.INCOMPATIBLE_TYPE); } values.add(val); @@ -390,11 +408,13 @@ public static Tag parseArray(String mojangson) throws MojangsonParseException { } /** - * Creates a Mojangson string from the given NBT Tag. Convenience method for generic tags (Tag). + * Creates a Mojangson string from the given NBT Tag. Convenience method for generic tags + * (Tag). * * @param tag the NBT Tag to convert * @return the converted Mojangson string */ + @SuppressWarnings("unchecked") public static String fromGenericTag(Tag tag) { switch (tag.getType()) { case BYTE: @@ -412,15 +432,16 @@ public static String fromGenericTag(Tag tag) { case INT_ARRAY: return fromTag((IntArrayTag) tag); case LIST: - return fromTag((ListTag) tag); + return fromTag((ListTag) tag); case LONG: return fromTag((LongTag) tag); case SHORT: return fromTag((ShortTag) tag); case STRING: return fromTag((StringTag) tag); + default: + return null; } - return null; } /** @@ -588,6 +609,6 @@ public static String fromTag(ShortTag tag) { */ public static String fromTag(StringTag tag) { return String.valueOf(MojangsonToken.STRING_QUOTES) + tag.getValue() - + MojangsonToken.STRING_QUOTES; + + MojangsonToken.STRING_QUOTES; } } diff --git a/src/main/java/net/glowstone/util/mojangson/MojangsonToken.java b/src/main/java/net/glowstone/util/mojangson/MojangsonToken.java index 187b0c1e93..14347fef80 100644 --- a/src/main/java/net/glowstone/util/mojangson/MojangsonToken.java +++ b/src/main/java/net/glowstone/util/mojangson/MojangsonToken.java @@ -1,5 +1,10 @@ package net.glowstone.util.mojangson; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor public enum MojangsonToken { COMPOUND_START(0, "Compound_Start", '{'), @@ -18,27 +23,9 @@ public enum MojangsonToken { WHITE_SPACE(13, "WhiteSpace", ' '); - private int id; - private String name; - private char symbol; - - MojangsonToken(int id, String name, char symbol) { - this.id = id; - this.name = name; - this.symbol = symbol; - } - - public int getId() { - return id; - } - - public String getName() { - return name; - } - - public char getSymbol() { - return symbol; - } + private final int id; + private final String name; + private final char symbol; @Override public String toString() { diff --git a/src/main/java/net/glowstone/util/mojangson/ex/MojangsonParseException.java b/src/main/java/net/glowstone/util/mojangson/ex/MojangsonParseException.java index 5ec5638cbd..e5327141cb 100644 --- a/src/main/java/net/glowstone/util/mojangson/ex/MojangsonParseException.java +++ b/src/main/java/net/glowstone/util/mojangson/ex/MojangsonParseException.java @@ -1,7 +1,11 @@ package net.glowstone.util.mojangson.ex; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + public class MojangsonParseException extends Exception { + @Getter private ParseExceptionReason reason; public MojangsonParseException(String message, ParseExceptionReason reason) { @@ -9,28 +13,18 @@ public MojangsonParseException(String message, ParseExceptionReason reason) { this.reason = reason; } - public ParseExceptionReason getReason() { - return reason; - } - @Override public String getMessage() { return reason.getMessage() + ": " + super.getMessage(); } + @RequiredArgsConstructor public enum ParseExceptionReason { INVALID_FORMAT_NUM("Given value is not numerical"), UNEXPECTED_SYMBOL("Unexpected symbol in Mojangson string"), INCOMPATIBLE_TYPE("List does not support given tag type."); - private String message; - - ParseExceptionReason(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } + @Getter + private final String message; } } diff --git a/src/main/java/net/glowstone/util/nbt/ByteArrayTag.java b/src/main/java/net/glowstone/util/nbt/ByteArrayTag.java index 4065fb1264..73cf3a7639 100644 --- a/src/main/java/net/glowstone/util/nbt/ByteArrayTag.java +++ b/src/main/java/net/glowstone/util/nbt/ByteArrayTag.java @@ -1,5 +1,7 @@ package net.glowstone.util.nbt; +import lombok.Getter; + /** * The {@code TAG_Byte_Array} tag. */ @@ -11,6 +13,7 @@ public final class ByteArrayTag extends Tag { /** * The value. */ + @Getter private final byte[] value; /** @@ -23,11 +26,6 @@ public ByteArrayTag(byte... value) { this.value = value; } - @Override - public byte[] getValue() { - return value; - } - @Override protected void valueToString(StringBuilder hex) { for (byte b : value) { diff --git a/src/main/java/net/glowstone/util/nbt/CompoundTag.java b/src/main/java/net/glowstone/util/nbt/CompoundTag.java index 7453a68ef2..f9f209964d 100644 --- a/src/main/java/net/glowstone/util/nbt/CompoundTag.java +++ b/src/main/java/net/glowstone/util/nbt/CompoundTag.java @@ -10,15 +10,19 @@ import java.util.Map; import java.util.Map.Entry; import java.util.stream.Collectors; +import lombok.Getter; +import net.glowstone.util.DynamicallyTypedMapWithDoubles; /** * The {@code TAG_Compound} tag. */ -public final class CompoundTag extends Tag> { +public final class CompoundTag extends Tag> + implements DynamicallyTypedMapWithDoubles { /** * The value. */ + @Getter private final Map value = new LinkedHashMap<>(); /** @@ -28,11 +32,6 @@ public CompoundTag() { super(TagType.COMPOUND); } - @Override - public Map getValue() { - return value; - } - @Override protected void valueToString(StringBuilder builder) { builder.append(value.size()).append(" entries\n{\n"); @@ -172,6 +171,11 @@ public int getInt(String key) { return get(key, IntTag.class); } + @Override + public boolean getBoolean(String key) { + return getByte(key) != 0; + } + /** * Returns the value of a {@code long} subtag. * @@ -385,6 +389,7 @@ public boolean isIntArray(String key) { * Test whether the subtag with the given key is of {@link List} type. * * @param key the key to look up + * @param type the {@link TagType} of the list's elements * @return true if the subtag exists and is a {@link List}; false otherwise */ public boolean isList(String key, TagType type) { @@ -396,15 +401,27 @@ public boolean isList(String key, TagType type) { } /** - * Test whether the subtag with the given key is of CompoundTag type. + * Test whether the subtag with the given key is of {@link CompoundTag} type. * * @param key the key to look up - * @return true if the subtag exists and is a CompoundTag; false otherwise + * @return true if the subtag exists and is a {@link CompoundTag}; false otherwise */ public boolean isCompound(String key) { return is(key, CompoundTag.class); } + /** + * Test whether the subtag with the given key is of {@link List} type with elements of type + * {@link CompoundTag}. + * + * @param key the key to look up + * @return true if the subtag exists and is a {@link List} with elements of type + * {@link CompoundTag}; false otherwise + */ + public boolean isCompoundList(String key) { + return isList(key, TagType.COMPOUND); + } + //////////////////////////////////////////////////////////////////////////// // Simple sets diff --git a/src/main/java/net/glowstone/util/nbt/IntArrayTag.java b/src/main/java/net/glowstone/util/nbt/IntArrayTag.java index bf609af082..6f3c379a35 100644 --- a/src/main/java/net/glowstone/util/nbt/IntArrayTag.java +++ b/src/main/java/net/glowstone/util/nbt/IntArrayTag.java @@ -1,5 +1,7 @@ package net.glowstone.util.nbt; +import lombok.Getter; + /** * The {@code TAG_Int_Array} tag. */ @@ -8,6 +10,7 @@ public final class IntArrayTag extends Tag { /** * The value. */ + @Getter private final int[] value; /** @@ -20,11 +23,6 @@ public IntArrayTag(int... value) { this.value = value; } - @Override - public int[] getValue() { - return value; - } - @Override protected void valueToString(StringBuilder hex) { for (int b : value) { diff --git a/src/main/java/net/glowstone/util/nbt/ListTag.java b/src/main/java/net/glowstone/util/nbt/ListTag.java index 0b028606a8..cfaf900679 100644 --- a/src/main/java/net/glowstone/util/nbt/ListTag.java +++ b/src/main/java/net/glowstone/util/nbt/ListTag.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import lombok.Getter; /** * The {@code TAG_List} tag. @@ -10,8 +11,11 @@ public final class ListTag extends Tag> { /** * The type of entries within this list. + * + * @return The type of item in this list. */ - private final TagType type; + @Getter + private final TagType childType; /** * The value. @@ -21,32 +25,23 @@ public final class ListTag extends Tag> { /** * Creates the tag. * - * @param type The type of item in the list. + * @param childType The type of item in the list. * @param value The value. */ - public ListTag(TagType type, List value) { + public ListTag(TagType childType, List value) { super(TagType.LIST); - this.type = type; + this.childType = childType; this.value = new ArrayList<>(value); // modifying list should not modify tag // ensure type of objects in list matches tag type for (Tag elem : value) { - if (type != elem.getType()) { + if (childType != elem.getType()) { throw new IllegalArgumentException( - "ListTag(" + type + ") cannot hold tags of type " + elem.getType()); + "ListTag(" + childType + ") cannot hold tags of type " + elem.getType()); } } } - /** - * Gets the type of item in this list. - * - * @return The type of item in this list. - */ - public TagType getChildType() { - return type; - } - @Override public List getValue() { return value; @@ -54,7 +49,7 @@ public List getValue() { @Override protected void valueToString(StringBuilder builder) { - builder.append(value.size()).append(" entries of type ").append(type.getName()) + builder.append(value.size()).append(" entries of type ").append(childType.getName()) .append("\n{\n"); for (T elem : value) { builder.append(" ").append(elem.toString().replaceAll("\n", "\n ")).append("\n"); diff --git a/src/main/java/net/glowstone/util/nbt/NBTInputStream.java b/src/main/java/net/glowstone/util/nbt/NbtInputStream.java similarity index 92% rename from src/main/java/net/glowstone/util/nbt/NBTInputStream.java rename to src/main/java/net/glowstone/util/nbt/NbtInputStream.java index 5fce04b33f..003c5b1fe5 100644 --- a/src/main/java/net/glowstone/util/nbt/NBTInputStream.java +++ b/src/main/java/net/glowstone/util/nbt/NbtInputStream.java @@ -9,11 +9,12 @@ import java.util.zip.GZIPInputStream; /** - * This class reads NBT, or Named Binary Tag streams, and produces an object graph of subclasses of the {@link Tag} object. + * This class reads NBT, or Named Binary Tag streams, and produces an object graph of subclasses of + * the {@link Tag} object. * *

    The NBT format was created by Markus Persson, and the specification may be found at http://www.minecraft.net/docs/NBT.txt. */ -public final class NBTInputStream implements Closeable { +public final class NbtInputStream implements Closeable { /** * The data input stream. @@ -28,7 +29,7 @@ public final class NBTInputStream implements Closeable { * @param is The input stream. * @throws IOException if an I/O error occurs. */ - public NBTInputStream(InputStream is) throws IOException { + public NbtInputStream(InputStream is) throws IOException { this(is, true); } @@ -42,7 +43,7 @@ public NBTInputStream(InputStream is) throws IOException { * @throws IOException if an I/O error occurs. */ @SuppressWarnings("resource") - public NBTInputStream(InputStream is, boolean compressed) throws IOException { + public NbtInputStream(InputStream is, boolean compressed) throws IOException { this.is = new DataInputStream(compressed ? new GZIPInputStream(is) : is); } @@ -53,7 +54,7 @@ public NBTInputStream(InputStream is, boolean compressed) throws IOException { * @throws IOException if an I/O error occurs. */ public CompoundTag readCompound() throws IOException { - return readCompound(NBTReadLimiter.UNLIMITED); + return readCompound(NbtReadLimiter.UNLIMITED); } /** @@ -63,7 +64,7 @@ public CompoundTag readCompound() throws IOException { * @return The tag that was read. * @throws IOException if an I/O error occurs. */ - public CompoundTag readCompound(NBTReadLimiter readLimiter) throws IOException { + public CompoundTag readCompound(NbtReadLimiter readLimiter) throws IOException { // read type TagType type = TagType.byIdOrError(is.readUnsignedByte()); if (type != TagType.COMPOUND) { @@ -78,7 +79,7 @@ public CompoundTag readCompound(NBTReadLimiter readLimiter) throws IOException { return (CompoundTag) readTagPayload(type, 0, readLimiter); } - private CompoundTag readCompound(int depth, NBTReadLimiter readLimiter) throws IOException { + private CompoundTag readCompound(int depth, NbtReadLimiter readLimiter) throws IOException { CompoundTag result = new CompoundTag(); while (true) { @@ -110,7 +111,7 @@ private CompoundTag readCompound(int depth, NBTReadLimiter readLimiter) throws I * @throws IOException if an I/O error occurs. */ @SuppressWarnings("unchecked") - private Tag readTagPayload(TagType type, int depth, NBTReadLimiter readLimiter) + private Tag readTagPayload(TagType type, int depth, NbtReadLimiter readLimiter) throws IOException { if (depth > 512) { diff --git a/src/main/java/net/glowstone/util/nbt/NBTOutputStream.java b/src/main/java/net/glowstone/util/nbt/NbtOutputStream.java similarity index 90% rename from src/main/java/net/glowstone/util/nbt/NBTOutputStream.java rename to src/main/java/net/glowstone/util/nbt/NbtOutputStream.java index df24769427..2d05b23c3f 100644 --- a/src/main/java/net/glowstone/util/nbt/NBTOutputStream.java +++ b/src/main/java/net/glowstone/util/nbt/NbtOutputStream.java @@ -11,11 +11,12 @@ import java.util.zip.GZIPOutputStream; /** - * This class writes NBT, or Named Binary Tag, {@link Tag} objects to an underlying {@link OutputStream}. + * This class writes NBT, or Named Binary Tag, {@link Tag} objects to an underlying + * {@link OutputStream}. * *

    The NBT format was created by Markus Persson, and the specification may be found at http://www.minecraft.net/docs/NBT.txt. */ -public final class NBTOutputStream implements Closeable { +public final class NbtOutputStream implements Closeable { /** * The output stream. @@ -23,24 +24,26 @@ public final class NBTOutputStream implements Closeable { private final DataOutputStream os; /** - * Creates a new NBTOutputStream, which will write data to the specified underlying output stream. This assumes the output stream should be compressed with GZIP. + * Creates a new NBTOutputStream, which will write data to the specified underlying output + * stream. This assumes the output stream should be compressed with GZIP. * * @param os The output stream. * @throws IOException if an I/O error occurs. */ - public NBTOutputStream(OutputStream os) throws IOException { + public NbtOutputStream(OutputStream os) throws IOException { this(os, true); } /** - * Creates a new NBTOutputStream, which will write data to the specified underlying output stream. A flag indicates if the output should be compressed with GZIP or not. + * Creates a new NBTOutputStream, which will write data to the specified underlying output + * stream. A flag indicates if the output should be compressed with GZIP or not. * * @param os The output stream. * @param compressed A flag that indicates if the output should be compressed. * @throws IOException if an I/O error occurs. */ @SuppressWarnings("resource") - public NBTOutputStream(OutputStream os, boolean compressed) throws IOException { + public NbtOutputStream(OutputStream os, boolean compressed) throws IOException { this.os = new DataOutputStream(compressed ? new GZIPOutputStream(os) : os); } diff --git a/src/main/java/net/glowstone/util/nbt/NBTReadLimiter.java b/src/main/java/net/glowstone/util/nbt/NbtReadLimiter.java similarity index 52% rename from src/main/java/net/glowstone/util/nbt/NBTReadLimiter.java rename to src/main/java/net/glowstone/util/nbt/NbtReadLimiter.java index 1d1f12e902..1cb01d18c7 100644 --- a/src/main/java/net/glowstone/util/nbt/NBTReadLimiter.java +++ b/src/main/java/net/glowstone/util/nbt/NbtReadLimiter.java @@ -1,8 +1,8 @@ package net.glowstone.util.nbt; -public class NBTReadLimiter { +public class NbtReadLimiter { - public static final NBTReadLimiter UNLIMITED = new NBTReadLimiter(0L) { + public static final NbtReadLimiter UNLIMITED = new NbtReadLimiter(0L) { @Override public void read(int length) { @@ -12,10 +12,15 @@ public void read(int length) { private final long limit; private long read; - public NBTReadLimiter(long limit) { + public NbtReadLimiter(long limit) { this.limit = limit; } + /** + * Increments the read-length count, and throws an exception if the limit is exceeded. + * @param length the length to add to the read-length count + * @throws IllegalStateException if the limit is exceeded + */ public void read(int length) { read += length; if (read > limit) { diff --git a/src/main/java/net/glowstone/util/nbt/StringTag.java b/src/main/java/net/glowstone/util/nbt/StringTag.java index fbe8c7eba9..4ad593871b 100644 --- a/src/main/java/net/glowstone/util/nbt/StringTag.java +++ b/src/main/java/net/glowstone/util/nbt/StringTag.java @@ -1,5 +1,7 @@ package net.glowstone.util.nbt; +import lombok.Getter; + /** * The {@code TAG_String} tag. */ @@ -8,6 +10,7 @@ public final class StringTag extends Tag { /** * The value. */ + @Getter private final String value; /** @@ -19,10 +22,5 @@ public StringTag(String value) { super(TagType.STRING); this.value = value; } - - @Override - public String getValue() { - return value; - } } diff --git a/src/main/java/net/glowstone/util/nbt/Tag.java b/src/main/java/net/glowstone/util/nbt/Tag.java index 7a330be6a9..e3d461a5ab 100644 --- a/src/main/java/net/glowstone/util/nbt/Tag.java +++ b/src/main/java/net/glowstone/util/nbt/Tag.java @@ -1,33 +1,20 @@ package net.glowstone.util.nbt; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + /** * Represents a single NBT tag. */ +@RequiredArgsConstructor public abstract class Tag { /** * The type of this tag. */ + @Getter private final TagType type; - /** - * Creates the tag with the specified type. - * - * @param type The type. - */ - protected Tag(TagType type) { - this.type = type; - } - - /** - * Gets the type of this tag. - * - * @return The type of this tag. - */ - public final TagType getType() { - return type; - } - /** * Gets the value of this tag. * diff --git a/src/main/java/net/glowstone/util/nbt/TagType.java b/src/main/java/net/glowstone/util/nbt/TagType.java index 834fd4a457..8c0664f2a0 100644 --- a/src/main/java/net/glowstone/util/nbt/TagType.java +++ b/src/main/java/net/glowstone/util/nbt/TagType.java @@ -4,10 +4,14 @@ import java.lang.reflect.Constructor; import java.util.List; import java.util.Map; +import lombok.Getter; +import lombok.RequiredArgsConstructor; /** * The types of NBT tags that exist. */ +@Getter +@RequiredArgsConstructor public enum TagType { END("End", null, Void.class), @@ -19,8 +23,6 @@ public enum TagType { DOUBLE("Double", DoubleTag.class, double.class), BYTE_ARRAY("Byte_Array", ByteArrayTag.class, byte[].class), STRING("String", StringTag.class, String.class), - // javac complains about this because ListTag is generic - @SuppressWarnings("unchecked") LIST("List", ListTag.class, List.class), COMPOUND("Compound", CompoundTag.class, Map.class), INT_ARRAY("Int_Array", IntArrayTag.class, int[].class); @@ -29,13 +31,12 @@ public enum TagType { private final Class tagClass; private final Class valueClass; - > TagType(String name, Class tagClass, Class valueClass) { - // ? extends V is needed to get Compound to work for some reason - this.name = name; - this.tagClass = tagClass; - this.valueClass = valueClass; - } - + /** + * Returns the tag type with a given ID. + * + * @param id the ID to look up + * @return the tag type with ID {@code id}, or null if none exists + */ public static TagType byId(int id) { if (id < 0 || id >= values().length) { return null; @@ -43,6 +44,13 @@ public static TagType byId(int id) { return values()[id]; } + /** + * Returns the tag type with a given ID. + * + * @param id the ID to look up + * @return the tag type with ID {@code id} + * @throws IOException if {@code id} doesn't match any tag type + */ static TagType byIdOrError(int id) throws IOException { if (id < 0 || id >= values().length) { throw new IOException("Invalid tag type: " + id); @@ -54,18 +62,6 @@ public byte getId() { return (byte) ordinal(); } - public String getName() { - return name; - } - - public Class getTagClass() { - return tagClass; - } - - public Class getValueClass() { - return valueClass; - } - public Constructor getConstructor() throws NoSuchMethodException { return tagClass.getConstructor(valueClass); } diff --git a/src/main/java/net/glowstone/util/noise/PerlinNoise.java b/src/main/java/net/glowstone/util/noise/PerlinNoise.java index a08833c332..b879222bc6 100644 --- a/src/main/java/net/glowstone/util/noise/PerlinNoise.java +++ b/src/main/java/net/glowstone/util/noise/PerlinNoise.java @@ -5,6 +5,10 @@ public class PerlinNoise extends PerlinNoiseGenerator { + /** + * Creates an instance using the given PRNG. + * @param rand the PRNG used to generate the seed permutation + */ public PerlinNoise(Random rand) { offsetX = rand.nextDouble() * 256; offsetY = rand.nextDouble() * 256; @@ -13,8 +17,8 @@ public PerlinNoise(Random rand) { // on at least 3 different sources that the permutation table should initially be // populated with indices. // "The permutation table is his answer to the issue of random numbers. - // First take an array of decent length, usually 256 values. Fill it sequentially - // with each number in that range: so index 1 gets 1, index 8 gets 8, index 251 gets 251, etc... + // First take an array of decent length, usually 256 values. Fill it sequentially with each + // number in that range: so index 1 gets 1, index 8 gets 8, index 251 gets 251, etc... // Then randomly shuffle the values so you have a table of 256 random values, but only // contains the values between 0 and 255." // source: https://code.google.com/p/fractalterraingeneration/wiki/Perlin_Noise @@ -31,10 +35,26 @@ public PerlinNoise(Random rand) { } public static int floor(double x) { - int iX = (int) x; - return x < iX ? iX - 1 : iX; + int floored = (int) x; + return x < floored ? floored - 1 : floored; } + /** + * Generates a rectangular section of this generator's noise. + * + * @param noise the output of the previous noise layer + * @param x the X offset + * @param y the Y offset + * @param z the Z offset + * @param sizeX the size on the X axis + * @param sizeY the size on the Y axis + * @param sizeZ the size on the Z axis + * @param scaleX the X scale parameter + * @param scaleY the Y scale parameter + * @param scaleZ the Z scale parameter + * @param amplitude the amplitude parameter + * @return {@code noise} with this layer of noise added + */ public double[] getNoise(double[] noise, double x, double y, double z, int sizeX, int sizeY, int sizeZ, double scaleX, double scaleY, double scaleZ, double amplitude) { if (sizeY == 1) { @@ -49,26 +69,26 @@ protected double[] get2dNoise(double[] noise, double x, double z, int sizeX, int double scaleX, double scaleZ, double amplitude) { int index = 0; for (int i = 0; i < sizeX; i++) { - double dX = x + offsetX + i * scaleX; - int floorX = floor(dX); - int iX = floorX & 255; - dX -= floorX; - double fX = fade(dX); + double dx = x + offsetX + i * scaleX; + int floorX = floor(dx); + int ix = floorX & 255; + dx -= floorX; + double fx = fade(dx); for (int j = 0; j < sizeZ; j++) { - double dZ = z + offsetZ + j * scaleZ; - int floorZ = floor(dZ); - int iZ = floorZ & 255; - dZ -= floorZ; - double fZ = fade(dZ); + double dz = z + offsetZ + j * scaleZ; + int floorZ = floor(dz); + int iz = floorZ & 255; + dz -= floorZ; + double fz = fade(dz); // Hash coordinates of the square corners - int a = perm[iX]; - int aa = perm[a] + iZ; - int b = perm[iX + 1]; - int ba = perm[b] + iZ; - double x1 = lerp(fX, grad(perm[aa], dX, 0, dZ), grad(perm[ba], dX - 1, 0, dZ)); - double x2 = lerp(fX, grad(perm[aa + 1], dX, 0, dZ - 1), - grad(perm[ba + 1], dX - 1, 0, dZ - 1)); - noise[index++] += lerp(fZ, x1, x2) * amplitude; + int a = perm[ix]; + int aa = perm[a] + iz; + int b = perm[ix + 1]; + int ba = perm[b] + iz; + double x1 = lerp(fx, grad(perm[aa], dx, 0, dz), grad(perm[ba], dx - 1, 0, dz)); + double x2 = lerp(fx, grad(perm[aa + 1], dx, 0, dz - 1), + grad(perm[ba + 1], dx - 1, 0, dz - 1)); + noise[index++] += lerp(fz, x1, x2) * amplitude; } } return noise; @@ -83,44 +103,44 @@ protected double[] get3dNoise(double[] noise, double x, double y, double z, int double x4 = 0; int index = 0; for (int i = 0; i < sizeX; i++) { - double dX = x + offsetX + i * scaleX; - int floorX = floor(dX); - int iX = floorX & 255; - dX -= floorX; - double fX = fade(dX); + double dx = x + offsetX + i * scaleX; + int floorX = floor(dx); + int ix = floorX & 255; + dx -= floorX; + double fx = fade(dx); for (int j = 0; j < sizeZ; j++) { - double dZ = z + offsetZ + j * scaleZ; - int floorZ = floor(dZ); - int iZ = floorZ & 255; - dZ -= floorZ; - double fZ = fade(dZ); + double dz = z + offsetZ + j * scaleZ; + int floorZ = floor(dz); + int iz = floorZ & 255; + dz -= floorZ; + double fz = fade(dz); for (int k = 0; k < sizeY; k++) { - double dY = y + offsetY + k * scaleY; - int floorY = floor(dY); - int iY = floorY & 255; - dY -= floorY; - double fY = fade(dY); - if (k == 0 || iY != n) { - n = iY; + double dy = y + offsetY + k * scaleY; + int floorY = floor(dy); + int iy = floorY & 255; + dy -= floorY; + double fy = fade(dy); + if (k == 0 || iy != n) { + n = iy; // Hash coordinates of the cube corners - int a = perm[iX] + iY; - int aa = perm[a] + iZ; - int ab = perm[a + 1] + iZ; - int b = perm[iX + 1] + iY; - int ba = perm[b] + iZ; - int bb = perm[b + 1] + iZ; - x1 = lerp(fX, grad(perm[aa], dX, dY, dZ), grad(perm[ba], dX - 1, dY, dZ)); - x2 = lerp(fX, grad(perm[ab], dX, dY - 1, dZ), - grad(perm[bb], dX - 1, dY - 1, dZ)); - x3 = lerp(fX, grad(perm[aa + 1], dX, dY, dZ - 1), - grad(perm[ba + 1], dX - 1, dY, dZ - 1)); - x4 = lerp(fX, grad(perm[ab + 1], dX, dY - 1, dZ - 1), - grad(perm[bb + 1], dX - 1, dY - 1, dZ - 1)); + int a = perm[ix] + iy; + int aa = perm[a] + iz; + int ab = perm[a + 1] + iz; + int b = perm[ix + 1] + iy; + int ba = perm[b] + iz; + int bb = perm[b + 1] + iz; + x1 = lerp(fx, grad(perm[aa], dx, dy, dz), grad(perm[ba], dx - 1, dy, dz)); + x2 = lerp(fx, grad(perm[ab], dx, dy - 1, dz), + grad(perm[bb], dx - 1, dy - 1, dz)); + x3 = lerp(fx, grad(perm[aa + 1], dx, dy, dz - 1), + grad(perm[ba + 1], dx - 1, dy, dz - 1)); + x4 = lerp(fx, grad(perm[ab + 1], dx, dy - 1, dz - 1), + grad(perm[bb + 1], dx - 1, dy - 1, dz - 1)); } - double y1 = lerp(fY, x1, x2); - double y2 = lerp(fY, x3, x4); + double y1 = lerp(fy, x1, x2); + double y2 = lerp(fy, x3, x4); - noise[index++] += lerp(fZ, y1, y2) * amplitude; + noise[index++] += lerp(fz, y1, y2) * amplitude; } } } diff --git a/src/main/java/net/glowstone/util/noise/PerlinOctaveGenerator.java b/src/main/java/net/glowstone/util/noise/PerlinOctaveGenerator.java index 2fdcf3b7e0..aca4479ecc 100644 --- a/src/main/java/net/glowstone/util/noise/PerlinOctaveGenerator.java +++ b/src/main/java/net/glowstone/util/noise/PerlinOctaveGenerator.java @@ -8,28 +8,37 @@ public class PerlinOctaveGenerator extends OctaveGenerator { @Getter - protected final int xSize; + protected final int sizeX; @Getter - protected final int ySize; + protected final int sizeY; @Getter - protected final int zSize; + protected final int sizeZ; protected double[] noise; - public PerlinOctaveGenerator(Random rand, int octaves, int xSize, int zSize) { - this(rand, octaves, xSize, 1, zSize); + public PerlinOctaveGenerator(Random rand, int octaves, int sizeX, int sizeZ) { + this(rand, octaves, sizeX, 1, sizeZ); } - public PerlinOctaveGenerator(Random rand, int octaves, int xSize, int ySize, int zSize) { - this(createOctaves(rand, octaves), rand, xSize, ySize, zSize); + public PerlinOctaveGenerator(Random rand, int octaves, int sizeX, int sizeY, int sizeZ) { + this(createOctaves(rand, octaves), rand, sizeX, sizeY, sizeZ); } - public PerlinOctaveGenerator(NoiseGenerator[] octaves, Random rand, int xSize, int ySize, - int zSize) { + /** + * Creates a generator for multiple layers of Perlin noise. + * + * @param octaves the noise generators + * @param rand the PRNG + * @param sizeX the size on the X axis + * @param sizeY the size on the Y axis + * @param sizeZ the size on the Z axis + */ + public PerlinOctaveGenerator(NoiseGenerator[] octaves, Random rand, int sizeX, int sizeY, + int sizeZ) { super(octaves); - this.xSize = xSize; - this.ySize = ySize; - this.zSize = zSize; - noise = new double[xSize * ySize * zSize]; + this.sizeX = sizeX; + this.sizeY = sizeY; + this.sizeZ = sizeZ; + noise = new double[sizeX * sizeY * sizeZ]; } protected static NoiseGenerator[] createOctaves(Random rand, int octaves) { @@ -46,11 +55,32 @@ protected static long floor(double x) { return x >= 0 ? (long) x : (long) x - 1; } - public double[] getFractalBrownianMotion(double x, double z, double lacunarity, double persistence) { + /** + * Generates multiple layers of noise. + * + * @param x the starting X coordinate + * @param z the starting Z coordinate + * @param lacunarity layer n's frequency as a fraction of layer {@code n - 1}'s frequency + * @param persistence layer n's amplitude as a multiple of layer {@code n - 1}'s amplitude + * @return + */ + public double[] getFractalBrownianMotion( + double x, double z, double lacunarity, double persistence) { return getFractalBrownianMotion(x, 0, z, lacunarity, persistence); } - public double[] getFractalBrownianMotion(double x, double y, double z, double lacunarity, double persistence) { + /** + * Generates multiple layers of noise. + * + * @param x the starting X coordinate + * @param y the starting Y coordinate + * @param z the starting Z coordinate + * @param lacunarity layer n's frequency as a fraction of layer {@code n - 1}'s frequency + * @param persistence layer n's amplitude as a multiple of layer {@code n - 1}'s amplitude + * @return + */ + public double[] getFractalBrownianMotion(double x, double y, double z, double lacunarity, + double persistence) { for (int i = 0; i < noise.length; i++) { noise[i] = 0; } @@ -63,27 +93,28 @@ public double[] getFractalBrownianMotion(double x, double y, double z, double la z = z * zScale; // fBm - // the noise have to be periodic over x and z axis: otherwise it can go crazy with high input, - // leading to strange oddities in terrain generation like the old minecraft farland symptoms. + // the noise have to be periodic over x and z axis: otherwise it can go crazy with high + // input, leading to strange oddities in terrain generation like the old minecraft farland + // symptoms. for (NoiseGenerator octave : octaves) { - double dX = x * freq; - double dZ = z * freq; + double dx = x * freq; + double dz = z * freq; // compute integer part - long lX = floor(dX); - long lZ = floor(dZ); + long lx = floor(dx); + long lz = floor(dz); // compute fractional part - dX -= lX; - dZ -= lZ; + dx -= lx; + dz -= lz; // wrap integer part to 0..16777216 - lX %= 16777216; - lZ %= 16777216; + lx %= 16777216; + lz %= 16777216; // add to fractional part - dX += lX; - dZ += lZ; + dx += lx; + dz += lz; - double dY = y * freq; + double dy = y * freq; noise = ((PerlinNoise) octave) - .getNoise(noise, dX, dY, dZ, xSize, ySize, zSize, xScale * freq, yScale * freq, + .getNoise(noise, dx, dy, dz, sizeX, sizeY, sizeZ, xScale * freq, yScale * freq, zScale * freq, amp); freq *= lacunarity; amp *= persistence; diff --git a/src/main/java/net/glowstone/util/noise/SimplexNoise.java b/src/main/java/net/glowstone/util/noise/SimplexNoise.java index e5c9340891..aa6d579061 100644 --- a/src/main/java/net/glowstone/util/noise/SimplexNoise.java +++ b/src/main/java/net/glowstone/util/noise/SimplexNoise.java @@ -2,16 +2,14 @@ import java.util.Random; -/* - * A speed-improved simplex noise algorithm +/** + * A speed-improved simplex noise algorithm. * - * Based on example code by Stefan Gustavson (stegu@itn.liu.se). + *

    Based on example code by Stefan Gustavson (stegu@itn.liu.se). * Optimisations by Peter Eastman (peastman@drizzle.stanford.edu). * Better rank ordering method by Stefan Gustavson in 2012. * - * This could be sped up even further, but it's useful as is. - * - * Version 2012-03-09 + *

    This could be sped up even further, but it's useful as is. */ public class SimplexNoise extends PerlinNoise { @@ -29,6 +27,11 @@ public class SimplexNoise extends PerlinNoise { new Grad(0, 1, 1), new Grad(0, -1, 1), new Grad(0, 1, -1), new Grad(0, -1, -1)}; protected final int[] permMod12 = new int[512]; + /** + * Creates a simplex noise generator. + * + * @param rand the PRNG to use + */ public SimplexNoise(Random rand) { super(rand); for (int i = 0; i < 512; i++) { @@ -100,10 +103,10 @@ private double simplex2D(double xin, double yin) { int i = floor(xin + s); int j = floor(yin + s); double t = (i + j) * G2; - double dX0 = i - t; // Unskew the cell origin back to (x,y) space - double dY0 = j - t; - double x0 = xin - dX0; // The x,y distances from the cell origin - double y0 = yin - dY0; + double dx0 = i - t; // Unskew the cell origin back to (x,y) space + double dy0 = j - t; + double x0 = xin - dx0; // The x,y distances from the cell origin + double y0 = yin - dy0; // For the 2D case, the simplex shape is an equilateral triangle. @@ -174,9 +177,9 @@ private double simplex3D(double xin, double yin, double zin) { int j = floor(yin + s); int k = floor(zin + s); double t = (i + j + k) * G3; - double dX0 = i - t; // Unskew the cell origin back to (x,y,z) space - double dY0 = j - t; - double dZ0 = k - t; + double dx0 = i - t; // Unskew the cell origin back to (x,y,z) space + double dy0 = j - t; + double dz0 = k - t; // For the 3D case, the simplex shape is a slightly irregular tetrahedron. @@ -187,9 +190,9 @@ private double simplex3D(double xin, double yin, double zin) { int j2; int k2; - double x0 = xin - dX0; // The x,y,z distances from the cell origin - double y0 = yin - dY0; - double z0 = zin - dZ0; + double x0 = xin - dx0; // The x,y,z distances from the cell origin + double y0 = yin - dy0; + double z0 = zin - dz0; // Determine which simplex we are in if (x0 >= y0) { if (y0 >= z0) { diff --git a/src/main/java/net/glowstone/util/noise/SimplexOctaveGenerator.java b/src/main/java/net/glowstone/util/noise/SimplexOctaveGenerator.java index d9becaf463..fc826a0058 100644 --- a/src/main/java/net/glowstone/util/noise/SimplexOctaveGenerator.java +++ b/src/main/java/net/glowstone/util/noise/SimplexOctaveGenerator.java @@ -5,12 +5,12 @@ public class SimplexOctaveGenerator extends PerlinOctaveGenerator { - public SimplexOctaveGenerator(Random rand, int octaves, int xSize, int zSize) { - this(rand, octaves, xSize, 1, zSize); + public SimplexOctaveGenerator(Random rand, int octaves, int sizeX, int sizeZ) { + this(rand, octaves, sizeX, 1, sizeZ); } - public SimplexOctaveGenerator(Random rand, int octaves, int xSize, int ySize, int zSize) { - super(createOctaves(rand, octaves), rand, xSize, ySize, zSize); + public SimplexOctaveGenerator(Random rand, int octaves, int sizeX, int sizeY, int sizeZ) { + super(createOctaves(rand, octaves), rand, sizeX, sizeY, sizeZ); } public SimplexOctaveGenerator(Random rand, int octaves) { @@ -28,7 +28,8 @@ protected static NoiseGenerator[] createOctaves(Random rand, int octaves) { } @Override - public double[] getFractalBrownianMotion(double x, double y, double z, double lacunarity, double persistence) { + public double[] getFractalBrownianMotion( + double x, double y, double z, double lacunarity, double persistence) { for (int i = 0; i < noise.length; i++) { noise[i] = 0; } @@ -39,7 +40,7 @@ public double[] getFractalBrownianMotion(double x, double y, double z, double la // fBm for (NoiseGenerator octave : octaves) { noise = ((SimplexNoise) octave) - .getNoise(noise, x, y, z, xSize, ySize, zSize, xScale * freq, yScale * freq, + .getNoise(noise, x, y, z, sizeX, sizeY, sizeZ, xScale * freq, yScale * freq, zScale * freq, 0.55D / amp); freq *= lacunarity; amp *= persistence; diff --git a/src/main/java/net/glowstone/util/pattern/BlockPattern.java b/src/main/java/net/glowstone/util/pattern/BlockPattern.java index c46006df68..845968b684 100644 --- a/src/main/java/net/glowstone/util/pattern/BlockPattern.java +++ b/src/main/java/net/glowstone/util/pattern/BlockPattern.java @@ -12,10 +12,6 @@ public BlockPattern(PatternItem... blocks) { this.blocks = blocks; } - public PatternItem[] getBlocks() { - return blocks; - } - /** * Test whether this pattern matches a block. * @param location the base location diff --git a/src/test/java/net/glowstone/util/nbt/NbtInputTest.java b/src/test/java/net/glowstone/util/nbt/NbtInputTest.java index 5ff9703bf5..6fafa48bb9 100644 --- a/src/test/java/net/glowstone/util/nbt/NbtInputTest.java +++ b/src/test/java/net/glowstone/util/nbt/NbtInputTest.java @@ -8,7 +8,7 @@ import org.junit.Test; /** - * Tests for {@link NBTInputStream} and reading from {@link CompoundTag}s. + * Tests for {@link NbtInputStream} and reading from {@link CompoundTag}s. */ public class NbtInputTest { @@ -16,7 +16,7 @@ public class NbtInputTest { public void helloWorld() throws IOException { InputStream raw = getClass().getResourceAsStream("/nbt/hello_world.nbt"); assertThat("Failed to get test resource /nbt/hello_world.nbt", raw, notNullValue()); - try (NBTInputStream in = new NBTInputStream(raw, false)) { + try (NbtInputStream in = new NbtInputStream(raw, false)) { Checks.checkHelloWorld(in.readCompound()); } } @@ -25,7 +25,7 @@ public void helloWorld() throws IOException { public void bigTest() throws IOException { InputStream raw = getClass().getResourceAsStream("/nbt/bigtest.nbt"); assertThat("Failed to get test resource /nbt/bigtest.nbt", raw, notNullValue()); - try (NBTInputStream in = new NBTInputStream(raw)) { + try (NbtInputStream in = new NbtInputStream(raw)) { Checks.checkBigTest(in.readCompound()); } } diff --git a/src/test/java/net/glowstone/util/nbt/NbtOutputTest.java b/src/test/java/net/glowstone/util/nbt/NbtOutputTest.java index 2fbdca52d8..7c3b2aad45 100644 --- a/src/test/java/net/glowstone/util/nbt/NbtOutputTest.java +++ b/src/test/java/net/glowstone/util/nbt/NbtOutputTest.java @@ -8,7 +8,7 @@ import org.junit.Test; /** - * Tests for {@link NBTOutputStream} and constructing {@link CompoundTag}s. + * Tests for {@link NbtOutputStream} and constructing {@link CompoundTag}s. */ public class NbtOutputTest { @@ -76,11 +76,11 @@ public void bigTest() throws IOException { private CompoundTag saveLoad(CompoundTag tag) throws IOException { ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); - try (NBTOutputStream out = new NBTOutputStream(bytesOut)) { + try (NbtOutputStream out = new NbtOutputStream(bytesOut)) { out.writeTag(tag); } ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytesOut.toByteArray()); - try (NBTInputStream in = new NBTInputStream(bytesIn)) { + try (NbtInputStream in = new NbtInputStream(bytesIn)) { return in.readCompound(); } }