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:
DerFrZocker 2021-11-14 21:20:34 +01:00
commit 4771132c0e
No known key found for this signature in database
GPG key ID: 713F71FFFE1DDF91
18 changed files with 681 additions and 53 deletions

View file

@ -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>

View file

@ -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>

View file

@ -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.

View file

@ -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.

View file

@ -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)) {

View file

@ -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.
*

View file

@ -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;

View file

@ -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,
/**

View file

@ -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;

View file

@ -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}
*/

View file

@ -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) {
}

View file

@ -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();

View 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();
}

View 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);
}

View 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);
}

View 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;

View file

@ -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()]);

View file

@ -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"));
}
}