22
23import java.io.IOException;
24
25public class IslandLand { 26 private final Island island; 27 28 private final World world; 29 private final double[] positions; 30 private final double x; 31 private final double y; 32 private final double z; 33 private final double yaw; 34 private final double pitch; 35 36 private final Location location; 37 38 private final VectorWrapper minPoint; 39 private final VectorWrapper maxPoint; 40 41 private final LandState landState; 42 43 public IslandLand(final Island island, final World world, double[] positions) { 44 this.island = island; 45 this.world = world; 46 this.positions = positions; 47 this.x = positions[0]; 48 this.y = positions[1]; 49 this.z = positions[2]; 50 51 final ClipboardWrapper schematicPlot = island.getSchematicClipboardWrapper(); 52 53 final RegionWrapper regionWrapper = schematicPlot.region(); 54 final VectorWrapper origin = schematicPlot.getOrigin(); 55 56 this.yaw = 0f; 57 this.pitch = 0f; 58 59 this.minPoint = regionWrapper.getMinimumPoint() 60 .subtract(origin) 61 .add(this.x, y, this.z); 62 this.maxPoint = regionWrapper.getMaximumPoint() 63 .subtract(origin) 64 .add(this.x, y, this.z); 65 66 this.location = new Location(world, this.x, y, this.z, (float) yaw, (float) pitch); 67 this.landState = new LandState(); 68 } 69 70 public void generatePlot() throws WorldEditException { 71 // TODO: Make this generation operation async 72 BridgeUtil.debug("Generating plot at " + this.location.toString() + " for " + 73 "island " + this.island.getSlot()); 74 75 final BukkitWorld bukkitWorld = new BukkitWorld(world); 76 77 try (final EditSessionWrapper editSessionWrapper = MultiWorldEditAPI.getMultiWorldEdit() 78 .create(bukkitWorld, -1)) { 79 final Clipboard schematicClipboard = getIsland().getSchematicClipboard(); 80 final EditSession editSession = editSessionWrapper.to(); 81 82 final Operation operation = MultiWorldEditAPI.getMultiWorldEdit() 83 .create(schematicClipboard, editSession, bukkitWorld) 84 .to((int) x, (int) y, (int) z) 85 .ignoreAirBlocks(true) 86 .build(); 87 88 Operations.completeLegacy(operation); 89 } catch (IOException e) { 90 throw new IllegalStateException(e); 91 } 92 } 93 94 public void reserveWith(final GameIsland gameIsland) { 95 this.landState.reserveWith(gameIsland); 96 } 97 98 public World getWorld() { 99 return world;100 }101102 public double getX() {103 return x;104 }105106 public double getY() {107 return y;108 }109110 public double getZ() {111 return z;112 }113114 public Location getIslandLocation() {115 final Location absoluteLocation = island.getAbsoluteLocation();116117 // if the absolute location were not defined, return the island plot location118 if (absoluteLocation == null) {119 return location;120 }121122 // otherwise, add plot's location to the absolute location123 final Location islandLocation = getPlotLocation().subtract(absoluteLocation);124 islandLocation.setYaw(absoluteLocation.getYaw());125 islandLocation.setPitch(absoluteLocation.getPitch());126127 return islandLocation;128 }129130 public Location getPlotLocation() {131 return this.location.clone();132 }133134 public CuboidRegion region() {135 return new CuboidRegion(minPoint, maxPoint);136 }137138 public Island getIsland() {139 return island;140 }141142 public GameIsland getGameIsland() {143 return landState.getGame();144 }145146 public void free() {147 landState.free();148 }149150 public boolean isFree() {151 return landState.isFree();152 }153154 public int getWidth() {155 return getIsland().getSchematicClipboard().getRegion().getWidth();156 }157158 @Override159 public String toString() {160 final StringBuilder sb = new StringBuilder("IslandLand{");161 sb.append("island=")162 .append(island);163 sb.append(", world=")164 .append(world);165 sb.append(", x=")166 .append(x);167 sb.append(", y=")168 .append(y);169 sb.append(", z=")170 .append(z);171 sb.append(", yaw=")172 .append(yaw);173 sb.append(", pitch=")174 .append(pitch);175 sb.append(", location=")176 .append(location);177 sb.append(", minPoint=")178 .append(minPoint);179 sb.append(", maxPoint=")180 .append(maxPoint);181 sb.append(", landState=")182 .append(landState);183 sb.append('}');184 return sb.toString();185 }186187 @Override188 public boolean equals(final Object o) {189 if (this == o) {190 return true;191 }192193 if (!(o instanceof IslandLand)) {194 return false;195 }196197 final IslandLand that = (IslandLand) o;198199 return new EqualsBuilder().append(getIsland(), that.getIsland())200 .isEquals();201 }202203 @Override204 public int hashCode() {205 return new HashCodeBuilder(17, 37).append(getIsland())206 .toHashCode();207 }208209 public double[] getPositions() {210 return this.positions;211 }212213 private static class LandState {214 private GameIsland gameIsland;215216 public void reserveWith(final GameIsland gameIsland) {217 this.gameIsland = gameIsland;218 }219220 public void free() {221 gameIsland = null;222 }223224 public boolean isFree() {225 return gameIsland == null;226 }227228 public GameIsland getGame() {229 return gameIsland;230 }231232 @Override233 public String toString() {234 final StringBuilder sb = new StringBuilder("LandState{");235 sb.append("gameIsland=")236 .append(gameIsland);237 sb.append('}');238 return sb.toString();239 }240241 @Override242 public boolean equals(final Object o) {243 if (this == o) {244 return true;245 }246247 if (!(o instanceof LandState)) {248 return false;249 }250251 final LandState landState = (LandState) o;252253 return new EqualsBuilder().append(gameIsland, landState.gameIsland)254 .isEquals();255 }256257 @Override258 public int hashCode() {259 return new HashCodeBuilder(17, 37).append(gameIsland)260 .toHashCode();261 }262 }263}
16import org.bukkit.entity.Player;
17import org.bukkit.inventory.ItemStack;
18
19public class GameIsland { 20 private final ArenaManager arenaManager; 21 private final Umbrella umbrella; 22 private final Island island; 23 private final GamePlayer gamePlayer; 24 25 private IslandLand islandLand; 26 27 public GameIsland(final ArenaManager arenaManager, final Island island, 28 final GamePlayer gamePlayer) { 29 this.arenaManager = arenaManager; 30 // todo: memory leak, as this does not get invalidated once done 31 this.umbrella = new GameIslandUmbrella(this).getUmbrella(); 32 this.island = island; 33 this.gamePlayer = gamePlayer; 34 } 35 36 public void start() { 37 // setting the player's queue to true 38 this.gamePlayer.startQueue(); 39 40 // binding the game player instance to bridge player 41 this.gamePlayer.getBridgePlayer().setGamePlayer(gamePlayer); 42 43 // reverse an island plot for this game 44 this.islandLand = arenaManager.reservePlot(this); 45 46 // execute the on join method on game island 47 onJoin(); 48 49 // reset the player's queue 50 this.gamePlayer.resetQueue(); 51 } 52 53 public void onJoin() { 54 final Player player = gamePlayer.getBridgePlayer().getPlayer(); 55 56 // setting the player island slot 57 gamePlayer.setCurrentGame(this); 58 // teleport the player to the island plot 59 gamePlayer.teleport(islandLand); 60 61 // clears the player's inventory 62 player.getInventory().clear(); 63 64 // active the game umbrella 65 umbrella.activate(player); 66 67 // add the block 68 player.getInventory() 69 .setItem(0, new ItemStack(gamePlayer.getBridgePlayer() 70 .getChoseMaterial(), 64)); 71 72 player.setHealth(player.getMaxHealth()); 73 player.setFoodLevel(20); 74 75 player.setGameMode(GameMode.SURVIVAL); 76 } 77 78 public void resetGame(final boolean notify) { 79 gamePlayer.resetBlocks(); 80 gamePlayer.resetTimer(); 81 gamePlayer.teleport(islandLand); 82 83 gamePlayer.getBridgePlayer().increment(PlayerStatType.TOTAL_TRIES); 84 85 final Player player = gamePlayer.getBridgePlayer().getPlayer(); 86 87 player.getInventory().setItem(0, 88 new ItemStack(gamePlayer.getBridgePlayer() 89 .getChoseMaterial(), 90 64)); 91 92 if (notify) { 93 BridgeUtil.sendMessage(player, Message.INSTANCE.islandReset); 94 } 95 } 96 97 public void resetGame() { 98 resetGame(true); 99 }100101 public void remove() {102 final Player player = gamePlayer.getBridgePlayer()103 .getPlayer();104105 if (player != null) {106 player.getInventory()107 .clear();108109 final LobbyCategory lobbyCategory = ConfigurationManager.INSTANCE.getLobbyCategory();110111 umbrella.inactivate(player);112113 // teleport the player to the lobby location114 final Location location = lobbyCategory.getLobbyLocation();115 if (location != null) {116 player.teleport(location);117 }118 }119120 // remove the blocks121 gamePlayer.resetBlocks();122123 // free the plot124 getIslandPlot().free();125126 // set the player's game to null, as they're leaving the island127 gamePlayer.setCurrentGame(null);128 }129130 public CuboidRegion region() {131 final IslandLand islandLand = getIslandPlot();132 if (islandLand == null) {133 return null;134 }135 return islandLand.region();136 }137138 public Island getIsland() {139 return island;140 }141142 public GamePlayer getGamePlayer() {143 return gamePlayer;144 }145146 public IslandLand getIslandPlot() {147 return islandLand;148 }149150 public void stopGame() {151 getIsland().leaveGame(getGamePlayer().getBridgePlayer());152 }153}
22import java.util.*;
23import java.util.concurrent.atomic.AtomicInteger;
24
25public final class ArenaManager { 26 private final @NotNull Map<Integer, Collection<IslandLand>> ISLAND_PLOTS = 27 new HashMap<>(); 28 private final AtomicInteger COUNTER = new AtomicInteger(100); 29 30 private File worldDirectory; 31 private World world; 32 33 public void load() { 34 this.world = Bukkit.createWorld(WorldCreator.name("speedbridge2") 35 .generator(new EmptyChunkGenerator())); 36 this.worldDirectory = new File( "speedbridge2"); 37 38 protectWorld(world); 39 } 40 41 private void protectWorld(final @NotNull World world) { 42 world.setFullTime(1000); 43 world.setWeatherDuration(0); 44 world.setStorm(false); 45 world.setThundering(false); 46 world.setPVP(false); 47 world.setAutoSave(false); 48 world.setMonsterSpawnLimit(0); 49 50 world.setGameRuleValue("doDaylightCycle", "false"); 51 } 52 53 public @NotNull IslandLand justReservePlot(final GameIsland gameIsland) { 54 return justGetPlot(gameIsland.getIsland(), gameIsland); 55 } 56 57 public @Nullable IslandLand reservePlot(final GameIsland gameIsland) { 58 if (world == null) { 59 Bukkit.getLogger() 60 .severe("The SpeedBridge2 world cannot be found! cancelled player's request to reserve a plot."); 61 return null; 62 } 63 64 final Island island = gameIsland.getIsland(); 65 66 // return the available plot 67 return getPlot(island, gameIsland); 68 } 69 70 private IslandLand justGetPlot(final Island island, final GameIsland gameIsland) { 71 final int islandSlot = island.getSlot(); 72 73 // retrieving a collection of plots that is associated with the given island slot 74 final Collection<IslandLand> islandLands = retrieve(islandSlot); 75 76 // attempt to get an available plot with the given island slot 77 IslandLand islandLand = getAvailablePlot(islandLands, islandSlot); 78 79 // if we found an available plot, start reserving the plot 80 if (islandLand != null) { 81 islandLand.reserveWith(gameIsland); 82 } else { 83 // otherwise, create our own island plot 84 islandLand = createIslandPlotWithNoGeneration(islandLands, island, gameIsland); 85 } 86 return islandLand; 87 } 88 89 private IslandLand getPlot(final Island island, final GameIsland gameIsland) { 90 final int islandSlot = island.getSlot(); 91 92 // retrieving a collection of plots that is associated with the given island slot 93 final Collection<IslandLand> islandLands = retrieve(islandSlot); 94 95 // attempt to get an available plot with the given island slot 96 IslandLand islandLand = getAvailablePlot(islandLands, islandSlot); 97 98 // if we found an available plot, start reserving the plot 99 if (islandLand != null) {100 islandLand.reserveWith(gameIsland);101 } else {102 // otherwise, create our own island plot103 islandLand = createIslandPlot(islandLands, island, gameIsland);104 }105 return islandLand;106 }107108 private IslandLand getAvailablePlot(final Collection<IslandLand> islandLands,109 final int slot) {110 for (final IslandLand islandLand : islandLands) {111 // if it's not the same island plot, or the plot is not free; continue112 if (islandLand.getIsland().getSlot() != slot || !islandLand.isFree()) {113 continue;114 }115116 BridgeUtil.debug("SchematicManager#getAvailablePlot: Found a free plot for " + slot + " slot!");117 return islandLand;118 }119 return null;120 }121122// private IslandLand getNewPlot(final Island target) {123// return getNewPlot(target, getPositions());124// }125126 private IslandLand getNewPlot(final Island target, double[] positions) {127 return new IslandLand(target, world, positions);128 }129130 private IslandLand createIslandPlotWithNoGeneration(final Collection<IslandLand> islandLandList131 , final Island target, final GameIsland gameIsland) {132 BridgeUtil.debug("SchematicManager#createIslandPlot: Creating a new island plot for " + target.getSlot() + " slot!");133134 final double[] positions = getPositions();135136 positions[0] += Math.abs(positions[0] - new IslandLand(target, world, positions).region().getMinimumPoint().getX());137138 BridgeUtil.debug("=== island " + target.getSlot() + " ===");139 BridgeUtil.debug("Placing schematic at: " + Arrays.toString(positions));140141 final IslandLand islandLand = getNewPlot(target, positions);142 BridgeUtil.debug("Island width is: " + islandLand.getWidth());143144 COUNTER.getAndAdd(islandLand.getWidth() + ConfigurationManager.INSTANCE.getGeneralCategory().getIslandSpaceGap());145146 BridgeUtil.debug("minimumPoint=" + serializeVector(islandLand.region().getMinimumPoint()));147 BridgeUtil.debug("maximumPoint=" + serializeVector(islandLand.region().getMaximumPoint()));148 BridgeUtil.debug("==========");149150 // reserving the plot to player151 islandLand.reserveWith(gameIsland);152153 // adding the plot for usability154 islandLandList.add(islandLand);155156 // adding the new island plot to the schematic plot map157 ISLAND_PLOTS.put(target.getSlot(), islandLandList);158 return islandLand;159 }160161 private IslandLand createIslandPlot(final Collection<IslandLand> islandLandList162 , final Island target, final GameIsland gameIsland) {163 BridgeUtil.debug("SchematicManager#createIslandPlot: Creating a new island plot for " + target.getSlot() + " slot!");164165 final double[] positions = getPositions();166167 positions[0] += Math.abs(positions[0] - new IslandLand(target, world, positions).region().getMinimumPoint().getX());168169 BridgeUtil.debug("=== island " + target.getSlot() + " ===");170 BridgeUtil.debug("Placing schematic at: " + Arrays.toString(positions));171172 final IslandLand islandLand = getNewPlot(target, positions);173 BridgeUtil.debug("Island width is: " + islandLand.getWidth());174175 COUNTER.getAndAdd(islandLand.getWidth() + ConfigurationManager.INSTANCE.getGeneralCategory().getIslandSpaceGap());176177 BridgeUtil.debug("minimumPoint=" + serializeVector(islandLand.region().getMinimumPoint()));178 BridgeUtil.debug("maximumPoint=" + serializeVector(islandLand.region().getMaximumPoint()));179 BridgeUtil.debug("==========");180181 // reserving the plot to player182 islandLand.reserveWith(gameIsland);183 try {184 // attempt to generate the plot185 islandLand.generatePlot();186 } catch (WorldEditException e) {187 throw new IllegalStateException(e);188 }189190 // adding the plot for usability191 islandLandList.add(islandLand);192193 // adding the new island plot to the schematic plot map194 ISLAND_PLOTS.put(target.getSlot(), islandLandList);195 return islandLand;196 }197198 public double[] getPositions() {199 return new double[]{COUNTER.get(), 100, 100};200 }201202 @NotNull203 private static String serializeVector(Vector vector) {204 return String.format("%s, %s, %s", vector.getX(), vector.getY(), vector.getZ());205 }206207 public void resetWorld() {208 final File worldFile = getWorldDirectory();209 if (worldFile != null && worldFile.exists()) {210 try {211 // delete the world outright212 FileUtils.forceDelete(worldFile);213 } catch (IOException e) {214 throw new IllegalStateException(e);215 }216 }217 }218219 public Collection<IslandLand> retrieve(final int slot) {220 return ISLAND_PLOTS.getOrDefault(slot, new ArrayList<>());221 }222223 public void clearPlot(final int slot) {224 ISLAND_PLOTS.remove(slot);225 }226227 public File getWorldDirectory() {228 return worldDirectory;229 }230231 public void unloadWorld() {232 if (world == null) {233 return;234 }235236 movePlayersFromWorld();237238 Bukkit.unloadWorld(world, false);239 }240241 private void movePlayersFromWorld() {242 for (final Player player : Bukkit.getOnlinePlayers()) {243 if (!player.getWorld()244 .getName()245 .equals(world.getName())) {246 continue;247 }248 Location lobbyLocation = ConfigurationManager.INSTANCE.getLobbyCategory()249 .getLobbyLocation();250251 if (lobbyLocation == null) {252 lobbyLocation = Bukkit.getServer().getWorlds().get(0).getSpawnLocation();253 }254255 player.teleport(lobbyLocation);256 }257 }258259 public World getWorld() {260 return this.world;261 }262263264265 private static final class EmptyChunkGenerator extends ChunkGenerator {266 @Override267 public @NotNull ChunkData generateChunkData(final World world, final Random random, final int x, final int z, final BiomeGrid biome) {268 return createChunkData(world);269 }270 }271}
13import java.lang.reflect.Type;
14import java.util.Arrays;
15
16public final class LocationSerializer implements TypeSerializer<Location> { 17 public static final LocationSerializer INSTANCE = new LocationSerializer(); 18 19 private LocationSerializer() {} 20 21 @Override 22 public Location deserialize(final Type type, final ConfigurationNode node) throws SerializationException { 23 final String worldName = nonVirtualNode(node, "world").getString(); 24 25 // if the world name is nonexistent, return the default 26 // location 27 if (worldName == null) { 28 return defaultLocation(); 29 } 30 31 final World world = getWorld(worldName); 32 33 34 // if the world was not loaded before, or it was deleted 35 // then we will create/load it manually 36// if (world == null) { 37// world = Bukkit.createWorld(WorldCreator.name(worldName)); 38// } 39 40 final double x = nonVirtualNode(node, "x").getDouble(); 41 final double y = nonVirtualNode(node, "y").getDouble(); 42 final double z = nonVirtualNode(node, "z").getDouble(); 43 final float yaw = nonVirtualNode(node, "yaw").getFloat(); 44 final float pitch = nonVirtualNode(node, "pitch").getFloat(); 45 46 return new Location(world, x, y, z, yaw, pitch); 47 } 48 49 private World getWorld(final String worldName) { 50 // attempts to get a world that are already loaded 51 World world = Bukkit.getWorld(worldName); 52 if (world != null) { 53 return world; 54 } 55 56 // loads/creates a world with the given worldName 57 // and notifies the administrators of the given action 58 BridgeUtil.log("Loading " + worldName + " world for the speedbridge2 lobby!"); 59 return Bukkit.createWorld(WorldCreator.name(worldName)); 60 } 61 62 private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path) throws SerializationException { 63 if (!source.hasChild(path)) { 64 throw new SerializationException("Required field " + Arrays.toString(path) + 65 " was not present in node"); 66 } 67 return source.node(path); 68 } 69 70 private Location defaultLocation() { 71 final World world; 72 try { 73 world = Bukkit.getWorlds() 74 .get(0); 75 return world.getSpawnLocation(); 76 } catch (final NullPointerException ignored) { 77 // do nothing 78 } 79 return null; 80 } 81 82 @Override 83 public void serialize(final Type type, @Nullable Location obj, final ConfigurationNode node) throws SerializationException { 84 if (obj == null && (obj = defaultLocation()) == null) { 85 node.raw(null); 86 return; 87 } 88 node.node("world") 89 .set(obj.getWorld() 90 .getName()); 91 node.node("x") 92 .set(obj.getX()); 93 node.node("y") 94 .set(obj.getY()); 95 node.node("z") 96 .set(obj.getZ()); 97 node.node("yaw") 98 .set(obj.getYaw()); 99 node.node("pitch")100 .set(obj.getPitch());101 }102}
17
18import java.util.*;
19
20@Command("speedbridge debug")21@CommandPermission("speedbridge.debug")22public class SpeedBridgeDebugCommand {23 private final Map<Island, List<GameIsland>> generatedGames = new HashMap<>();24 private final ArenaManager arenaManager;2526 public SpeedBridgeDebugCommand(ArenaManager arenaManager) {27 this.arenaManager = arenaManager;28 }2930 @Subcommand("arena teleport")31 public String islandTeleport(final Player player) {32 double[] positions = arenaManager.getPositions();33 player.teleport(new Location(this.arenaManager.getWorld(), positions[0], positions[1], positions[2]));34 return String.format("Teleported you to world %s with %s coordinates", arenaManager.getWorld().getName(), positions);35 }3637 @Subcommand("island generate")38 @Usage("island generate <island> [amount]")39 public String generateGame(final Island island, final @Default("1") int amount) {40 for (int i = 0; i < amount; i++) {41 generateGame(island);42 }43 return String.format("Generated %s games of island type %s", amount, island.getSlot());44 }4546 @Subcommand("island destroy")47 @Usage("island destroy")48 public String islandClear(final Island island) {49 int gameAmountDestroyed = destroyGames(island);50 int islandType = island.getSlot();51 return String.format("Destroyed %s games of island type %s!", gameAmountDestroyed, islandType);52 }5354 private int destroyGames(final Island island) {55 List<GameIsland> games = this.generatedGames.get(island);56 games.forEach(game -> {57 DestroyableLand islandPlot = (DestroyableLand) game.getIslandPlot();58 islandPlot.destroy();59 });60 return games.size();61 }6263 public void generateGame(final Island island) {64 final GamePlayer gamePlayer = GamePlayer.of(new EmptyBridgePlayer(UUID.randomUUID()));65 final GameIsland2 gameIsland = new GameIsland2(arenaManager, IslandFactory.createGame(island, gamePlayer));6667 DestroyableLand islandLand = new DestroyableLand(arenaManager.justReservePlot(gameIsland));68 try {69 islandLand.generatePlot();70 } catch (WorldEditException e) {71 throw new RuntimeException(e);72 }7374 gameIsland.setIslandPlot(islandLand);7576 this.generatedGames.compute(island, (island1, gameIslands) -> {77 if (gameIslands == null) {78 gameIslands = new ArrayList<>();79 }80 gameIslands.add(gameIsland);81 return gameIslands;82 });83 }84}
This class does not have any documentation.
Consider adding a documentation comment to explain its use.
While it may seem like the functionality of a class is perfectly obvious, any consumers of your API may not be able to pick up on certain details.
Consider a case where the class given below can be instantiated and provides certain functionalities within each instance in a thread-safe manner, perhaps it is a rest API client.
If there is no documentation comment on the class, it is not immediately obvious that the class is thread safe. Thus, multiple instances of the class may be created to perform operations concurrently, using up both memory as well as OS resources like sockets. If it were known from the beginning that the class were thread safe, the user would not need to create unnecessary extra instances of SomeClass
.
class SomeClass {
// ...
}
Make sure to add useful information regarding the usage or implementation of a particular declaration, so that anything about it which can't be understood from the name or some other cue is correctly conveyed.
/**
* Instances of this class are used to perform xyz action.
*
* This class is thread safe and the same instance can be used over multiple threads.
*/
class SomeClass {
// ...
}
This issue will not be reported for model entity classes. If there is any non-obvious behavior associated with a particular class however, do consider documenting it.