mirror of
https://hub.spigotmc.org/stash/scm/spigot/bukkit.git
synced 2025-08-21 05:44:17 +00:00
Merge branch 'master' of https://hub.spigotmc.org/stash/scm/~derfrzocker/bukkit into enums-to-registers
Conflicts: src/main/java/org/bukkit/Bukkit.java src/main/java/org/bukkit/Server.java
This commit is contained in:
commit
4771132c0e
18 changed files with 681 additions and 53 deletions
|
@ -46,6 +46,7 @@ import org.bukkit.plugin.ServicesManager;
|
|||
import org.bukkit.plugin.messaging.Messenger;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.scoreboard.ScoreboardManager;
|
||||
import org.bukkit.structure.StructureManager;
|
||||
import org.bukkit.util.CachedServerIcon;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
@ -451,6 +452,27 @@ public final class Bukkit {
|
|||
public static int getTicksPerWaterAmbientSpawns() {
|
||||
return server.getTicksPerAmbientSpawns();
|
||||
}
|
||||
/**
|
||||
* Gets the default ticks per water underground creature spawns value.
|
||||
* <p>
|
||||
* <b>Example Usage:</b>
|
||||
* <ul>
|
||||
* <li>A value of 1 will mean the server will attempt to spawn water underground creature
|
||||
* every tick.
|
||||
* <li>A value of 400 will mean the server will attempt to spawn water underground creature
|
||||
* every 400th tick.
|
||||
* <li>A value below 0 will be reset back to Minecraft's default.
|
||||
* </ul>
|
||||
* <p>
|
||||
* <b>Note:</b> If set to 0, water underground creature spawning will be disabled.
|
||||
* <p>
|
||||
* Minecraft default: 1.
|
||||
*
|
||||
* @return the default ticks per water underground creature spawn value
|
||||
*/
|
||||
public static int getTicksPerWaterUndergroundCreatureSpawns() {
|
||||
return server.getTicksPerWaterUndergroundCreatureSpawns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a player object by the given username.
|
||||
|
@ -1234,6 +1256,15 @@ public final class Bukkit {
|
|||
return server.getAmbientSpawnLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user-specified limit for number of water creature underground that can spawn
|
||||
* in a chunk.
|
||||
* @return the water underground creature limit
|
||||
*/
|
||||
public static int getWaterUndergroundCreatureSpawnLimit() {
|
||||
return server.getWaterUndergroundCreatureSpawnLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user-specified limit for number of ambient mobs that can spawn in
|
||||
* a chunk.
|
||||
|
@ -1653,6 +1684,16 @@ public final class Bukkit {
|
|||
return server.selectEntities(sender, selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the structure manager for loading and saving structures.
|
||||
*
|
||||
* @return the structure manager
|
||||
*/
|
||||
@NotNull
|
||||
public static StructureManager getStructureManager() {
|
||||
return server.getStructureManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registry for the given class.
|
||||
* <br>
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.bukkit.plugin.messaging.Messenger;
|
|||
import org.bukkit.plugin.messaging.PluginMessageRecipient;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.scoreboard.ScoreboardManager;
|
||||
import org.bukkit.structure.StructureManager;
|
||||
import org.bukkit.util.CachedServerIcon;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
@ -361,6 +362,26 @@ public interface Server extends PluginMessageRecipient {
|
|||
*/
|
||||
public int getTicksPerWaterAmbientSpawns();
|
||||
|
||||
/**
|
||||
* Gets the default ticks per water underground creature spawns value.
|
||||
* <p>
|
||||
* <b>Example Usage:</b>
|
||||
* <ul>
|
||||
* <li>A value of 1 will mean the server will attempt to spawn water underground creature
|
||||
* every tick.
|
||||
* <li>A value of 400 will mean the server will attempt to spawn water underground creature
|
||||
* every 400th tick.
|
||||
* <li>A value below 0 will be reset back to Minecraft's default.
|
||||
* </ul>
|
||||
* <p>
|
||||
* <b>Note:</b> If set to 0, water underground creature spawning will be disabled.
|
||||
* <p>
|
||||
* Minecraft default: 1.
|
||||
*
|
||||
* @return the default ticks per water underground creature spawn value
|
||||
*/
|
||||
public int getTicksPerWaterUndergroundCreatureSpawns();
|
||||
|
||||
/**
|
||||
* Gets the default ticks per ambient mob spawns value.
|
||||
* <p>
|
||||
|
@ -1035,6 +1056,13 @@ public interface Server extends PluginMessageRecipient {
|
|||
*/
|
||||
int getWaterAmbientSpawnLimit();
|
||||
|
||||
/**
|
||||
* Get user-specified limit for number of water creature underground that can spawn
|
||||
* in a chunk.
|
||||
* @return the water underground creature limit
|
||||
*/
|
||||
int getWaterUndergroundCreatureSpawnLimit();
|
||||
|
||||
/**
|
||||
* Gets user-specified limit for number of ambient mobs that can spawn in
|
||||
* a chunk.
|
||||
|
@ -1399,6 +1427,14 @@ public interface Server extends PluginMessageRecipient {
|
|||
@NotNull
|
||||
List<Entity> selectEntities(@NotNull CommandSender sender, @NotNull String selector) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Gets the structure manager for loading and saving structures.
|
||||
*
|
||||
* @return the structure manager
|
||||
*/
|
||||
@NotNull
|
||||
StructureManager getStructureManager();
|
||||
|
||||
/**
|
||||
* Returns the registry for the given class.
|
||||
* <br>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.bukkit;
|
||||
|
||||
import java.util.Set;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
|
@ -585,6 +586,50 @@ public interface Tag<T extends Keyed> extends Keyed {
|
|||
* Vanilla fluid tag representing water and flowing water.
|
||||
*/
|
||||
Tag<Fluid> FLUIDS_WATER = Bukkit.getTag(REGISTRY_FLUIDS, NamespacedKey.minecraft("water"), Fluid.class);
|
||||
/**
|
||||
* Key for the built in entity registry.
|
||||
*/
|
||||
String REGISTRY_ENTITY_TYPES = "entity_types";
|
||||
/**
|
||||
* Vanilla tag representing skeletons.
|
||||
*/
|
||||
Tag<EntityType> ENTITY_TYPES_SKELETONS = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("skeletons"), EntityType.class);
|
||||
/**
|
||||
* Vanilla tag representing raiders.
|
||||
*/
|
||||
Tag<EntityType> ENTITY_TYPES_RAIDERS = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("raiders"), EntityType.class);
|
||||
/**
|
||||
* Vanilla tag representing entities which can live in beehives.
|
||||
*/
|
||||
Tag<EntityType> ENTITY_TYPES_BEEHIVE_INHABITORS = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("beehive_inhabitors"), EntityType.class);
|
||||
/**
|
||||
* Vanilla tag representing arrows.
|
||||
*/
|
||||
Tag<EntityType> ENTITY_TYPES_ARROWS = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("arrows"), EntityType.class);
|
||||
/**
|
||||
* Vanilla tag representing projectiles.
|
||||
*/
|
||||
Tag<EntityType> ENTITY_TYPES_IMPACT_PROJECTILES = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("impact_projectiles"), EntityType.class);
|
||||
/**
|
||||
* Vanilla tag representing mobs which can walk on powder snow.
|
||||
*/
|
||||
Tag<EntityType> ENTITY_TYPES_POWDER_SNOW_WALKABLE_MOBS = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("powder_snow_walkable_mobs"), EntityType.class);
|
||||
/**
|
||||
* Vanilla tag representing which entities axolotls are always hostile to.
|
||||
*/
|
||||
Tag<EntityType> ENTITY_TYPES_AXOLOTL_ALWAYS_HOSTILES = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("axolotl_always_hostiles"), EntityType.class);
|
||||
/**
|
||||
* Vanilla tag representing axolotl targets.
|
||||
*/
|
||||
Tag<EntityType> ENTITY_TYPES_AXOLOTL_HUNT_TARGETS = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("axolotl_hunt_targets"), EntityType.class);
|
||||
/**
|
||||
* Vanilla tag representing entities immune from freezing.
|
||||
*/
|
||||
Tag<EntityType> ENTITY_TYPES_FREEZE_IMMUNE_ENTITY_TYPES = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("freeze_immune_entity_types"), EntityType.class);
|
||||
/**
|
||||
* Vanilla tag representing entities extra susceptible to freezing.
|
||||
*/
|
||||
Tag<EntityType> ENTITY_TYPES_FREEZE_HURTS_EXTRA_TYPES = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("freeze_hurts_extra_types"), EntityType.class);
|
||||
|
||||
/**
|
||||
* Returns whether or not this tag has an entry for the specified item.
|
||||
|
|
|
@ -1805,6 +1805,51 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
|||
*/
|
||||
public void setTicksPerWaterAmbientSpawns(int ticksPerAmbientSpawns);
|
||||
|
||||
/**
|
||||
* Gets the default ticks per water underground creature spawns value.
|
||||
* <p>
|
||||
* <b>Example Usage:</b>
|
||||
* <ul>
|
||||
* <li>A value of 1 will mean the server will attempt to spawn water underground creature
|
||||
* every tick.
|
||||
* <li>A value of 400 will mean the server will attempt to spawn water underground creature
|
||||
* every 400th tick.
|
||||
* <li>A value below 0 will be reset back to Minecraft's default.
|
||||
* </ul>
|
||||
* <p>
|
||||
* <b>Note:</b> If set to 0, water underground creature spawning will be disabled.
|
||||
* <p>
|
||||
* Minecraft default: 1.
|
||||
*
|
||||
* @return the default ticks per water underground creature spawn value
|
||||
*/
|
||||
public long getTicksPerWaterUndergroundCreatureSpawns();
|
||||
|
||||
/**
|
||||
* Sets the world's ticks per water underground creature spawns value
|
||||
* <p>
|
||||
* This value determines how many ticks there are between attempts to
|
||||
* spawn water underground creature.
|
||||
* <p>
|
||||
* <b>Example Usage:</b>
|
||||
* <ul>
|
||||
* <li>A value of 1 will mean the server will attempt to spawn water underground creature in
|
||||
* this world on every tick.
|
||||
* <li>A value of 400 will mean the server will attempt to spawn water underground creature
|
||||
* in this world every 400th tick.
|
||||
* <li>A value below 0 will be reset back to Minecraft's default.
|
||||
* </ul>
|
||||
* <p>
|
||||
* <b>Note:</b>
|
||||
* If set to 0, water underground creature spawning will be disabled for this world.
|
||||
* <p>
|
||||
* Minecraft default: 1.
|
||||
*
|
||||
* @param ticksPerWaterUndergroundCreatureSpawns the ticks per water underground creature spawns value you
|
||||
* want to set the world to
|
||||
*/
|
||||
public void setTicksPerWaterUndergroundCreatureSpawns(int ticksPerWaterUndergroundCreatureSpawns);
|
||||
|
||||
/**
|
||||
* Gets the world's ticks per ambient mob spawns value
|
||||
* <p>
|
||||
|
@ -1911,6 +1956,25 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
|||
*/
|
||||
void setWaterAnimalSpawnLimit(int limit);
|
||||
|
||||
/**
|
||||
* Gets the limit for number of water underground creature that can spawn in a chunk in
|
||||
* this world
|
||||
*
|
||||
* @return The water underground creature spawn limit
|
||||
*/
|
||||
int getWaterUndergroundCreatureSpawnLimit();
|
||||
|
||||
/**
|
||||
* Sets the limit for number of water underground creature that can spawn in a chunk in
|
||||
* this world
|
||||
* <p>
|
||||
* <b>Note:</b> If set to a negative number the world will use the
|
||||
* server-wide spawn limit instead.
|
||||
*
|
||||
* @param limit the new mob limit
|
||||
*/
|
||||
void setWaterUndergroundCreatureSpawnLimit(int limit);
|
||||
|
||||
/**
|
||||
* Gets user-specified limit for number of water ambient mobs that can spawn
|
||||
* in a chunk.
|
||||
|
|
|
@ -122,6 +122,9 @@ public class HelpCommand extends BukkitCommand {
|
|||
List<String> matchedTopics = new ArrayList<String>();
|
||||
String searchString = args[0];
|
||||
for (HelpTopic topic : Bukkit.getServer().getHelpMap().getHelpTopics()) {
|
||||
if (!topic.canSee(sender)) {
|
||||
continue;
|
||||
}
|
||||
String trimmedTopic = topic.getName().startsWith("/") ? topic.getName().substring(1) : topic.getName();
|
||||
|
||||
if (trimmedTopic.startsWith(searchString)) {
|
||||
|
|
|
@ -377,6 +377,11 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
|
|||
*/
|
||||
public void stopSound(@NotNull String sound, @Nullable SoundCategory category);
|
||||
|
||||
/**
|
||||
* Stop all sounds from playing.
|
||||
*/
|
||||
public void stopAllSounds();
|
||||
|
||||
/**
|
||||
* Plays an effect to just this player.
|
||||
*
|
||||
|
|
|
@ -49,18 +49,25 @@ public class BlockBreakEvent extends BlockExpEvent implements Cancellable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not the block will drop items as it normally would.
|
||||
* Sets whether or not the block will attempt to drop items as it normally
|
||||
* would.
|
||||
*
|
||||
* @param dropItems Whether or not the block will drop items
|
||||
* If and only if this is false then {@link BlockDropItemEvent} will not be
|
||||
* called after this event.
|
||||
*
|
||||
* @param dropItems Whether or not the block will attempt to drop items
|
||||
*/
|
||||
public void setDropItems(boolean dropItems) {
|
||||
this.dropItems = dropItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether or not the block will drop items.
|
||||
* Gets whether or not the block will attempt to drop items.
|
||||
*
|
||||
* @return Whether or not the block will drop items
|
||||
* If and only if this is false then {@link BlockDropItemEvent} will not be
|
||||
* called after this event.
|
||||
*
|
||||
* @return Whether or not the block will attempt to drop items
|
||||
*/
|
||||
public boolean isDropItems() {
|
||||
return this.dropItems;
|
||||
|
|
|
@ -260,9 +260,10 @@ public class EntityDamageEvent extends EntityEvent implements Cancellable {
|
|||
public enum DamageCause {
|
||||
|
||||
/**
|
||||
* Damage caused when an entity contacts a block such as a Cactus.
|
||||
* Damage caused when an entity contacts a block such as a Cactus,
|
||||
* Dripstone (Stalagmite) or Berry Bush.
|
||||
* <p>
|
||||
* Damage: 1 (Cactus)
|
||||
* Damage: variable
|
||||
*/
|
||||
CONTACT,
|
||||
/**
|
||||
|
@ -351,9 +352,12 @@ public class EntityDamageEvent extends EntityEvent implements Cancellable {
|
|||
*/
|
||||
LIGHTNING,
|
||||
/**
|
||||
* Damage caused by committing suicide using the command "/kill"
|
||||
* Damage caused by committing suicide.
|
||||
* <p>
|
||||
* Damage: 1000
|
||||
* <b>Note:</b> This is currently only used by plugins, default commands
|
||||
* like /minecraft:kill use {@link #VOID} to damage players.
|
||||
* <p>
|
||||
* Damage: variable
|
||||
*/
|
||||
SUICIDE,
|
||||
/**
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package org.bukkit.event.inventory;
|
||||
|
||||
import java.util.List;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.block.BlockEvent;
|
||||
import org.bukkit.inventory.BrewerInventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
|
@ -14,18 +16,23 @@ import org.jetbrains.annotations.NotNull;
|
|||
public class BrewEvent extends BlockEvent implements Cancellable {
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private BrewerInventory contents;
|
||||
private final List<ItemStack> results;
|
||||
private int fuelLevel;
|
||||
private boolean cancelled;
|
||||
|
||||
public BrewEvent(@NotNull Block brewer, @NotNull BrewerInventory contents, int fuelLevel) {
|
||||
public BrewEvent(@NotNull Block brewer, @NotNull BrewerInventory contents, @NotNull List<ItemStack> results, int fuelLevel) {
|
||||
super(brewer);
|
||||
this.contents = contents;
|
||||
this.results = results;
|
||||
this.fuelLevel = fuelLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the contents of the Brewing Stand.
|
||||
*
|
||||
* <b>Note:</b> The brewer inventory still holds the items found prior to
|
||||
* the finalization of the brewing process, e.g. the plain water bottles.
|
||||
*
|
||||
* @return the contents
|
||||
*/
|
||||
@NotNull
|
||||
|
@ -42,6 +49,21 @@ public class BrewEvent extends BlockEvent implements Cancellable {
|
|||
return fuelLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resulting items in the Brewing Stand.
|
||||
*
|
||||
* The returned list, in case of a server-created event instance, is
|
||||
* mutable. Any changes in the returned list will reflect in the brewing
|
||||
* result if the event is not cancelled. If the size of the list is reduced,
|
||||
* remaining items will be set to air.
|
||||
*
|
||||
* @return List of {@link ItemStack} resulting for this operation
|
||||
*/
|
||||
@NotNull
|
||||
public List<ItemStack> getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
|
|
|
@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable;
|
|||
|
||||
/**
|
||||
* Called when a player is about to teleport because it is in contact with a
|
||||
* portal.
|
||||
* portal which will generate an exit portal.
|
||||
* <p>
|
||||
* For other entities see {@link org.bukkit.event.entity.EntityPortalEvent}
|
||||
*/
|
||||
|
|
|
@ -101,7 +101,12 @@ final class PluginClassLoader extends URLClassLoader {
|
|||
|
||||
Class<?> loadClass0(@NotNull String name, boolean resolve, boolean checkGlobal, boolean checkLibraries) throws ClassNotFoundException {
|
||||
try {
|
||||
return super.loadClass(name, resolve);
|
||||
Class<?> result = super.loadClass(name, resolve);
|
||||
|
||||
// SPIGOT-6749: Library classes will appear in the above, but we don't want to return them to other plugins
|
||||
if (checkGlobal || result.getClassLoader() == this) {
|
||||
return result;
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ public interface ScoreboardManager {
|
|||
* This Scoreboard is saved by the server, is affected by the /scoreboard
|
||||
* command, and is the scoreboard shown by default to players.
|
||||
*
|
||||
* @return the default sever scoreboard
|
||||
* @return the default server scoreboard
|
||||
*/
|
||||
@NotNull
|
||||
Scoreboard getMainScoreboard();
|
||||
|
|
33
src/main/java/org/bukkit/structure/Palette.java
Normal file
33
src/main/java/org/bukkit/structure/Palette.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
package org.bukkit.structure;
|
||||
|
||||
import java.util.List;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represent a variation of a structure.
|
||||
*
|
||||
* Most structures, like the ones generated with structure blocks, only have a
|
||||
* single variant.
|
||||
*/
|
||||
public interface Palette {
|
||||
|
||||
/**
|
||||
* Gets a copy of the blocks this Palette is made of.
|
||||
*
|
||||
* The {@link BlockState#getLocation() positions} of the returned block
|
||||
* states are offsets relative to the structure's position that is provided
|
||||
* once the structure is placed into the world.
|
||||
*
|
||||
* @return The blocks in this palette
|
||||
*/
|
||||
@NotNull
|
||||
List<BlockState> getBlocks();
|
||||
|
||||
/**
|
||||
* Gets the number of blocks stored in this palette.
|
||||
*
|
||||
* @return The number of blocks in this palette
|
||||
*/
|
||||
int getBlockCount();
|
||||
}
|
146
src/main/java/org/bukkit/structure/Structure.java
Normal file
146
src/main/java/org/bukkit/structure/Structure.java
Normal file
|
@ -0,0 +1,146 @@
|
|||
package org.bukkit.structure;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.RegionAccessor;
|
||||
import org.bukkit.block.structure.Mirror;
|
||||
import org.bukkit.block.structure.StructureRotation;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.util.BlockVector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a structure.
|
||||
* <p>
|
||||
* A structure is a mutable template of captured blocks and entities that can be
|
||||
* copied back into the world. The {@link StructureManager}, retrieved via
|
||||
* {@link org.bukkit.Server#getStructureManager()}, allows you to create new
|
||||
* structures, load existing structures, and save structures.
|
||||
* <p>
|
||||
* In order for a structure to be usable by structure blocks, it needs to be
|
||||
* null {@link StructureManager#registerStructure(org.bukkit.NamespacedKey, Structure)
|
||||
* registered} with the {@link StructureManager}, or located in the primary
|
||||
* world folder, a DataPack, or the server's own default resources, so that the
|
||||
* StructureManager can find it.
|
||||
*/
|
||||
public interface Structure {
|
||||
|
||||
/**
|
||||
* Gets the current size of the structure.
|
||||
* <p>
|
||||
* The size of the structure may not be fixed.
|
||||
*
|
||||
* @return A new vector that represents the size of the structure along each
|
||||
* axis.
|
||||
*/
|
||||
@NotNull
|
||||
BlockVector getSize();
|
||||
|
||||
/**
|
||||
* Gets a list of available block palettes.
|
||||
*
|
||||
* @return a list of available variants of this structure.
|
||||
*/
|
||||
@NotNull
|
||||
List<Palette> getPalettes();
|
||||
|
||||
/**
|
||||
* Gets the number of palettes in this structure.
|
||||
*
|
||||
* @return The number of palettes in this structure
|
||||
*/
|
||||
int getPaletteCount();
|
||||
|
||||
/**
|
||||
* Gets a list of entities that have been included in the Structure.
|
||||
*
|
||||
* The entity positions are offsets relative to the structure's position
|
||||
* that is provided once the structure is placed into the world.
|
||||
*
|
||||
* @return a list of Entities included in the Structure.
|
||||
*/
|
||||
@NotNull
|
||||
List<Entity> getEntities();
|
||||
|
||||
/**
|
||||
* Gets the number of entities in this structure.
|
||||
*
|
||||
* @return The number of entities in this structure
|
||||
*/
|
||||
int getEntityCount();
|
||||
|
||||
/**
|
||||
* Place a structure in the world.
|
||||
*
|
||||
* @param location The location to place the structure at.
|
||||
* @param includeEntities If the entities present in the structure should be
|
||||
* spawned.
|
||||
* @param structureRotation The rotation of the structure.
|
||||
* @param mirror The mirror settings of the structure.
|
||||
* @param palette The palette index of the structure to use, starting at
|
||||
* {@code 0}, or {@code -1} to pick a random palette.
|
||||
* @param integrity Determines how damaged the building should look by
|
||||
* randomly skipping blocks to place. This value can range from 0 to 1. With
|
||||
* 0 removing all blocks and 1 spawning the structure in pristine condition.
|
||||
* @param random The randomizer used for setting the structure's
|
||||
* {@link org.bukkit.loot.LootTable}s and integrity.
|
||||
*/
|
||||
void place(@NotNull Location location, boolean includeEntities, @NotNull StructureRotation structureRotation, @NotNull Mirror mirror, int palette, float integrity, @NotNull Random random);
|
||||
|
||||
/**
|
||||
* Place a structure in the world.
|
||||
*
|
||||
* @param regionAccessor The world to place the structure in.
|
||||
* @param location The location to place the structure at.
|
||||
* @param includeEntities If the entities present in the structure should be
|
||||
* spawned.
|
||||
* @param structureRotation The rotation of the structure.
|
||||
* @param mirror The mirror settings of the structure.
|
||||
* @param palette The palette index of the structure to use, starting at
|
||||
* {@code 0}, or {@code -1} to pick a random palette.
|
||||
* @param integrity Determines how damaged the building should look by
|
||||
* randomly skipping blocks to place. This value can range from 0 to 1. With
|
||||
* 0 removing all blocks and 1 spawning the structure in pristine condition.
|
||||
* @param random The randomizer used for setting the structure's
|
||||
* {@link org.bukkit.loot.LootTable}s and integrity.
|
||||
*/
|
||||
void place(@NotNull RegionAccessor regionAccessor, @NotNull BlockVector location, boolean includeEntities, @NotNull StructureRotation structureRotation, @NotNull Mirror mirror, int palette, float integrity, @NotNull Random random);
|
||||
|
||||
/**
|
||||
* Fills the structure from an area in a world. The origin and size will be
|
||||
* calculated automatically from the two corners provided.
|
||||
* <p>
|
||||
* Be careful as this will override the current data of the structure.
|
||||
* <p>
|
||||
* Be aware that this method allows for creating structures larger than the
|
||||
* 48x48x48 size that Minecraft's Structure blocks support. Any structures
|
||||
* saved this way can not be loaded by using a structure block. Using the
|
||||
* API however will still work.
|
||||
*
|
||||
* @param corner1 A corner of the structure.
|
||||
* @param corner2 The corner opposite from corner1.
|
||||
* @param includeEntities true if entities should be included in the saved
|
||||
* structure.
|
||||
*/
|
||||
void fill(@NotNull Location corner1, @NotNull Location corner2, boolean includeEntities);
|
||||
|
||||
/**
|
||||
* Fills the Structure from an area in a world, starting at the specified
|
||||
* origin and extending in each axis according to the specified size vector.
|
||||
* <p>
|
||||
* Be careful as this will override the current data of the structure.
|
||||
* <p>
|
||||
* Be aware that this method allows for saving structures larger than the
|
||||
* 48x48x48 size that Minecraft's Structure blocks support. Any structures
|
||||
* saved this way can not be loaded by using a structure block. Using the
|
||||
* API however will still work.
|
||||
*
|
||||
* @param origin The origin of the structure.
|
||||
* @param size The size of the structure, must be at least 1x1x1.
|
||||
* @param includeEntities true if entities should be included in the saved
|
||||
* structure.
|
||||
* @throws IllegalArgumentException Thrown if size is smaller than 1x1x1
|
||||
*/
|
||||
void fill(@NotNull Location origin, @NotNull BlockVector size, boolean includeEntities);
|
||||
}
|
205
src/main/java/org/bukkit/structure/StructureManager.java
Normal file
205
src/main/java/org/bukkit/structure/StructureManager.java
Normal file
|
@ -0,0 +1,205 @@
|
|||
package org.bukkit.structure;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface StructureManager {
|
||||
|
||||
/**
|
||||
* Gets the currently registered structures.
|
||||
* <p>
|
||||
* These are the currently loaded structures that the StructureManager is
|
||||
* aware of. When a structure block refers to a structure, these structures
|
||||
* are checked first. If the specified structure is not found among the
|
||||
* currently registered structures, the StructureManager may dynamically
|
||||
* read the structure from the primary world folder, DataPacks, or the
|
||||
* server's own resources. Structures can be registered via {@link
|
||||
* #registerStructure(NamespacedKey, Structure)}
|
||||
*
|
||||
* @return an unmodifiable shallow copy of the currently registered
|
||||
* structures
|
||||
*/
|
||||
@NotNull
|
||||
Map<NamespacedKey, Structure> getStructures();
|
||||
|
||||
/**
|
||||
* Gets a registered Structure.
|
||||
*
|
||||
* @param structureKey The key for which to get the structure
|
||||
* @return The structure that belongs to the structureKey or
|
||||
* <code>null</code> if there is none registered for that key.
|
||||
*/
|
||||
@Nullable
|
||||
Structure getStructure(@NotNull NamespacedKey structureKey);
|
||||
|
||||
/**
|
||||
* Registers the given structure. See {@link #getStructures()}.
|
||||
*
|
||||
* @param structureKey The key for which to register the structure
|
||||
* @param structure The structure to register
|
||||
* @return The structure for the specified key, or <code>null</code> if the
|
||||
* structure could not be found.
|
||||
*/
|
||||
@Nullable
|
||||
Structure registerStructure(@NotNull NamespacedKey structureKey, @NotNull Structure structure);
|
||||
|
||||
/**
|
||||
* Unregisters a structure. Unregisters the specified structure. If the
|
||||
* structure still exists in the primary world folder, a DataPack, or is
|
||||
* part of the server's own resources, it may be loaded and registered again
|
||||
* when it is requested by a plugin or the server itself.
|
||||
*
|
||||
* @param structureKey The key for which to save the structure for
|
||||
* @return The structure that was registered for that key or
|
||||
* <code>null</code> if there was none
|
||||
*/
|
||||
@Nullable
|
||||
Structure unregisterStructure(@NotNull NamespacedKey structureKey);
|
||||
|
||||
/**
|
||||
* Loads a structure for the specified key and optionally {@link
|
||||
* #registerStructure(NamespacedKey, Structure) registers} it.
|
||||
* <p>
|
||||
* This will first check the already loaded {@link #getStructures()
|
||||
* registered structures}, and otherwise load the structure from the primary
|
||||
* world folder, DataPacks, and the server's own resources (in this order).
|
||||
* <p>
|
||||
* When loading the structure from the primary world folder, the given key
|
||||
* is translated to a file as specified by
|
||||
* {@link #getStructureFile(NamespacedKey)}.
|
||||
*
|
||||
* @param structureKey The key for which to load the structure
|
||||
* @param register <code>true</code> to register the loaded structure.
|
||||
* @return The structure, or <code>null</code> if no structure was found for
|
||||
* the specified key
|
||||
*/
|
||||
@Nullable
|
||||
Structure loadStructure(@NotNull NamespacedKey structureKey, boolean register);
|
||||
|
||||
/**
|
||||
* Loads the structure for the specified key and automatically registers it.
|
||||
* See {@link #loadStructure(NamespacedKey, boolean)}.
|
||||
*
|
||||
* @param structureKey The key for which to load the structure
|
||||
* @return The structure for the specified key, or <code>null</code> if the
|
||||
* structure could not be found.
|
||||
*/
|
||||
@Nullable
|
||||
Structure loadStructure(@NotNull NamespacedKey structureKey);
|
||||
|
||||
/**
|
||||
* Saves the currently {@link #getStructures() registered structure} for the
|
||||
* specified {@link NamespacedKey key} to the primary world folder as
|
||||
* specified by {#getStructureFile(NamespacedKey}.
|
||||
*
|
||||
* @param structureKey The key for which to save the structure for
|
||||
*/
|
||||
void saveStructure(@NotNull NamespacedKey structureKey);
|
||||
|
||||
/**
|
||||
* Saves a structure with a given key to the primary world folder.
|
||||
*
|
||||
* @param structureKey The key for which to save the structure for
|
||||
* @param structure The structure to save for this structureKey
|
||||
*/
|
||||
void saveStructure(@NotNull NamespacedKey structureKey, @NotNull Structure structure) throws IOException;
|
||||
|
||||
/**
|
||||
* Unregisters the specified structure and deletes its {@link
|
||||
* #getStructureFile(NamespacedKey) structure file} from the primary world
|
||||
* folder. Note that this method cannot be used to delete vanilla Minecraft
|
||||
* structures, or structures from DataPacks. Unregistering these structures
|
||||
* will however work fine.
|
||||
*
|
||||
* @param structureKey The key of the structure to remove
|
||||
* @throws IOException If the file could not be removed for some reason.
|
||||
*/
|
||||
void deleteStructure(@NotNull NamespacedKey structureKey) throws IOException;
|
||||
|
||||
/**
|
||||
* Deletes the {@link #getStructureFile(NamespacedKey) structure file} for
|
||||
* the specified structure from the primary world folder. Note that this
|
||||
* method cannot be used to delete vanilla Minecraft structures, or
|
||||
* structures from DataPacks. Unregistering these structures will however
|
||||
* work fine.
|
||||
*
|
||||
* @param structureKey The key of the structure to remove
|
||||
* @param unregister Whether to also unregister the specified structure if
|
||||
* it is currently loaded.
|
||||
* @throws IOException If the file could not be removed for some reason.
|
||||
*/
|
||||
void deleteStructure(@NotNull NamespacedKey structureKey, boolean unregister) throws IOException;
|
||||
|
||||
/**
|
||||
* Gets the location where a structure file would exist in the primary world
|
||||
* directory based on the NamespacedKey using the format
|
||||
* world/generated/{NAMESPACE}/structures/{KEY}.nbt. This method will always
|
||||
* return a file, even if none exists at the moment.
|
||||
*
|
||||
* @param structureKey The key to build the filepath from.
|
||||
* @return The location where a file with this key would be.
|
||||
*/
|
||||
@NotNull
|
||||
File getStructureFile(@NotNull NamespacedKey structureKey);
|
||||
|
||||
/**
|
||||
* Reads a Structure from disk.
|
||||
*
|
||||
* @param file The file of the structure
|
||||
* @return The read structure
|
||||
* @throws IOException when the given file can not be read from
|
||||
*/
|
||||
@NotNull
|
||||
Structure loadStructure(@NotNull File file) throws IOException;
|
||||
|
||||
/**
|
||||
* Reads a Structure from a stream.
|
||||
*
|
||||
* @param inputStream The file of the structure
|
||||
* @return The read Structure
|
||||
*/
|
||||
@NotNull
|
||||
Structure loadStructure(@NotNull InputStream inputStream) throws IOException;
|
||||
|
||||
/**
|
||||
* Save a structure to a file. This will overwrite a file if it already
|
||||
* exists.
|
||||
*
|
||||
* @param file the target to save to.
|
||||
* @param structure the Structure to save.
|
||||
* @throws IOException when the given file can not be written to.
|
||||
*/
|
||||
void saveStructure(@NotNull File file, @NotNull Structure structure) throws IOException;
|
||||
|
||||
/**
|
||||
* Save a structure to a stream.
|
||||
*
|
||||
* @param outputStream the stream to write to.
|
||||
* @param structure the Structure to save.
|
||||
* @throws IOException when the given file can not be written to.
|
||||
*/
|
||||
void saveStructure(@NotNull OutputStream outputStream, @NotNull Structure structure) throws IOException;
|
||||
|
||||
/**
|
||||
* Creates a new empty structure.
|
||||
*
|
||||
* @return an empty structure.
|
||||
*/
|
||||
@NotNull
|
||||
Structure createStructure();
|
||||
|
||||
/**
|
||||
* Creates a copy of this structure.
|
||||
*
|
||||
* @param structure The structure to copy
|
||||
* @return a copy of the structure
|
||||
*/
|
||||
@NotNull
|
||||
Structure copy(@NotNull Structure structure);
|
||||
}
|
6
src/main/java/org/bukkit/structure/package-info.java
Normal file
6
src/main/java/org/bukkit/structure/package-info.java
Normal file
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* Classes related to creating or using {@link org.bukkit.structure.Structure
|
||||
* structures} without creating {@link org.bukkit.block.Structure Structure
|
||||
* blocks} in the world.
|
||||
*/
|
||||
package org.bukkit.structure;
|
|
@ -133,17 +133,12 @@ public class ChatPaginator {
|
|||
}
|
||||
|
||||
// Iterate over the wrapped lines, applying the last color from one line to the beginning of the next
|
||||
if (lines.get(0).length() == 0 || lines.get(0).charAt(0) != ChatColor.COLOR_CHAR) {
|
||||
lines.set(0, ChatColor.WHITE + lines.get(0));
|
||||
}
|
||||
for (int i = 1; i < lines.size(); i++) {
|
||||
final String pLine = lines.get(i - 1);
|
||||
final String subLine = lines.get(i);
|
||||
|
||||
char color = pLine.charAt(pLine.lastIndexOf(ChatColor.COLOR_CHAR) + 1);
|
||||
if (subLine.length() == 0 || subLine.charAt(0) != ChatColor.COLOR_CHAR) {
|
||||
lines.set(i, ChatColor.getByChar(color) + subLine);
|
||||
}
|
||||
String color = ChatColor.getLastColors(pLine);
|
||||
lines.set(i, color + subLine);
|
||||
}
|
||||
|
||||
return lines.toArray(new String[lines.size()]);
|
||||
|
|
|
@ -22,8 +22,8 @@ public class ChatPaginatorTest {
|
|||
String[] lines = ChatPaginator.wordWrap(rawString, 22);
|
||||
|
||||
assertThat(lines.length, is(2));
|
||||
assertThat(lines[0], is(ChatColor.WHITE.toString() + "123456789 123456789"));
|
||||
assertThat(lines[1], is(ChatColor.WHITE.toString() + "123456789"));
|
||||
assertThat(lines[0], is("123456789 123456789"));
|
||||
assertThat(lines[1], is("123456789"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -33,8 +33,8 @@ public class ChatPaginatorTest {
|
|||
|
||||
assertThat(lines.length, is(3));
|
||||
assertThat(lines[0], is(ChatColor.RED + "123456789"));
|
||||
assertThat(lines[1], is(ChatColor.RED.toString() + ChatColor.RED + "123456789"));
|
||||
assertThat(lines[2], is(ChatColor.RED + "123456789"));
|
||||
assertThat(lines[1], is(ChatColor.RED.toString() + ChatColor.RED + ChatColor.RED + "123456789"));
|
||||
assertThat(lines[2], is(ChatColor.RED.toString() + ChatColor.RED + "123456789"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -43,8 +43,8 @@ public class ChatPaginatorTest {
|
|||
String[] lines = ChatPaginator.wordWrap(rawString, 19);
|
||||
|
||||
assertThat(lines.length, is(2));
|
||||
assertThat(lines[0], is(ChatColor.WHITE.toString() + "123456789 123456789"));
|
||||
assertThat(lines[1], is(ChatColor.WHITE.toString() + "123456789 12345"));
|
||||
assertThat(lines[0], is("123456789 123456789"));
|
||||
assertThat(lines[1], is("123456789 12345"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -53,8 +53,8 @@ public class ChatPaginatorTest {
|
|||
String[] lines = ChatPaginator.wordWrap(rawString, 19);
|
||||
|
||||
assertThat(lines.length, is(2));
|
||||
assertThat(lines[0], is(ChatColor.WHITE.toString() + "123456789"));
|
||||
assertThat(lines[1], is(ChatColor.WHITE.toString() + "123456789 123456789"));
|
||||
assertThat(lines[0], is("123456789"));
|
||||
assertThat(lines[1], is("123456789 123456789"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -63,8 +63,8 @@ public class ChatPaginatorTest {
|
|||
String[] lines = ChatPaginator.wordWrap(rawString, 19);
|
||||
|
||||
assertThat(lines.length, is(2));
|
||||
assertThat(lines[0], is(ChatColor.WHITE.toString() + "12345678 23456789"));
|
||||
assertThat(lines[1], is(ChatColor.WHITE.toString() + "123456789"));
|
||||
assertThat(lines[0], is("12345678 23456789"));
|
||||
assertThat(lines[1], is("123456789"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -73,8 +73,8 @@ public class ChatPaginatorTest {
|
|||
String[] lines = ChatPaginator.wordWrap(rawString, 19);
|
||||
|
||||
assertThat(lines.length, is(2));
|
||||
assertThat(lines[0], is(ChatColor.WHITE.toString() + "12345678 23456789"));
|
||||
assertThat(lines[1], is(ChatColor.WHITE.toString() + "123456789"));
|
||||
assertThat(lines[0], is("12345678 23456789"));
|
||||
assertThat(lines[1], is("123456789"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -83,12 +83,12 @@ public class ChatPaginatorTest {
|
|||
String[] lines = ChatPaginator.wordWrap(rawString, 6);
|
||||
|
||||
assertThat(lines.length, is(6));
|
||||
assertThat(lines[0], is(ChatColor.WHITE.toString() + "123456"));
|
||||
assertThat(lines[1], is(ChatColor.WHITE.toString() + "789"));
|
||||
assertThat(lines[2], is(ChatColor.WHITE.toString() + "123456"));
|
||||
assertThat(lines[3], is(ChatColor.WHITE.toString() + "789"));
|
||||
assertThat(lines[4], is(ChatColor.WHITE.toString() + "123456"));
|
||||
assertThat(lines[5], is(ChatColor.WHITE.toString() + "789"));
|
||||
assertThat(lines[0], is("123456"));
|
||||
assertThat(lines[1], is("789"));
|
||||
assertThat(lines[2], is("123456"));
|
||||
assertThat(lines[3], is("789"));
|
||||
assertThat(lines[4], is("123456"));
|
||||
assertThat(lines[5], is("789"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -97,13 +97,13 @@ public class ChatPaginatorTest {
|
|||
String[] lines = ChatPaginator.wordWrap(rawString, 6);
|
||||
|
||||
assertThat(lines.length, is(7));
|
||||
assertThat(lines[0], is(ChatColor.WHITE.toString() + "1234"));
|
||||
assertThat(lines[1], is(ChatColor.WHITE.toString() + "123456"));
|
||||
assertThat(lines[2], is(ChatColor.WHITE.toString() + "789"));
|
||||
assertThat(lines[3], is(ChatColor.WHITE.toString() + "123456"));
|
||||
assertThat(lines[4], is(ChatColor.WHITE.toString() + "789"));
|
||||
assertThat(lines[5], is(ChatColor.WHITE.toString() + "123456"));
|
||||
assertThat(lines[6], is(ChatColor.WHITE.toString() + "789"));
|
||||
assertThat(lines[0], is("1234"));
|
||||
assertThat(lines[1], is("123456"));
|
||||
assertThat(lines[2], is("789"));
|
||||
assertThat(lines[3], is("123456"));
|
||||
assertThat(lines[4], is("789"));
|
||||
assertThat(lines[5], is("123456"));
|
||||
assertThat(lines[6], is("789"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -112,8 +112,8 @@ public class ChatPaginatorTest {
|
|||
String[] lines = ChatPaginator.wordWrap(rawString, 19);
|
||||
|
||||
assertThat(lines.length, is(2));
|
||||
assertThat(lines[0], is(ChatColor.WHITE.toString() + "123456789"));
|
||||
assertThat(lines[1], is(ChatColor.WHITE.toString() + "123456789"));
|
||||
assertThat(lines[0], is("123456789"));
|
||||
assertThat(lines[1], is("123456789"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -131,8 +131,19 @@ public class ChatPaginatorTest {
|
|||
String[] lines = ChatPaginator.wordWrap(rawString, 5);
|
||||
|
||||
assertThat(lines.length, is(2));
|
||||
assertThat(lines[0], is(ChatColor.WHITE.toString() + "123 1"));
|
||||
assertThat(lines[1], is(ChatColor.WHITE.toString() + "123"));
|
||||
assertThat(lines[0], is("123 1"));
|
||||
assertThat(lines[1], is("123"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWordWrap13() {
|
||||
String rawString = ChatColor.RED + "123456789 " + ChatColor.RED + ChatColor.BOLD + "123456789 " + ChatColor.RED + "123456789";
|
||||
String[] lines = ChatPaginator.wordWrap(rawString, 16);
|
||||
|
||||
assertThat(lines.length, is(3));
|
||||
assertThat(lines[0], is(ChatColor.RED + "123456789"));
|
||||
assertThat(lines[1], is(ChatColor.RED.toString() + ChatColor.RED + ChatColor.BOLD + "123456789"));
|
||||
assertThat(lines[2], is(ChatColor.RED.toString() + ChatColor.BOLD + ChatColor.RED + "123456789"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -143,8 +154,8 @@ public class ChatPaginatorTest {
|
|||
assertThat(page.getPageNumber(), is(1));
|
||||
assertThat(page.getTotalPages(), is(4));
|
||||
assertThat(page.getLines().length, is(2));
|
||||
assertThat(page.getLines()[0], is(ChatColor.WHITE.toString() + "1234"));
|
||||
assertThat(page.getLines()[1], is(ChatColor.WHITE.toString() + "123456"));
|
||||
assertThat(page.getLines()[0], is("1234"));
|
||||
assertThat(page.getLines()[1], is("123456"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -155,8 +166,8 @@ public class ChatPaginatorTest {
|
|||
assertThat(page.getPageNumber(), is(2));
|
||||
assertThat(page.getTotalPages(), is(4));
|
||||
assertThat(page.getLines().length, is(2));
|
||||
assertThat(page.getLines()[0], is(ChatColor.WHITE.toString() + "789"));
|
||||
assertThat(page.getLines()[1], is(ChatColor.WHITE.toString() + "123456"));
|
||||
assertThat(page.getLines()[0], is("789"));
|
||||
assertThat(page.getLines()[1], is("123456"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -167,6 +178,6 @@ public class ChatPaginatorTest {
|
|||
assertThat(page.getPageNumber(), is(4));
|
||||
assertThat(page.getTotalPages(), is(4));
|
||||
assertThat(page.getLines().length, is(1));
|
||||
assertThat(page.getLines()[0], is(ChatColor.WHITE.toString() + "789"));
|
||||
assertThat(page.getLines()[0], is("789"));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue