SPIGOT-5880, SPIGOT-5567: New ChunkGenerator API

## **Current API**
The current world generation API is very old and limited when you want to make more complex world generation. Resulting in some hard to fix bugs such as that you cannot modify blocks outside the chunk in the BlockPopulator (which should and was per the docs possible), or strange behavior such as SPIGOT-5880.

## **New API**
With the new API, the generation is more separate in multiple methods and is more in line with Vanilla chunk generation. The new API is designed to as future proof as possible. If for example a new generation step is added it can easily also be added as a step in API by simply creating the method for it. On the other side if a generation step gets removed, the method can easily be called after another, which is the case with surface and bedrock. The new API and changes are also fully backwards compatible with old chunk generators.

### **Changes in the new api**
**Extra generation steps:**
Noise, surface, bedrock and caves are added as steps. With those generation steps three extra methods for Vanilla generation are also added. Those new methods provide the ChunkData instead of returning one. The reason for this is, that the ChunkData is now backed by a ChunkAccess. With this, each step has the information of the step before and the Vanilla information (if chosen by setting a 'should' method to true). The old method is deprecated.

**New class BiomeProvider**
The BiomeProvider acts as Biome source and wrapper for the NMS class WorldChunkManager. With this the underlying Vanilla ChunkGeneration knows which Biome to use for the structure and decoration generation. (Fixes: SPIGOT-5880). Although the List of Biomes which is required in BiomeProvider, is currently not much in use in Vanilla, I decided to add it to future proof the API when it may be required in later versions of Minecraft.
The BiomeProvider is also separated from the ChunkGenerator for plugins which only want to change the biome map, such as single Biome worlds or if some biomes should be more present than others.

**Deprecated isParallelCapable**
Mojang has and is pushing to a more multi threaded chunk generation. This should also be the case for custom chunk generators. This is why the new API only supports multi threaded generation. This does not affect the old API, which is still checking this.

**Base height method added**
This method was added to also bring the Minecraft generator and Bukkit generator more in line. With this it is possible to return the max height of a location (before decorations). This is useful to let most structures know were to place them. This fixes SPIGOT-5567. (This fixes not all structures placement, desert pyramids for example are still way up at y-level 64, This however is more a vanilla bug and should be fixed at Mojangs end).

**WorldInfo Class**
The World object was swapped for a WorldInfo object. This is because many methods of the World object won't work during world generation and would mostly likely result in a deadlock. It contains any information a plugin should need to identify the world.

**BlockPopulator Changes**
Instead of directly manipulating a chunk, changes are now made to a new class LimitedRegion, this class provides methods to populated the chunk and its surrounding area. The wrapping is done so that the population can be moved into the place where Minecraft generates decorations. Where there is no chunk to access yet. By moving it into this place the generation is now async and the surrounding area of the chunk can also be used.

For common methods between the World and LimitedRegion a RegionAccessor was added.
This commit is contained in:
DerFrZocker 2021-08-15 08:08:16 +10:00 committed by md_5
parent 61e4ca7b9e
commit 4f6bcc84f9
No known key found for this signature in database
GPG Key ID: E8E901AC7C617C11
41 changed files with 2034 additions and 949 deletions

View File

@ -1,6 +1,6 @@
--- a/net/minecraft/server/MinecraftServer.java --- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java
@@ -163,6 +163,25 @@ @@ -163,6 +163,27 @@
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -16,17 +16,19 @@
+import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.dedicated.DedicatedServer;
+import net.minecraft.server.dedicated.DedicatedServerProperties; +import net.minecraft.server.dedicated.DedicatedServerProperties;
+import net.minecraft.util.datafix.DataConverterRegistry; +import net.minecraft.util.datafix.DataConverterRegistry;
+import net.minecraft.world.level.levelgen.ChunkGeneratorAbstract;
+import net.minecraft.world.level.storage.WorldDataServer; +import net.minecraft.world.level.storage.WorldDataServer;
+import org.bukkit.Bukkit; +import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.Main; +import org.bukkit.craftbukkit.Main;
+import org.bukkit.craftbukkit.generator.CustomWorldChunkManager;
+import org.bukkit.event.server.ServerLoadEvent; +import org.bukkit.event.server.ServerLoadEvent;
+// CraftBukkit end +// CraftBukkit end
+ +
public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTask> implements IMojangStatistics, ICommandListener, AutoCloseable { public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTask> implements IMojangStatistics, ICommandListener, AutoCloseable {
public static final Logger LOGGER = LogManager.getLogger(); public static final Logger LOGGER = LogManager.getLogger();
@@ -254,6 +273,20 @@ @@ -254,6 +275,20 @@
private final DefinedStructureManager structureManager; private final DefinedStructureManager structureManager;
protected SaveData worldData; protected SaveData worldData;
@ -47,7 +49,7 @@
public static <S extends MinecraftServer> S a(Function<Thread, S> function) { public static <S extends MinecraftServer> S a(Function<Thread, S> function) {
AtomicReference<S> atomicreference = new AtomicReference(); AtomicReference<S> atomicreference = new AtomicReference();
Thread thread = new Thread(() -> { Thread thread = new Thread(() -> {
@@ -263,14 +296,14 @@ @@ -263,14 +298,14 @@
thread.setUncaughtExceptionHandler((thread1, throwable) -> { thread.setUncaughtExceptionHandler((thread1, throwable) -> {
MinecraftServer.LOGGER.error(throwable); MinecraftServer.LOGGER.error(throwable);
}); });
@ -64,7 +66,7 @@
super("Server"); super("Server");
this.metricsRecorder = InactiveMetricsRecorder.INSTANCE; this.metricsRecorder = InactiveMetricsRecorder.INSTANCE;
this.profiler = this.metricsRecorder.e(); this.profiler = this.metricsRecorder.e();
@@ -282,7 +315,7 @@ @@ -282,7 +317,7 @@
this.status = new ServerPing(); this.status = new ServerPing();
this.random = new Random(); this.random = new Random();
this.port = -1; this.port = -1;
@ -73,7 +75,7 @@
this.running = true; this.running = true;
this.tickTimes = new long[100]; this.tickTimes = new long[100];
this.resourcePack = ""; this.resourcePack = "";
@@ -312,13 +345,40 @@ @@ -312,13 +347,40 @@
this.structureManager = new DefinedStructureManager(datapackresources.i(), convertable_conversionsession, datafixer); this.structureManager = new DefinedStructureManager(datapackresources.i(), convertable_conversionsession, datafixer);
this.serverThread = thread; this.serverThread = thread;
this.executor = SystemUtils.f(); this.executor = SystemUtils.f();
@ -115,7 +117,7 @@
ScoreboardServer scoreboardserver1 = this.getScoreboard(); ScoreboardServer scoreboardserver1 = this.getScoreboard();
Objects.requireNonNull(scoreboardserver1); Objects.requireNonNull(scoreboardserver1);
@@ -329,7 +389,7 @@ @@ -329,7 +391,7 @@
public static void convertWorld(Convertable.ConversionSession convertable_conversionsession) { public static void convertWorld(Convertable.ConversionSession convertable_conversionsession) {
if (convertable_conversionsession.isConvertable()) { if (convertable_conversionsession.isConvertable()) {
@ -124,7 +126,7 @@
convertable_conversionsession.convert(new IProgressUpdate() { convertable_conversionsession.convert(new IProgressUpdate() {
private long timeStamp = SystemUtils.getMonotonicMillis(); private long timeStamp = SystemUtils.getMonotonicMillis();
@@ -358,48 +418,198 @@ @@ -358,48 +420,211 @@
} }
@ -154,8 +156,7 @@
+ +
+ overworldData = new WorldDataServer(worldsettings, generatorsettings, Lifecycle.stable()); + overworldData = new WorldDataServer(worldsettings, generatorsettings, Lifecycle.stable());
+ } + }
+
- this.a(worldloadlistener);
+ GeneratorSettings overworldSettings = overworldData.getGeneratorSettings(); + GeneratorSettings overworldSettings = overworldData.getGeneratorSettings();
+ RegistryMaterials<WorldDimension> registrymaterials = overworldSettings.d(); + RegistryMaterials<WorldDimension> registrymaterials = overworldSettings.d();
+ for (Entry<ResourceKey<WorldDimension>, WorldDimension> entry : registrymaterials.d()) { + for (Entry<ResourceKey<WorldDimension>, WorldDimension> entry : registrymaterials.d()) {
@ -163,7 +164,8 @@
+ +
+ WorldServer world; + WorldServer world;
+ int dimension = 0; + int dimension = 0;
+
- this.a(worldloadlistener);
+ if (dimensionKey == WorldDimension.NETHER) { + if (dimensionKey == WorldDimension.NETHER) {
+ if (getAllowNether()) { + if (getAllowNether()) {
+ dimension = -1; + dimension = -1;
@ -226,6 +228,7 @@
+ } + }
+ +
+ org.bukkit.generator.ChunkGenerator gen = this.server.getGenerator(name); + org.bukkit.generator.ChunkGenerator gen = this.server.getGenerator(name);
+ org.bukkit.generator.BiomeProvider biomeProvider = this.server.getBiomeProvider(name);
+ +
+ WorldDataServer worlddata = (WorldDataServer) worldSession.a((DynamicOps) registryreadops, datapackconfiguration); + WorldDataServer worlddata = (WorldDataServer) worldSession.a((DynamicOps) registryreadops, datapackconfiguration);
+ if (worlddata == null) { + if (worlddata == null) {
@ -271,6 +274,18 @@
+ chunkgenerator = worlddimension.c(); + chunkgenerator = worlddimension.c();
+ } + }
+ +
+ org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(iworlddataserver, worldSession, org.bukkit.World.Environment.getEnvironment(dimension), dimensionmanager);
+ if (biomeProvider == null && gen != null) {
+ biomeProvider = gen.getDefaultBiomeProvider(worldInfo);
+ }
+
+ if (biomeProvider != null) {
+ WorldChunkManager worldChunkManager = new CustomWorldChunkManager(worldInfo, biomeProvider, registryHolder.b(IRegistry.BIOME_REGISTRY));
+ if (chunkgenerator instanceof ChunkGeneratorAbstract) {
+ chunkgenerator = new ChunkGeneratorAbstract(worldChunkManager, chunkgenerator.strongholdSeed, ((ChunkGeneratorAbstract) chunkgenerator).settings);
+ }
+ }
+
+ ResourceKey<World> worldKey = ResourceKey.a(IRegistry.DIMENSION_REGISTRY, dimensionKey.a()); + ResourceKey<World> worldKey = ResourceKey.a(IRegistry.DIMENSION_REGISTRY, dimensionKey.a());
+ +
+ if (dimensionKey == WorldDimension.OVERWORLD) { + if (dimensionKey == WorldDimension.OVERWORLD) {
@ -279,14 +294,14 @@
+ +
+ WorldLoadListener worldloadlistener = this.progressListenerFactory.create(11); + WorldLoadListener worldloadlistener = this.progressListenerFactory.create(11);
+ +
+ world = new WorldServer(this, this.executor, worldSession, iworlddataserver, worldKey, dimensionmanager, worldloadlistener, chunkgenerator, flag, j, list, true, org.bukkit.World.Environment.getEnvironment(dimension), gen); + world = new WorldServer(this, this.executor, worldSession, iworlddataserver, worldKey, dimensionmanager, worldloadlistener, chunkgenerator, flag, j, list, true, org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider);
+ WorldPersistentData worldpersistentdata = world.getWorldPersistentData(); + WorldPersistentData worldpersistentdata = world.getWorldPersistentData();
+ this.initializeScoreboards(worldpersistentdata); + this.initializeScoreboards(worldpersistentdata);
+ this.server.scoreboardManager = new org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager(this, world.getScoreboard()); + this.server.scoreboardManager = new org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager(this, world.getScoreboard());
+ this.commandStorage = new PersistentCommandStorage(worldpersistentdata); + this.commandStorage = new PersistentCommandStorage(worldpersistentdata);
+ } else { + } else {
+ WorldLoadListener worldloadlistener = this.progressListenerFactory.create(11); + WorldLoadListener worldloadlistener = this.progressListenerFactory.create(11);
+ world = new WorldServer(this, this.executor, worldSession, iworlddataserver, worldKey, dimensionmanager, worldloadlistener, chunkgenerator, flag, j, ImmutableList.of(), true, org.bukkit.World.Environment.getEnvironment(dimension), gen); + world = new WorldServer(this, this.executor, worldSession, iworlddataserver, worldKey, dimensionmanager, worldloadlistener, chunkgenerator, flag, j, ImmutableList.of(), true, org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider);
+ } + }
+ +
+ worlddata.a(this.getServerModName(), this.getModded().isPresent()); + worlddata.a(this.getServerModName(), this.getModded().isPresent());
@ -354,7 +369,7 @@
if (!iworlddataserver.p()) { if (!iworlddataserver.p()) {
try { try {
a(worldserver, iworlddataserver, generatorsettings.c(), flag); a(worldserver, iworlddataserver, generatorsettings.c(), flag);
@@ -421,31 +631,8 @@ @@ -421,31 +646,8 @@
iworlddataserver.c(true); iworlddataserver.c(true);
} }
@ -387,7 +402,7 @@
private static void a(WorldServer worldserver, IWorldDataServer iworlddataserver, boolean flag, boolean flag1) { private static void a(WorldServer worldserver, IWorldDataServer iworlddataserver, boolean flag, boolean flag1) {
if (flag1) { if (flag1) {
@@ -458,6 +645,21 @@ @@ -458,6 +660,21 @@
return biomebase.b().b(); return biomebase.b().b();
}, random); }, random);
ChunkCoordIntPair chunkcoordintpair = blockposition == null ? new ChunkCoordIntPair(0, 0) : new ChunkCoordIntPair(blockposition); ChunkCoordIntPair chunkcoordintpair = blockposition == null ? new ChunkCoordIntPair(0, 0) : new ChunkCoordIntPair(blockposition);
@ -409,7 +424,7 @@
if (blockposition == null) { if (blockposition == null) {
MinecraftServer.LOGGER.warn("Unable to find spawn biome"); MinecraftServer.LOGGER.warn("Unable to find spawn biome");
@@ -532,8 +734,15 @@ @@ -532,8 +749,15 @@
iworlddataserver.setGameType(EnumGamemode.SPECTATOR); iworlddataserver.setGameType(EnumGamemode.SPECTATOR);
} }
@ -427,7 +442,7 @@
MinecraftServer.LOGGER.info("Preparing start region for dimension {}", worldserver.getDimensionKey().a()); MinecraftServer.LOGGER.info("Preparing start region for dimension {}", worldserver.getDimensionKey().a());
BlockPosition blockposition = worldserver.getSpawn(); BlockPosition blockposition = worldserver.getSpawn();
@@ -546,16 +755,20 @@ @@ -546,16 +770,20 @@
chunkproviderserver.addTicket(TicketType.START, new ChunkCoordIntPair(blockposition), 11, Unit.INSTANCE); chunkproviderserver.addTicket(TicketType.START, new ChunkCoordIntPair(blockposition), 11, Unit.INSTANCE);
while (chunkproviderserver.b() != 441) { while (chunkproviderserver.b() != 441) {
@ -456,7 +471,7 @@
ForcedChunk forcedchunk = (ForcedChunk) worldserver1.getWorldPersistentData().a(ForcedChunk::b, "chunks"); ForcedChunk forcedchunk = (ForcedChunk) worldserver1.getWorldPersistentData().a(ForcedChunk::b, "chunks");
if (forcedchunk != null) { if (forcedchunk != null) {
@@ -570,11 +783,18 @@ @@ -570,11 +798,18 @@
} }
} }
@ -478,7 +493,7 @@
} }
protected void loadResourcesZip() { protected void loadResourcesZip() {
@@ -619,12 +839,16 @@ @@ -619,12 +854,16 @@
worldserver.save((IProgressUpdate) null, flag1, worldserver.noSave && !flag2); worldserver.save((IProgressUpdate) null, flag1, worldserver.noSave && !flag2);
} }
@ -495,7 +510,7 @@
if (flag1) { if (flag1) {
Iterator iterator1 = this.getWorlds().iterator(); Iterator iterator1 = this.getWorlds().iterator();
@@ -645,8 +869,29 @@ @@ -645,8 +884,29 @@
this.stop(); this.stop();
} }
@ -525,7 +540,7 @@
if (this.getServerConnection() != null) { if (this.getServerConnection() != null) {
this.getServerConnection().b(); this.getServerConnection().b();
} }
@@ -655,6 +900,7 @@ @@ -655,6 +915,7 @@
MinecraftServer.LOGGER.info("Saving players"); MinecraftServer.LOGGER.info("Saving players");
this.playerList.savePlayers(); this.playerList.savePlayers();
this.playerList.shutdown(); this.playerList.shutdown();
@ -533,7 +548,7 @@
} }
MinecraftServer.LOGGER.info("Saving worlds"); MinecraftServer.LOGGER.info("Saving worlds");
@@ -732,9 +978,10 @@ @@ -732,9 +993,10 @@
while (this.running) { while (this.running) {
long i = SystemUtils.getMonotonicMillis() - this.nextTickTime; long i = SystemUtils.getMonotonicMillis() - this.nextTickTime;
@ -545,7 +560,7 @@
MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", i, j); MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", i, j);
this.nextTickTime += j * 50L; this.nextTickTime += j * 50L;
this.lastOverloadWarning = this.nextTickTime; this.lastOverloadWarning = this.nextTickTime;
@@ -745,6 +992,7 @@ @@ -745,6 +1007,7 @@
this.debugCommandProfiler = new MinecraftServer.a(SystemUtils.getMonotonicNanos(), this.tickCount); this.debugCommandProfiler = new MinecraftServer.a(SystemUtils.getMonotonicNanos(), this.tickCount);
} }
@ -553,7 +568,7 @@
this.nextTickTime += 50L; this.nextTickTime += 50L;
this.bh(); this.bh();
this.profiler.enter("tick"); this.profiler.enter("tick");
@@ -790,6 +1038,12 @@ @@ -790,6 +1053,12 @@
} catch (Throwable throwable1) { } catch (Throwable throwable1) {
MinecraftServer.LOGGER.error("Exception stopping the server", throwable1); MinecraftServer.LOGGER.error("Exception stopping the server", throwable1);
} finally { } finally {
@ -566,7 +581,7 @@
this.exit(); this.exit();
} }
@@ -798,8 +1052,15 @@ @@ -798,8 +1067,15 @@
} }
private boolean canSleepForTick() { private boolean canSleepForTick() {
@ -583,7 +598,7 @@
protected void sleepForTick() { protected void sleepForTick() {
this.executeAll(); this.executeAll();
@@ -908,7 +1169,7 @@ @@ -908,7 +1184,7 @@
this.status.b().a(agameprofile); this.status.b().a(agameprofile);
} }
@ -592,7 +607,7 @@
MinecraftServer.LOGGER.debug("Autosave started"); MinecraftServer.LOGGER.debug("Autosave started");
this.profiler.enter("save"); this.profiler.enter("save");
this.playerList.savePlayers(); this.playerList.savePlayers();
@@ -938,22 +1199,39 @@ @@ -938,22 +1214,39 @@
} }
public void b(BooleanSupplier booleansupplier) { public void b(BooleanSupplier booleansupplier) {
@ -632,7 +647,7 @@
this.profiler.enter("tick"); this.profiler.enter("tick");
@@ -1042,7 +1320,7 @@ @@ -1042,7 +1335,7 @@
@DontObfuscate @DontObfuscate
public String getServerModName() { public String getServerModName() {
@ -641,7 +656,7 @@
} }
public SystemReport b(SystemReport systemreport) { public SystemReport b(SystemReport systemreport) {
@@ -1414,16 +1692,17 @@ @@ -1414,16 +1707,17 @@
public CompletableFuture<Void> a(Collection<String> collection) { public CompletableFuture<Void> a(Collection<String> collection) {
CompletableFuture<Void> completablefuture = CompletableFuture.supplyAsync(() -> { CompletableFuture<Void> completablefuture = CompletableFuture.supplyAsync(() -> {
@ -661,7 +676,7 @@
this.packRepository.a(collection); this.packRepository.a(collection);
this.worldData.a(a(this.packRepository)); this.worldData.a(a(this.packRepository));
datapackresources.j(); datapackresources.j();
@@ -1768,6 +2047,22 @@ @@ -1768,6 +2062,22 @@
} }

View File

@ -47,9 +47,9 @@
+ } + }
+ +
+ // Add env and gen to constructor, WorldData -> WorldDataServer + // Add env and gen to constructor, WorldData -> WorldDataServer
+ public WorldServer(MinecraftServer minecraftserver, Executor executor, Convertable.ConversionSession convertable_conversionsession, IWorldDataServer iworlddataserver, ResourceKey<World> resourcekey, DimensionManager dimensionmanager, WorldLoadListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List<MobSpawner> list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { + public WorldServer(MinecraftServer minecraftserver, Executor executor, Convertable.ConversionSession convertable_conversionsession, IWorldDataServer iworlddataserver, ResourceKey<World> resourcekey, DimensionManager dimensionmanager, WorldLoadListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List<MobSpawner> list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
+ // Objects.requireNonNull(minecraftserver); // CraftBukkit - decompile error + // Objects.requireNonNull(minecraftserver); // CraftBukkit - decompile error
+ super(iworlddataserver, resourcekey, dimensionmanager, minecraftserver::getMethodProfiler, false, flag, i, gen, env); + super(iworlddataserver, resourcekey, dimensionmanager, minecraftserver::getMethodProfiler, false, flag, i, gen, biomeProvider, env);
+ this.pvpMode = minecraftserver.getPVP(); + this.pvpMode = minecraftserver.getPVP();
+ convertable = convertable_conversionsession; + convertable = convertable_conversionsession;
+ uuid = WorldUUID.getUUID(convertable_conversionsession.levelPath.toFile()); + uuid = WorldUUID.getUUID(convertable_conversionsession.levelPath.toFile());

View File

@ -59,13 +59,14 @@
protected static final Logger LOGGER = LogManager.getLogger(); protected static final Logger LOGGER = LogManager.getLogger();
public static final String ID_TAG = "id"; public static final String ID_TAG = "id";
public static final String PASSENGERS_TAG = "Passengers"; public static final String PASSENGERS_TAG = "Passengers";
@@ -224,6 +274,21 @@ @@ -224,6 +274,22 @@
private float crystalSoundIntensity; private float crystalSoundIntensity;
private int lastCrystalSoundPlayTick; private int lastCrystalSoundPlayTick;
public boolean hasVisualFire; public boolean hasVisualFire;
+ // CraftBukkit start + // CraftBukkit start
+ public boolean persist = true; + public boolean persist = true;
+ public boolean valid; + public boolean valid;
+ public boolean generation;
+ public org.bukkit.projectiles.ProjectileSource projectileSource; // For projectiles only + public org.bukkit.projectiles.ProjectileSource projectileSource; // For projectiles only
+ public boolean forceExplosionKnockback; // SPIGOT-949 + public boolean forceExplosionKnockback; // SPIGOT-949
+ public boolean persistentInvisibility = false; + public boolean persistentInvisibility = false;
@ -81,7 +82,7 @@
public Entity(EntityTypes<?> entitytypes, World world) { public Entity(EntityTypes<?> entitytypes, World world) {
this.id = Entity.ENTITY_COUNTER.incrementAndGet(); this.id = Entity.ENTITY_COUNTER.incrementAndGet();
@@ -359,6 +424,12 @@ @@ -359,6 +425,12 @@
public void ae() {} public void ae() {}
public void setPose(EntityPose entitypose) { public void setPose(EntityPose entitypose) {
@ -94,7 +95,7 @@
this.entityData.set(Entity.DATA_POSE, entitypose); this.entityData.set(Entity.DATA_POSE, entitypose);
} }
@@ -375,6 +446,33 @@ @@ -375,6 +447,33 @@
} }
protected void setYawPitch(float f, float f1) { protected void setYawPitch(float f, float f1) {
@ -128,7 +129,7 @@
this.setYRot(f % 360.0F); this.setYRot(f % 360.0F);
this.setXRot(f1 % 360.0F); this.setXRot(f1 % 360.0F);
} }
@@ -416,6 +514,15 @@ @@ -416,6 +515,15 @@
this.entityBaseTick(); this.entityBaseTick();
} }
@ -144,7 +145,7 @@
public void entityBaseTick() { public void entityBaseTick() {
this.level.getMethodProfiler().enter("entityBaseTick"); this.level.getMethodProfiler().enter("entityBaseTick");
if (this.isPassenger() && this.getVehicle().isRemoved()) { if (this.isPassenger() && this.getVehicle().isRemoved()) {
@@ -429,7 +536,7 @@ @@ -429,7 +537,7 @@
this.walkDistO = this.walkDist; this.walkDistO = this.walkDist;
this.xRotO = this.getXRot(); this.xRotO = this.getXRot();
this.yRotO = this.getYRot(); this.yRotO = this.getYRot();
@ -153,7 +154,7 @@
if (this.aV()) { if (this.aV()) {
this.aW(); this.aW();
} }
@@ -507,7 +614,23 @@ @@ -507,7 +615,23 @@
public void burnFromLava() { public void burnFromLava() {
if (!this.isFireProof()) { if (!this.isFireProof()) {
@ -178,7 +179,7 @@
if (this.damageEntity(DamageSource.LAVA, 4.0F)) { if (this.damageEntity(DamageSource.LAVA, 4.0F)) {
this.playSound(SoundEffects.GENERIC_BURN, 0.4F, 2.0F + this.random.nextFloat() * 0.4F); this.playSound(SoundEffects.GENERIC_BURN, 0.4F, 2.0F + this.random.nextFloat() * 0.4F);
} }
@@ -516,6 +639,22 @@ @@ -516,6 +640,22 @@
} }
public void setOnFire(int i) { public void setOnFire(int i) {
@ -201,7 +202,7 @@
int j = i * 20; int j = i * 20;
if (this instanceof EntityLiving) { if (this instanceof EntityLiving) {
@@ -614,6 +753,28 @@ @@ -614,6 +754,28 @@
block.a((IBlockAccess) this.level, this); block.a((IBlockAccess) this.level, this);
} }
@ -230,15 +231,15 @@
if (this.onGround && !this.bE()) { if (this.onGround && !this.bE()) {
block.stepOn(this.level, blockposition, iblockdata, this); block.stepOn(this.level, blockposition, iblockdata, this);
} }
@@ -1276,6 +1437,7 @@ @@ -1276,6 +1438,7 @@
this.yo = d1; this.yo = d1;
this.zo = d4; this.zo = d4;
this.setPosition(d3, d1, d4); this.setPosition(d3, d1, d4);
+ level.getChunkAt((int) Math.floor(this.locX()) >> 4, (int) Math.floor(this.locZ()) >> 4); // CraftBukkit + if (valid) level.getChunkAt((int) Math.floor(this.locX()) >> 4, (int) Math.floor(this.locZ()) >> 4); // CraftBukkit
} }
public void d(Vec3D vec3d) { public void d(Vec3D vec3d) {
@@ -1466,6 +1628,12 @@ @@ -1466,6 +1629,12 @@
return false; return false;
} }
@ -251,7 +252,7 @@
public void a(Entity entity, int i, DamageSource damagesource) { public void a(Entity entity, int i, DamageSource damagesource) {
if (entity instanceof EntityPlayer) { if (entity instanceof EntityPlayer) {
CriterionTriggers.ENTITY_KILLED_PLAYER.a((EntityPlayer) entity, this, damagesource); CriterionTriggers.ENTITY_KILLED_PLAYER.a((EntityPlayer) entity, this, damagesource);
@@ -1499,7 +1667,7 @@ @@ -1499,7 +1668,7 @@
} else { } else {
String s = this.getSaveID(); String s = this.getSaveID();
@ -260,7 +261,7 @@
return false; return false;
} else { } else {
nbttagcompound.setString("id", s); nbttagcompound.setString("id", s);
@@ -1524,6 +1692,18 @@ @@ -1524,6 +1693,18 @@
Vec3D vec3d = this.getMot(); Vec3D vec3d = this.getMot();
nbttagcompound.set("Motion", this.newDoubleList(vec3d.x, vec3d.y, vec3d.z)); nbttagcompound.set("Motion", this.newDoubleList(vec3d.x, vec3d.y, vec3d.z));
@ -279,7 +280,7 @@
nbttagcompound.set("Rotation", this.newFloatList(this.getYRot(), this.getXRot())); nbttagcompound.set("Rotation", this.newFloatList(this.getYRot(), this.getXRot()));
nbttagcompound.setFloat("FallDistance", this.fallDistance); nbttagcompound.setFloat("FallDistance", this.fallDistance);
nbttagcompound.setShort("Fire", (short) this.remainingFireTicks); nbttagcompound.setShort("Fire", (short) this.remainingFireTicks);
@@ -1532,6 +1712,18 @@ @@ -1532,6 +1713,18 @@
nbttagcompound.setBoolean("Invulnerable", this.invulnerable); nbttagcompound.setBoolean("Invulnerable", this.invulnerable);
nbttagcompound.setInt("PortalCooldown", this.portalCooldown); nbttagcompound.setInt("PortalCooldown", this.portalCooldown);
nbttagcompound.a("UUID", this.getUniqueID()); nbttagcompound.a("UUID", this.getUniqueID());
@ -298,7 +299,7 @@
IChatBaseComponent ichatbasecomponent = this.getCustomName(); IChatBaseComponent ichatbasecomponent = this.getCustomName();
if (ichatbasecomponent != null) { if (ichatbasecomponent != null) {
@@ -1599,6 +1791,11 @@ @@ -1599,6 +1792,11 @@
} }
} }
@ -310,7 +311,7 @@
return nbttagcompound; return nbttagcompound;
} catch (Throwable throwable) { } catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Saving entity NBT"); CrashReport crashreport = CrashReport.a(throwable, "Saving entity NBT");
@@ -1680,6 +1877,49 @@ @@ -1680,6 +1878,49 @@
} else { } else {
throw new IllegalStateException("Entity has invalid position"); throw new IllegalStateException("Entity has invalid position");
} }
@ -360,7 +361,7 @@
} catch (Throwable throwable) { } catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Loading entity NBT"); CrashReport crashreport = CrashReport.a(throwable, "Loading entity NBT");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being loaded"); CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being loaded");
@@ -1755,9 +1995,22 @@ @@ -1755,9 +1996,22 @@
} else if (this.level.isClientSide) { } else if (this.level.isClientSide) {
return null; return null;
} else { } else {
@ -383,7 +384,7 @@
this.level.addEntity(entityitem); this.level.addEntity(entityitem);
return entityitem; return entityitem;
} }
@@ -1849,7 +2102,7 @@ @@ -1849,7 +2103,7 @@
this.setPose(EntityPose.STANDING); this.setPose(EntityPose.STANDING);
this.vehicle = entity; this.vehicle = entity;
@ -392,7 +393,7 @@
entity.n().filter((entity2) -> { entity.n().filter((entity2) -> {
return entity2 instanceof EntityPlayer; return entity2 instanceof EntityPlayer;
}).forEach((entity2) -> { }).forEach((entity2) -> {
@@ -1880,7 +2133,7 @@ @@ -1880,7 +2134,7 @@
Entity entity = this.vehicle; Entity entity = this.vehicle;
this.vehicle = null; this.vehicle = null;
@ -401,7 +402,7 @@
} }
} }
@@ -1889,10 +2142,31 @@ @@ -1889,10 +2143,31 @@
this.bo(); this.bo();
} }
@ -434,7 +435,7 @@
if (this.passengers.isEmpty()) { if (this.passengers.isEmpty()) {
this.passengers = ImmutableList.of(entity); this.passengers = ImmutableList.of(entity);
} else { } else {
@@ -1908,12 +2182,32 @@ @@ -1908,12 +2183,32 @@
} }
} }
@ -468,7 +469,7 @@
if (this.passengers.size() == 1 && this.passengers.get(0) == entity) { if (this.passengers.size() == 1 && this.passengers.get(0) == entity) {
this.passengers = ImmutableList.of(); this.passengers = ImmutableList.of();
} else { } else {
@@ -1924,6 +2218,7 @@ @@ -1924,6 +2219,7 @@
entity.boardingCooldown = 60; entity.boardingCooldown = 60;
} }
@ -476,7 +477,7 @@
} }
protected boolean o(Entity entity) { protected boolean o(Entity entity) {
@@ -1974,14 +2269,20 @@ @@ -1974,14 +2270,20 @@
if (this.isInsidePortal) { if (this.isInsidePortal) {
MinecraftServer minecraftserver = worldserver.getMinecraftServer(); MinecraftServer minecraftserver = worldserver.getMinecraftServer();
@ -500,12 +501,12 @@
this.level.getMethodProfiler().exit(); this.level.getMethodProfiler().exit();
} }
@@ -2099,6 +2400,13 @@ @@ -2099,6 +2401,13 @@
} }
public void setSwimming(boolean flag) { public void setSwimming(boolean flag) {
+ // CraftBukkit start + // CraftBukkit start
+ if (this.isSwimming() != flag && this instanceof EntityLiving) { + if (valid && this.isSwimming() != flag && this instanceof EntityLiving) {
+ if (CraftEventFactory.callToggleSwimEvent((EntityLiving) this, flag).isCancelled()) { + if (CraftEventFactory.callToggleSwimEvent((EntityLiving) this, flag).isCancelled()) {
+ return; + return;
+ } + }
@ -514,7 +515,7 @@
this.setFlag(4, flag); this.setFlag(4, flag);
} }
@@ -2147,8 +2455,12 @@ @@ -2147,8 +2456,12 @@
return this.getScoreboardTeam() != null ? this.getScoreboardTeam().isAlly(scoreboardteambase) : false; return this.getScoreboardTeam() != null ? this.getScoreboardTeam().isAlly(scoreboardteambase) : false;
} }
@ -528,7 +529,7 @@
} }
public boolean getFlag(int i) { public boolean getFlag(int i) {
@@ -2175,7 +2487,17 @@ @@ -2175,7 +2488,17 @@
} }
public void setAirTicks(int i) { public void setAirTicks(int i) {
@ -547,7 +548,7 @@
} }
public int getTicksFrozen() { public int getTicksFrozen() {
@@ -2202,11 +2524,41 @@ @@ -2202,11 +2525,41 @@
public void onLightningStrike(WorldServer worldserver, EntityLightning entitylightning) { public void onLightningStrike(WorldServer worldserver, EntityLightning entitylightning) {
this.setFireTicks(this.remainingFireTicks + 1); this.setFireTicks(this.remainingFireTicks + 1);
@ -591,7 +592,7 @@
} }
public void k(boolean flag) { public void k(boolean flag) {
@@ -2356,15 +2708,32 @@ @@ -2356,15 +2709,32 @@
@Nullable @Nullable
public Entity b(WorldServer worldserver) { public Entity b(WorldServer worldserver) {
@ -626,7 +627,7 @@
this.level.getMethodProfiler().exitEnter("reloading"); this.level.getMethodProfiler().exitEnter("reloading");
Entity entity = this.getEntityType().a((World) worldserver); Entity entity = this.getEntityType().a((World) worldserver);
@@ -2373,9 +2742,17 @@ @@ -2373,9 +2743,17 @@
entity.setPositionRotation(shapedetectorshape.pos.x, shapedetectorshape.pos.y, shapedetectorshape.pos.z, shapedetectorshape.yRot, entity.getXRot()); entity.setPositionRotation(shapedetectorshape.pos.x, shapedetectorshape.pos.y, shapedetectorshape.pos.z, shapedetectorshape.yRot, entity.getXRot());
entity.setMot(shapedetectorshape.speed); entity.setMot(shapedetectorshape.speed);
worldserver.addEntityTeleport(entity); worldserver.addEntityTeleport(entity);
@ -646,7 +647,7 @@
} }
this.cc(); this.cc();
@@ -2396,13 +2773,18 @@ @@ -2396,13 +2774,18 @@
@Nullable @Nullable
protected ShapeDetectorShape a(WorldServer worldserver) { protected ShapeDetectorShape a(WorldServer worldserver) {
@ -669,7 +670,7 @@
return null; return null;
} else { } else {
WorldBorder worldborder = worldserver.getWorldBorder(); WorldBorder worldborder = worldserver.getWorldBorder();
@@ -2412,8 +2794,16 @@ @@ -2412,8 +2795,16 @@
double d3 = Math.min(2.9999872E7D, worldborder.h() - 16.0D); double d3 = Math.min(2.9999872E7D, worldborder.h() - 16.0D);
double d4 = DimensionManager.a(this.level.getDimensionManager(), worldserver.getDimensionManager()); double d4 = DimensionManager.a(this.level.getDimensionManager(), worldserver.getDimensionManager());
BlockPosition blockposition = new BlockPosition(MathHelper.a(this.locX() * d4, d0, d2), this.locY(), MathHelper.a(this.locZ() * d4, d1, d3)); BlockPosition blockposition = new BlockPosition(MathHelper.a(this.locX() * d4, d0, d2), this.locY(), MathHelper.a(this.locZ() * d4, d1, d3));
@ -687,7 +688,7 @@
IBlockData iblockdata = this.level.getType(this.portalEntrancePos); IBlockData iblockdata = this.level.getType(this.portalEntrancePos);
EnumDirection.EnumAxis enumdirection_enumaxis; EnumDirection.EnumAxis enumdirection_enumaxis;
Vec3D vec3d; Vec3D vec3d;
@@ -2430,8 +2820,8 @@ @@ -2430,8 +2821,8 @@
vec3d = new Vec3D(0.5D, 0.0D, 0.0D); vec3d = new Vec3D(0.5D, 0.0D, 0.0D);
} }
@ -698,7 +699,7 @@
} }
} else { } else {
BlockPosition blockposition1; BlockPosition blockposition1;
@@ -2441,8 +2831,15 @@ @@ -2441,8 +2832,15 @@
} else { } else {
blockposition1 = worldserver.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING_NO_LEAVES, worldserver.getSpawn()); blockposition1 = worldserver.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING_NO_LEAVES, worldserver.getSpawn());
} }
@ -715,7 +716,7 @@
} }
} }
@@ -2450,8 +2847,23 @@ @@ -2450,8 +2848,23 @@
return BlockPortalShape.a(blockutil_rectangle, enumdirection_enumaxis, this.getPositionVector(), this.a(this.getPose())); return BlockPortalShape.a(blockutil_rectangle, enumdirection_enumaxis, this.getPositionVector(), this.a(this.getPose()));
} }
@ -741,7 +742,7 @@
} }
public boolean canPortal() { public boolean canPortal() {
@@ -2660,7 +3072,26 @@ @@ -2660,7 +3073,26 @@
} }
public final void a(AxisAlignedBB axisalignedbb) { public final void a(AxisAlignedBB axisalignedbb) {

View File

@ -66,9 +66,9 @@
+ return typeKey; + return typeKey;
+ } + }
+ +
+ protected World(WorldDataMutable worlddatamutable, ResourceKey<World> resourcekey, final DimensionManager dimensionmanager, Supplier<GameProfilerFiller> supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env) { + protected World(WorldDataMutable worlddatamutable, ResourceKey<World> resourcekey, final DimensionManager dimensionmanager, Supplier<GameProfilerFiller> supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env) {
+ this.generator = gen; + this.generator = gen;
+ this.world = new CraftWorld((WorldServer) this, gen, env); + this.world = new CraftWorld((WorldServer) this, gen, biomeProvider, env);
+ this.ticksPerAnimalSpawns = this.getCraftServer().getTicksPerAnimalSpawns(); // CraftBukkit + this.ticksPerAnimalSpawns = this.getCraftServer().getTicksPerAnimalSpawns(); // CraftBukkit
+ this.ticksPerMonsterSpawns = this.getCraftServer().getTicksPerMonsterSpawns(); // CraftBukkit + this.ticksPerMonsterSpawns = this.getCraftServer().getTicksPerMonsterSpawns(); // CraftBukkit
+ this.ticksPerWaterSpawns = this.getCraftServer().getTicksPerWaterSpawns(); // CraftBukkit + this.ticksPerWaterSpawns = this.getCraftServer().getTicksPerWaterSpawns(); // CraftBukkit

View File

@ -1,6 +1,70 @@
--- a/net/minecraft/world/level/chunk/ChunkGenerator.java --- a/net/minecraft/world/level/chunk/ChunkGenerator.java
+++ b/net/minecraft/world/level/chunk/ChunkGenerator.java +++ b/net/minecraft/world/level/chunk/ChunkGenerator.java
@@ -269,7 +269,16 @@ @@ -63,7 +63,7 @@
protected final WorldChunkManager biomeSource;
protected final WorldChunkManager runtimeBiomeSource;
private final StructureSettings settings;
- private final long strongholdSeed;
+ public final long strongholdSeed; // PAIL private -> public
private final List<ChunkCoordIntPair> strongholdPositions;
private final BaseStoneSource defaultBaseStoneSource;
@@ -217,7 +217,7 @@
}
}
- public void addDecorations(RegionLimitedWorldAccess regionlimitedworldaccess, StructureManager structuremanager) {
+ public void addVanillaDecorations(RegionLimitedWorldAccess regionlimitedworldaccess, StructureManager structuremanager) { // CraftBukkit
ChunkCoordIntPair chunkcoordintpair = regionlimitedworldaccess.a();
int i = chunkcoordintpair.d();
int j = chunkcoordintpair.e();
@@ -236,8 +236,45 @@
}
}
+ public void addDecorations(RegionLimitedWorldAccess regionlimitedworldaccess, StructureManager structuremanager) {
+ // CraftBukkit start
+ addDecorations(regionlimitedworldaccess, structuremanager, true);
+ }
+
+ public void addDecorations(RegionLimitedWorldAccess regionlimitedworldaccess, StructureManager structuremanager, boolean vanilla) {
+ if (vanilla) {
+ addVanillaDecorations(regionlimitedworldaccess, structuremanager);
+ }
+
+ org.bukkit.World world = regionlimitedworldaccess.getMinecraftWorld().getWorld();
+ // only call when a populator is present (prevents unnecessary entity conversion)
+ if (world.getPopulators().size() != 0) {
+ org.bukkit.craftbukkit.generator.CraftLimitedRegion limitedRegion = new org.bukkit.craftbukkit.generator.CraftLimitedRegion(regionlimitedworldaccess);
+ int x = regionlimitedworldaccess.a().x;
+ int z = regionlimitedworldaccess.a().z;
+ for (org.bukkit.generator.BlockPopulator populator : world.getPopulators()) {
+ SeededRandom seededrandom = new SeededRandom();
+ seededrandom.a(regionlimitedworldaccess.getSeed(), x, z);
+ populator.populate(world, seededrandom, x, z, limitedRegion);
+ }
+ limitedRegion.saveEntities();
+ limitedRegion.breakLink();
+ }
+ // CraftBukkit end
+ }
+
public abstract void buildBase(RegionLimitedWorldAccess regionlimitedworldaccess, IChunkAccess ichunkaccess);
+ // CraftBukkit start - spilt surface and bedrock generation code
+ public SeededRandom buildSurface(RegionLimitedWorldAccess regionlimitedworldaccess, IChunkAccess iChunkAccess) {
+ throw new UnsupportedOperationException("Methode not overridden");
+ }
+
+ public void buildBedrock(IChunkAccess iChunkAccess, Random random) {
+ throw new UnsupportedOperationException("Methode not overridden");
+ }
+ // CraftBukkit end
+
public void addMobs(RegionLimitedWorldAccess regionlimitedworldaccess) {}
public StructureSettings getSettings() {
@@ -269,7 +306,16 @@
while (iterator.hasNext()) { while (iterator.hasNext()) {
Supplier<StructureFeature<?, ?>> supplier = (Supplier) iterator.next(); Supplier<StructureFeature<?, ?>> supplier = (Supplier) iterator.next();
@ -18,7 +82,7 @@
} }
} }
@@ -364,9 +373,11 @@ @@ -364,9 +410,11 @@
} }
static { static {

View File

@ -0,0 +1,69 @@
--- a/net/minecraft/world/level/levelgen/ChunkGeneratorAbstract.java
+++ b/net/minecraft/world/level/levelgen/ChunkGeneratorAbstract.java
@@ -76,7 +76,7 @@
protected final IBlockData defaultBlock;
protected final IBlockData defaultFluid;
private final long seed;
- protected final Supplier<GeneratorSettingBase> settings;
+ public final Supplier<GeneratorSettingBase> settings; // PAIL protected -> public
private final int height;
private final NoiseSampler sampler;
private final BaseStoneSource baseStoneSource;
@@ -257,6 +257,19 @@
@Override
public void buildBase(RegionLimitedWorldAccess regionlimitedworldaccess, IChunkAccess ichunkaccess) {
+ // CraftBukkit start - spilt surface and bedrock generation code
+ Random random = buildSurface(regionlimitedworldaccess, ichunkaccess);
+ buildBedrock(ichunkaccess, random);
+ }
+
+ @Override
+ public void buildBedrock(IChunkAccess iChunkAccess, Random random) {
+ a(iChunkAccess, random); // PAIL rename setBedrock
+ }
+
+ @Override
+ public SeededRandom buildSurface(RegionLimitedWorldAccess regionlimitedworldaccess, IChunkAccess ichunkaccess) {
+ // CraftBukkit end
ChunkCoordIntPair chunkcoordintpair = ichunkaccess.getPos();
int i = chunkcoordintpair.x;
int j = chunkcoordintpair.z;
@@ -281,7 +294,10 @@
}
}
- this.a(ichunkaccess, seededrandom);
+ // CraftBukkit start - spilt surface and bedrock generation code
+ // this.a(ichunkaccess, seededrandom);
+ return seededrandom;
+ // CraftBukkit end
}
private void a(IChunkAccess ichunkaccess, Random random) {
@@ -403,16 +419,23 @@
BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
for (int i1 = 0; i1 < this.cellCountX; ++i1) {
+ // CraftBukkit start - decompile error
+ int i1Final = i1;
list.forEach((noiseinterpolator1) -> {
- noiseinterpolator1.a(i1);
+ noiseinterpolator1.a(i1Final);
+ // CraftBukkit end
});
for (int j1 = 0; j1 < this.cellCountZ; ++j1) {
ChunkSection chunksection = ichunkaccess.b(ichunkaccess.getSectionsCount() - 1);
for (int k1 = j - 1; k1 >= 0; --k1) {
+ // CraftBukkit start - decompile error
+ int kiFinal = k1;
+ int j1Final = j1;
list.forEach((noiseinterpolator1) -> {
- noiseinterpolator1.a(k1, j1);
+ noiseinterpolator1.a(kiFinal, j1Final);
+ // CraftBukkit end
});
for (int l1 = this.cellHeight - 1; l1 >= 0; --l1) {

View File

@ -2,7 +2,7 @@ package org.bukkit.craftbukkit;
import org.bukkit.HeightMap; import org.bukkit.HeightMap;
final class CraftHeightMap { public final class CraftHeightMap {
private CraftHeightMap() { private CraftHeightMap() {
} }

View File

@ -0,0 +1,888 @@
package org.bukkit.craftbukkit;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import net.minecraft.core.BlockPosition;
import net.minecraft.core.EnumDirection;
import net.minecraft.core.IRegistry;
import net.minecraft.data.worldgen.BiomeDecoratorGroups;
import net.minecraft.world.entity.EntityAreaEffectCloud;
import net.minecraft.world.entity.EntityExperienceOrb;
import net.minecraft.world.entity.EntityInsentient;
import net.minecraft.world.entity.EntityTypes;
import net.minecraft.world.entity.EnumMobSpawn;
import net.minecraft.world.entity.GroupDataEntity;
import net.minecraft.world.entity.decoration.EntityArmorStand;
import net.minecraft.world.entity.decoration.EntityHanging;
import net.minecraft.world.entity.decoration.EntityItemFrame;
import net.minecraft.world.entity.decoration.EntityLeash;
import net.minecraft.world.entity.decoration.EntityPainting;
import net.minecraft.world.entity.item.EntityFallingBlock;
import net.minecraft.world.entity.item.EntityTNTPrimed;
import net.minecraft.world.entity.monster.EntityZombie;
import net.minecraft.world.entity.projectile.EntityEgg;
import net.minecraft.world.entity.projectile.EntityEnderSignal;
import net.minecraft.world.entity.projectile.EntityEvokerFangs;
import net.minecraft.world.entity.projectile.EntityFireball;
import net.minecraft.world.entity.projectile.EntityFireworks;
import net.minecraft.world.entity.projectile.EntityPotion;
import net.minecraft.world.entity.projectile.EntitySnowball;
import net.minecraft.world.entity.projectile.EntityTippedArrow;
import net.minecraft.world.entity.vehicle.EntityBoat;
import net.minecraft.world.entity.vehicle.EntityMinecartChest;
import net.minecraft.world.entity.vehicle.EntityMinecartCommandBlock;
import net.minecraft.world.entity.vehicle.EntityMinecartFurnace;
import net.minecraft.world.entity.vehicle.EntityMinecartHopper;
import net.minecraft.world.entity.vehicle.EntityMinecartMobSpawner;
import net.minecraft.world.entity.vehicle.EntityMinecartRideable;
import net.minecraft.world.entity.vehicle.EntityMinecartTNT;
import net.minecraft.world.level.GeneratorAccessSeed;
import net.minecraft.world.level.biome.BiomeBase;
import net.minecraft.world.level.block.BlockChorusFlower;
import net.minecraft.world.level.block.BlockDiodeAbstract;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.IBlockData;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import net.minecraft.world.phys.AxisAlignedBB;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.RegionAccessor;
import org.bukkit.TreeType;
import org.bukkit.block.Biome;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.potion.CraftPotionUtil;
import org.bukkit.craftbukkit.util.BlockStateListPopulator;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.AbstractSkeleton;
import org.bukkit.entity.AbstractVillager;
import org.bukkit.entity.Ambient;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Axolotl;
import org.bukkit.entity.Bat;
import org.bukkit.entity.Bee;
import org.bukkit.entity.Blaze;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Cat;
import org.bukkit.entity.CaveSpider;
import org.bukkit.entity.ChestedHorse;
import org.bukkit.entity.Chicken;
import org.bukkit.entity.Cod;
import org.bukkit.entity.ComplexLivingEntity;
import org.bukkit.entity.Cow;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Donkey;
import org.bukkit.entity.DragonFireball;
import org.bukkit.entity.Drowned;
import org.bukkit.entity.Egg;
import org.bukkit.entity.ElderGuardian;
import org.bukkit.entity.EnderCrystal;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.EnderPearl;
import org.bukkit.entity.EnderSignal;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Endermite;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Evoker;
import org.bukkit.entity.EvokerFangs;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Fireball;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Fish;
import org.bukkit.entity.Fox;
import org.bukkit.entity.Ghast;
import org.bukkit.entity.Giant;
import org.bukkit.entity.GlowItemFrame;
import org.bukkit.entity.GlowSquid;
import org.bukkit.entity.Goat;
import org.bukkit.entity.Golem;
import org.bukkit.entity.Guardian;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.Hoglin;
import org.bukkit.entity.Husk;
import org.bukkit.entity.Illager;
import org.bukkit.entity.Illusioner;
import org.bukkit.entity.IronGolem;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LeashHitch;
import org.bukkit.entity.LightningStrike;
import org.bukkit.entity.LingeringPotion;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Llama;
import org.bukkit.entity.LlamaSpit;
import org.bukkit.entity.MagmaCube;
import org.bukkit.entity.Marker;
import org.bukkit.entity.Minecart;
import org.bukkit.entity.Mule;
import org.bukkit.entity.MushroomCow;
import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Painting;
import org.bukkit.entity.Panda;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.Phantom;
import org.bukkit.entity.Pig;
import org.bukkit.entity.PigZombie;
import org.bukkit.entity.Piglin;
import org.bukkit.entity.PiglinBrute;
import org.bukkit.entity.Pillager;
import org.bukkit.entity.Player;
import org.bukkit.entity.PolarBear;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.PufferFish;
import org.bukkit.entity.Rabbit;
import org.bukkit.entity.Ravager;
import org.bukkit.entity.Salmon;
import org.bukkit.entity.Sheep;
import org.bukkit.entity.Shulker;
import org.bukkit.entity.ShulkerBullet;
import org.bukkit.entity.Silverfish;
import org.bukkit.entity.Skeleton;
import org.bukkit.entity.SkeletonHorse;
import org.bukkit.entity.Slime;
import org.bukkit.entity.SmallFireball;
import org.bukkit.entity.Snowball;
import org.bukkit.entity.Snowman;
import org.bukkit.entity.SpectralArrow;
import org.bukkit.entity.Spellcaster;
import org.bukkit.entity.Spider;
import org.bukkit.entity.Squid;
import org.bukkit.entity.Stray;
import org.bukkit.entity.Strider;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.ThrownExpBottle;
import org.bukkit.entity.ThrownPotion;
import org.bukkit.entity.TippedArrow;
import org.bukkit.entity.TraderLlama;
import org.bukkit.entity.Trident;
import org.bukkit.entity.TropicalFish;
import org.bukkit.entity.Turtle;
import org.bukkit.entity.Vex;
import org.bukkit.entity.Villager;
import org.bukkit.entity.Vindicator;
import org.bukkit.entity.WanderingTrader;
import org.bukkit.entity.Witch;
import org.bukkit.entity.Wither;
import org.bukkit.entity.WitherSkeleton;
import org.bukkit.entity.WitherSkull;
import org.bukkit.entity.Wolf;
import org.bukkit.entity.Zoglin;
import org.bukkit.entity.Zombie;
import org.bukkit.entity.ZombieHorse;
import org.bukkit.entity.ZombieVillager;
import org.bukkit.entity.minecart.CommandMinecart;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.entity.minecart.PoweredMinecart;
import org.bukkit.entity.minecart.SpawnerMinecart;
import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionData;
import org.bukkit.potion.PotionType;
import org.bukkit.util.Consumer;
import org.bukkit.util.Vector;
public abstract class CraftRegionAccessor implements RegionAccessor {
public abstract GeneratorAccessSeed getHandle();
public boolean isNormalWorld() {
return getHandle() instanceof net.minecraft.server.level.WorldServer;
}
@Override
public Biome getBiome(Location location) {
return getBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
@Override
public Biome getBiome(int x, int y, int z) {
return CraftBlock.biomeBaseToBiome(getHandle().t().d(IRegistry.BIOME_REGISTRY), getHandle().getBiome(x >> 2, y >> 2, z >> 2));
}
@Override
public void setBiome(Location location, Biome biome) {
setBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ(), biome);
}
@Override
public void setBiome(int x, int y, int z, Biome biome) {
Preconditions.checkArgument(biome != Biome.CUSTOM, "Cannot set the biome to %s", biome);
BiomeBase biomeBase = CraftBlock.biomeToBiomeBase(getHandle().t().d(IRegistry.BIOME_REGISTRY), biome);
setBiome(x, y, z, biomeBase);
}
public abstract void setBiome(int x, int y, int z, BiomeBase biomeBase);
@Override
public BlockState getBlockState(Location location) {
return getBlockState(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
@Override
public BlockState getBlockState(int x, int y, int z) {
return CraftBlock.at(getHandle(), new BlockPosition(x, y, z)).getState();
}
@Override
public BlockData getBlockData(Location location) {
return getBlockData(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
@Override
public BlockData getBlockData(int x, int y, int z) {
return CraftBlockData.fromData(getData(x, y, z));
}
@Override
public Material getType(Location location) {
return getType(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
@Override
public Material getType(int x, int y, int z) {
return CraftMagicNumbers.getMaterial(getData(x, y, z).getBlock());
}
private IBlockData getData(int x, int y, int z) {
return getHandle().getType(new BlockPosition(x, y, z));
}
@Override
public void setBlockData(Location location, BlockData blockData) {
setBlockData(location.getBlockX(), location.getBlockY(), location.getBlockZ(), blockData);
}
@Override
public void setBlockData(int x, int y, int z, BlockData blockData) {
getHandle().setTypeAndData(new BlockPosition(x, y, z), ((CraftBlockData) blockData).getState(), 3);
}
@Override
public void setType(Location location, Material material) {
setType(location.getBlockX(), location.getBlockY(), location.getBlockZ(), material);
}
@Override
public void setType(int x, int y, int z, Material material) {
setBlockData(x, y, z, material.createBlockData());
}
@Override
public boolean generateTree(Location location, Random random, TreeType treeType) {
BlockPosition pos = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ());
return generateTree(getHandle(), getHandle().getMinecraftWorld().getChunkProvider().generator, pos, random, treeType);
}
@Override
public boolean generateTree(Location location, Random random, TreeType treeType, Consumer<BlockState> consumer) {
BlockPosition pos = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ());
BlockStateListPopulator populator = new BlockStateListPopulator(getHandle());
boolean result = generateTree(populator, getHandle().getMinecraftWorld().getChunkProvider().generator, pos, random, treeType);
for (BlockState blockState : populator.getList()) {
if (consumer != null) {
consumer.accept(blockState);
}
blockState.update(true, true);
}
return result;
}
public boolean generateTree(GeneratorAccessSeed access, ChunkGenerator chunkGenerator, BlockPosition pos, Random random, TreeType treeType) {
net.minecraft.world.level.levelgen.feature.WorldGenFeatureConfigured gen;
switch (treeType) {
case BIG_TREE:
gen = BiomeDecoratorGroups.FANCY_OAK;
break;
case BIRCH:
gen = BiomeDecoratorGroups.BIRCH;
break;
case REDWOOD:
gen = BiomeDecoratorGroups.SPRUCE;
break;
case TALL_REDWOOD:
gen = BiomeDecoratorGroups.PINE;
break;
case JUNGLE:
gen = BiomeDecoratorGroups.MEGA_JUNGLE_TREE;
break;
case SMALL_JUNGLE:
gen = BiomeDecoratorGroups.JUNGLE_TREE_NO_VINE;
break;
case COCOA_TREE:
gen = BiomeDecoratorGroups.JUNGLE_TREE;
break;
case JUNGLE_BUSH:
gen = BiomeDecoratorGroups.JUNGLE_BUSH;
break;
case RED_MUSHROOM:
gen = BiomeDecoratorGroups.HUGE_RED_MUSHROOM;
break;
case BROWN_MUSHROOM:
gen = BiomeDecoratorGroups.HUGE_BROWN_MUSHROOM;
break;
case SWAMP:
gen = BiomeDecoratorGroups.SWAMP_OAK;
break;
case ACACIA:
gen = BiomeDecoratorGroups.ACACIA;
break;
case DARK_OAK:
gen = BiomeDecoratorGroups.DARK_OAK;
break;
case MEGA_REDWOOD:
gen = BiomeDecoratorGroups.MEGA_PINE;
break;
case TALL_BIRCH:
gen = BiomeDecoratorGroups.SUPER_BIRCH_BEES_0002;
break;
case CHORUS_PLANT:
((BlockChorusFlower) Blocks.CHORUS_FLOWER).a(access, pos, random, 8);
return true;
case CRIMSON_FUNGUS:
gen = BiomeDecoratorGroups.CRIMSON_FUNGI_PLANTED;
break;
case WARPED_FUNGUS:
gen = BiomeDecoratorGroups.WARPED_FUNGI_PLANTED;
break;
case AZALEA:
gen = BiomeDecoratorGroups.AZALEA_TREE;
break;
case TREE:
default:
gen = BiomeDecoratorGroups.OAK;
break;
}
return gen.feature.generate(new FeaturePlaceContext(access, chunkGenerator, random, pos, gen.config));
}
@Override
public Entity spawnEntity(Location location, EntityType entityType) {
return spawn(location, entityType.getEntityClass());
}
@Override
public List<Entity> getEntities() {
List<Entity> list = new ArrayList<Entity>();
getNMSEntities().forEach(entity -> {
Entity bukkitEntity = entity.getBukkitEntity();
// Assuming that bukkitEntity isn't null
if (bukkitEntity != null && (!isNormalWorld() || bukkitEntity.isValid())) {
list.add(bukkitEntity);
}
});
return list;
}
@Override
public List<LivingEntity> getLivingEntities() {
List<LivingEntity> list = new ArrayList<LivingEntity>();
getNMSEntities().forEach(entity -> {
Entity bukkitEntity = entity.getBukkitEntity();
// Assuming that bukkitEntity isn't null
if (bukkitEntity != null && bukkitEntity instanceof LivingEntity && (!isNormalWorld() || bukkitEntity.isValid())) {
list.add((LivingEntity) bukkitEntity);
}
});
return list;
}
@Override
@SuppressWarnings("unchecked")
public <T extends Entity> Collection<T> getEntitiesByClass(Class<T> clazz) {
Collection<T> list = new ArrayList<T>();
getNMSEntities().forEach(entity -> {
Entity bukkitEntity = entity.getBukkitEntity();
if (bukkitEntity == null) {
return;
}
Class<?> bukkitClass = bukkitEntity.getClass();
if (clazz.isAssignableFrom(bukkitClass) && (!isNormalWorld() || bukkitEntity.isValid())) {
list.add((T) bukkitEntity);
}
});
return list;
}
@Override
public Collection<Entity> getEntitiesByClasses(Class<?>... classes) {
Collection<Entity> list = new ArrayList<Entity>();
getNMSEntities().forEach(entity -> {
Entity bukkitEntity = entity.getBukkitEntity();
if (bukkitEntity == null) {
return;
}
Class<?> bukkitClass = bukkitEntity.getClass();
for (Class<?> clazz : classes) {
if (clazz.isAssignableFrom(bukkitClass)) {
if (!isNormalWorld() || bukkitEntity.isValid()) {
list.add(bukkitEntity);
}
break;
}
}
});
return list;
}
public abstract Iterable<net.minecraft.world.entity.Entity> getNMSEntities();
@Override
public <T extends Entity> T spawn(Location location, Class<T> clazz) throws IllegalArgumentException {
return spawn(location, clazz, null, CreatureSpawnEvent.SpawnReason.CUSTOM);
}
@Override
public <T extends Entity> T spawn(Location location, Class<T> clazz, Consumer<T> function) throws IllegalArgumentException {
return spawn(location, clazz, function, CreatureSpawnEvent.SpawnReason.CUSTOM);
}
public <T extends Entity> T spawn(Location location, Class<T> clazz, Consumer<T> function, CreatureSpawnEvent.SpawnReason reason) throws IllegalArgumentException {
net.minecraft.world.entity.Entity entity = createEntity(location, clazz);
return addEntity(entity, reason, function);
}
@SuppressWarnings("unchecked")
public <T extends Entity> T addEntity(net.minecraft.world.entity.Entity entity, CreatureSpawnEvent.SpawnReason reason) throws IllegalArgumentException {
return addEntity(entity, reason, null);
}
@SuppressWarnings("unchecked")
public <T extends Entity> T addEntity(net.minecraft.world.entity.Entity entity, CreatureSpawnEvent.SpawnReason reason, Consumer<T> function) throws IllegalArgumentException {
Preconditions.checkArgument(entity != null, "Cannot spawn null entity");
if (entity instanceof EntityInsentient) {
((EntityInsentient) entity).prepare(getHandle(), getHandle().getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.COMMAND, (GroupDataEntity) null, null);
}
if (!isNormalWorld()) {
entity.generation = true;
}
if (function != null) {
function.accept((T) entity.getBukkitEntity());
}
addEntityToWorld(entity, reason);
return (T) entity.getBukkitEntity();
}
public abstract void addEntityToWorld(net.minecraft.world.entity.Entity entity, CreatureSpawnEvent.SpawnReason reason);
@SuppressWarnings("unchecked")
public net.minecraft.world.entity.Entity createEntity(Location location, Class<? extends Entity> clazz) throws IllegalArgumentException {
if (location == null || clazz == null) {
throw new IllegalArgumentException("Location or entity class cannot be null");
}
net.minecraft.world.entity.Entity entity = null;
net.minecraft.world.level.World world = getHandle().getMinecraftWorld();
double x = location.getX();
double y = location.getY();
double z = location.getZ();
float pitch = location.getPitch();
float yaw = location.getYaw();
// order is important for some of these
if (Boat.class.isAssignableFrom(clazz)) {
entity = new EntityBoat(world, x, y, z);
entity.setPositionRotation(x, y, z, yaw, pitch);
} else if (FallingBlock.class.isAssignableFrom(clazz)) {
entity = new EntityFallingBlock(world, x, y, z, getHandle().getType(new BlockPosition(x, y, z)));
} else if (Projectile.class.isAssignableFrom(clazz)) {
if (Snowball.class.isAssignableFrom(clazz)) {
entity = new EntitySnowball(world, x, y, z);
} else if (Egg.class.isAssignableFrom(clazz)) {
entity = new EntityEgg(world, x, y, z);
} else if (AbstractArrow.class.isAssignableFrom(clazz)) {
if (TippedArrow.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ARROW.a(world);
((EntityTippedArrow) entity).setType(CraftPotionUtil.fromBukkit(new PotionData(PotionType.WATER, false, false)));
} else if (SpectralArrow.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SPECTRAL_ARROW.a(world);
} else if (Trident.class.isAssignableFrom(clazz)) {
entity = EntityTypes.TRIDENT.a(world);
} else {
entity = EntityTypes.ARROW.a(world);
}
entity.setPositionRotation(x, y, z, 0, 0);
} else if (ThrownExpBottle.class.isAssignableFrom(clazz)) {
entity = EntityTypes.EXPERIENCE_BOTTLE.a(world);
entity.setPositionRotation(x, y, z, 0, 0);
} else if (EnderPearl.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ENDER_PEARL.a(world);
entity.setPositionRotation(x, y, z, 0, 0);
} else if (ThrownPotion.class.isAssignableFrom(clazz)) {
if (LingeringPotion.class.isAssignableFrom(clazz)) {
entity = new EntityPotion(world, x, y, z);
((EntityPotion) entity).setItem(CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.LINGERING_POTION, 1)));
} else {
entity = new EntityPotion(world, x, y, z);
((EntityPotion) entity).setItem(CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.SPLASH_POTION, 1)));
}
} else if (Fireball.class.isAssignableFrom(clazz)) {
if (SmallFireball.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SMALL_FIREBALL.a(world);
} else if (WitherSkull.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WITHER_SKULL.a(world);
} else if (DragonFireball.class.isAssignableFrom(clazz)) {
entity = EntityTypes.DRAGON_FIREBALL.a(world);
} else {
entity = EntityTypes.FIREBALL.a(world);
}
entity.setPositionRotation(x, y, z, yaw, pitch);
Vector direction = location.getDirection().multiply(10);
((EntityFireball) entity).setDirection(direction.getX(), direction.getY(), direction.getZ());
} else if (ShulkerBullet.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SHULKER_BULLET.a(world);
entity.setPositionRotation(x, y, z, yaw, pitch);
} else if (LlamaSpit.class.isAssignableFrom(clazz)) {
entity = EntityTypes.LLAMA_SPIT.a(world);
entity.setPositionRotation(x, y, z, yaw, pitch);
} else if (Firework.class.isAssignableFrom(clazz)) {
entity = new EntityFireworks(world, x, y, z, net.minecraft.world.item.ItemStack.EMPTY);
}
} else if (Minecart.class.isAssignableFrom(clazz)) {
if (PoweredMinecart.class.isAssignableFrom(clazz)) {
entity = new EntityMinecartFurnace(world, x, y, z);
} else if (StorageMinecart.class.isAssignableFrom(clazz)) {
entity = new EntityMinecartChest(world, x, y, z);
} else if (ExplosiveMinecart.class.isAssignableFrom(clazz)) {
entity = new EntityMinecartTNT(world, x, y, z);
} else if (HopperMinecart.class.isAssignableFrom(clazz)) {
entity = new EntityMinecartHopper(world, x, y, z);
} else if (SpawnerMinecart.class.isAssignableFrom(clazz)) {
entity = new EntityMinecartMobSpawner(world, x, y, z);
} else if (CommandMinecart.class.isAssignableFrom(clazz)) {
entity = new EntityMinecartCommandBlock(world, x, y, z);
} else { // Default to rideable minecart for pre-rideable compatibility
entity = new EntityMinecartRideable(world, x, y, z);
}
} else if (EnderSignal.class.isAssignableFrom(clazz)) {
entity = new EntityEnderSignal(world, x, y, z);
} else if (EnderCrystal.class.isAssignableFrom(clazz)) {
entity = EntityTypes.END_CRYSTAL.a(world);
entity.setPositionRotation(x, y, z, 0, 0);
} else if (LivingEntity.class.isAssignableFrom(clazz)) {
if (Chicken.class.isAssignableFrom(clazz)) {
entity = EntityTypes.CHICKEN.a(world);
} else if (Cow.class.isAssignableFrom(clazz)) {
if (MushroomCow.class.isAssignableFrom(clazz)) {
entity = EntityTypes.MOOSHROOM.a(world);
} else {
entity = EntityTypes.COW.a(world);
}
} else if (Golem.class.isAssignableFrom(clazz)) {
if (Snowman.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SNOW_GOLEM.a(world);
} else if (IronGolem.class.isAssignableFrom(clazz)) {
entity = EntityTypes.IRON_GOLEM.a(world);
} else if (Shulker.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SHULKER.a(world);
}
} else if (Creeper.class.isAssignableFrom(clazz)) {
entity = EntityTypes.CREEPER.a(world);
} else if (Ghast.class.isAssignableFrom(clazz)) {
entity = EntityTypes.GHAST.a(world);
} else if (Pig.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PIG.a(world);
} else if (Player.class.isAssignableFrom(clazz)) {
// need a net server handler for this one
} else if (Sheep.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SHEEP.a(world);
} else if (AbstractHorse.class.isAssignableFrom(clazz)) {
if (ChestedHorse.class.isAssignableFrom(clazz)) {
if (Donkey.class.isAssignableFrom(clazz)) {
entity = EntityTypes.DONKEY.a(world);
} else if (Mule.class.isAssignableFrom(clazz)) {
entity = EntityTypes.MULE.a(world);
} else if (Llama.class.isAssignableFrom(clazz)) {
if (TraderLlama.class.isAssignableFrom(clazz)) {
entity = EntityTypes.TRADER_LLAMA.a(world);
} else {
entity = EntityTypes.LLAMA.a(world);
}
}
} else if (SkeletonHorse.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SKELETON_HORSE.a(world);
} else if (ZombieHorse.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ZOMBIE_HORSE.a(world);
} else {
entity = EntityTypes.HORSE.a(world);
}
} else if (AbstractSkeleton.class.isAssignableFrom(clazz)) {
if (Stray.class.isAssignableFrom(clazz)) {
entity = EntityTypes.STRAY.a(world);
} else if (WitherSkeleton.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WITHER_SKELETON.a(world);
} else if (Skeleton.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SKELETON.a(world);
}
} else if (Slime.class.isAssignableFrom(clazz)) {
if (MagmaCube.class.isAssignableFrom(clazz)) {
entity = EntityTypes.MAGMA_CUBE.a(world);
} else {
entity = EntityTypes.SLIME.a(world);
}
} else if (Spider.class.isAssignableFrom(clazz)) {
if (CaveSpider.class.isAssignableFrom(clazz)) {
entity = EntityTypes.CAVE_SPIDER.a(world);
} else {
entity = EntityTypes.SPIDER.a(world);
}
} else if (Squid.class.isAssignableFrom(clazz)) {
if (GlowSquid.class.isAssignableFrom(clazz)) {
entity = EntityTypes.GLOW_SQUID.a(world);
} else {
entity = EntityTypes.SQUID.a(world);
}
} else if (Tameable.class.isAssignableFrom(clazz)) {
if (Wolf.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WOLF.a(world);
} else if (Parrot.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PARROT.a(world);
} else if (Cat.class.isAssignableFrom(clazz)) {
entity = EntityTypes.CAT.a(world);
}
} else if (PigZombie.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ZOMBIFIED_PIGLIN.a(world);
} else if (Zombie.class.isAssignableFrom(clazz)) {
if (Husk.class.isAssignableFrom(clazz)) {
entity = EntityTypes.HUSK.a(world);
} else if (ZombieVillager.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ZOMBIE_VILLAGER.a(world);
} else if (Drowned.class.isAssignableFrom(clazz)) {
entity = EntityTypes.DROWNED.a(world);
} else {
entity = new EntityZombie(world);
}
} else if (Giant.class.isAssignableFrom(clazz)) {
entity = EntityTypes.GIANT.a(world);
} else if (Silverfish.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SILVERFISH.a(world);
} else if (Enderman.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ENDERMAN.a(world);
} else if (Blaze.class.isAssignableFrom(clazz)) {
entity = EntityTypes.BLAZE.a(world);
} else if (AbstractVillager.class.isAssignableFrom(clazz)) {
if (Villager.class.isAssignableFrom(clazz)) {
entity = EntityTypes.VILLAGER.a(world);
} else if (WanderingTrader.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WANDERING_TRADER.a(world);
}
} else if (Witch.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WITCH.a(world);
} else if (Wither.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WITHER.a(world);
} else if (ComplexLivingEntity.class.isAssignableFrom(clazz)) {
if (EnderDragon.class.isAssignableFrom(clazz)) {
if (isNormalWorld()) {
entity = EntityTypes.ENDER_DRAGON.a(getHandle().getMinecraftWorld());
} else {
throw new IllegalArgumentException("Cannot spawn entity " + clazz.getName() + " during world generation");
}
}
} else if (Ambient.class.isAssignableFrom(clazz)) {
if (Bat.class.isAssignableFrom(clazz)) {
entity = EntityTypes.BAT.a(world);
}
} else if (Rabbit.class.isAssignableFrom(clazz)) {
entity = EntityTypes.RABBIT.a(world);
} else if (Endermite.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ENDERMITE.a(world);
} else if (Guardian.class.isAssignableFrom(clazz)) {
if (ElderGuardian.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ELDER_GUARDIAN.a(world);
} else {
entity = EntityTypes.GUARDIAN.a(world);
}
} else if (ArmorStand.class.isAssignableFrom(clazz)) {
entity = new EntityArmorStand(world, x, y, z);
} else if (PolarBear.class.isAssignableFrom(clazz)) {
entity = EntityTypes.POLAR_BEAR.a(world);
} else if (Vex.class.isAssignableFrom(clazz)) {
entity = EntityTypes.VEX.a(world);
} else if (Illager.class.isAssignableFrom(clazz)) {
if (Spellcaster.class.isAssignableFrom(clazz)) {
if (Evoker.class.isAssignableFrom(clazz)) {
entity = EntityTypes.EVOKER.a(world);
} else if (Illusioner.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ILLUSIONER.a(world);
}
} else if (Vindicator.class.isAssignableFrom(clazz)) {
entity = EntityTypes.VINDICATOR.a(world);
} else if (Pillager.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PILLAGER.a(world);
}
} else if (Turtle.class.isAssignableFrom(clazz)) {
entity = EntityTypes.TURTLE.a(world);
} else if (Phantom.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PHANTOM.a(world);
} else if (Fish.class.isAssignableFrom(clazz)) {
if (Cod.class.isAssignableFrom(clazz)) {
entity = EntityTypes.COD.a(world);
} else if (PufferFish.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PUFFERFISH.a(world);
} else if (Salmon.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SALMON.a(world);
} else if (TropicalFish.class.isAssignableFrom(clazz)) {
entity = EntityTypes.TROPICAL_FISH.a(world);
}
} else if (Dolphin.class.isAssignableFrom(clazz)) {
entity = EntityTypes.DOLPHIN.a(world);
} else if (Ocelot.class.isAssignableFrom(clazz)) {
entity = EntityTypes.OCELOT.a(world);
} else if (Ravager.class.isAssignableFrom(clazz)) {
entity = EntityTypes.RAVAGER.a(world);
} else if (Panda.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PANDA.a(world);
} else if (Fox.class.isAssignableFrom(clazz)) {
entity = EntityTypes.FOX.a(world);
} else if (Bee.class.isAssignableFrom(clazz)) {
entity = EntityTypes.BEE.a(world);
} else if (Hoglin.class.isAssignableFrom(clazz)) {
entity = EntityTypes.HOGLIN.a(world);
} else if (Piglin.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PIGLIN.a(world);
} else if (PiglinBrute.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PIGLIN_BRUTE.a(world);
} else if (Strider.class.isAssignableFrom(clazz)) {
entity = EntityTypes.STRIDER.a(world);
} else if (Zoglin.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ZOGLIN.a(world);
} else if (Axolotl.class.isAssignableFrom(clazz)) {
entity = EntityTypes.AXOLOTL.a(world);
} else if (Goat.class.isAssignableFrom(clazz)) {
entity = EntityTypes.GOAT.a(world);
}
if (entity != null) {
entity.setLocation(x, y, z, yaw, pitch);
entity.setHeadRotation(yaw); // SPIGOT-3587
}
} else if (Hanging.class.isAssignableFrom(clazz)) {
BlockFace face = BlockFace.SELF;
int width = 16; // 1 full block, also painting smallest size.
int height = 16; // 1 full block, also painting smallest size.
if (ItemFrame.class.isAssignableFrom(clazz)) {
width = 12;
height = 12;
} else if (LeashHitch.class.isAssignableFrom(clazz)) {
width = 9;
height = 9;
}
BlockFace[] faces = new BlockFace[]{BlockFace.EAST, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN};
final BlockPosition pos = new BlockPosition(x, y, z);
for (BlockFace dir : faces) {
IBlockData nmsBlock = getHandle().getType(pos.shift(CraftBlock.blockFaceToNotch(dir)));
if (nmsBlock.getMaterial().isBuildable() || BlockDiodeAbstract.isDiode(nmsBlock)) {
boolean taken = false;
AxisAlignedBB bb = (ItemFrame.class.isAssignableFrom(clazz))
? EntityItemFrame.calculateBoundingBox(null, pos, CraftBlock.blockFaceToNotch(dir).opposite(), width, height)
: EntityHanging.calculateBoundingBox(null, pos, CraftBlock.blockFaceToNotch(dir).opposite(), width, height);
List<net.minecraft.world.entity.Entity> list = (List<net.minecraft.world.entity.Entity>) getHandle().getEntities(null, bb);
for (Iterator<net.minecraft.world.entity.Entity> it = list.iterator(); !taken && it.hasNext();) {
net.minecraft.world.entity.Entity e = it.next();
if (e instanceof EntityHanging) {
taken = true; // Hanging entities do not like hanging entities which intersect them.
}
}
if (!taken) {
face = dir;
break;
}
}
}
if (LeashHitch.class.isAssignableFrom(clazz)) {
entity = new EntityLeash(world, new BlockPosition(x, y, z));
} else {
// No valid face found
Preconditions.checkArgument(face != BlockFace.SELF, "Cannot spawn hanging entity for %s at %s (no free face)", clazz.getName(), location);
EnumDirection dir = CraftBlock.blockFaceToNotch(face).opposite();
if (Painting.class.isAssignableFrom(clazz)) {
if (isNormalWorld()) {
entity = new EntityPainting(getHandle().getMinecraftWorld(), new BlockPosition(x, y, z), dir);
} else {
entity = new EntityPainting(EntityTypes.PAINTING, getHandle().getMinecraftWorld());
entity.setLocation(x, y, z, yaw, pitch);
((EntityPainting) entity).setDirection(dir);
}
} else if (ItemFrame.class.isAssignableFrom(clazz)) {
if (GlowItemFrame.class.isAssignableFrom(clazz)) {
entity = new net.minecraft.world.entity.decoration.GlowItemFrame(world, new BlockPosition(x, y, z), dir);
} else {
entity = new EntityItemFrame(world, new BlockPosition(x, y, z), dir);
}
}
}
// survives call does not work during world generation
if (entity != null && isNormalWorld() && !((EntityHanging) entity).survives()) {
throw new IllegalArgumentException("Cannot spawn hanging entity for " + clazz.getName() + " at " + location);
}
} else if (TNTPrimed.class.isAssignableFrom(clazz)) {
entity = new EntityTNTPrimed(world, x, y, z, null);
} else if (ExperienceOrb.class.isAssignableFrom(clazz)) {
entity = new EntityExperienceOrb(world, x, y, z, 0);
} else if (LightningStrike.class.isAssignableFrom(clazz)) {
entity = EntityTypes.LIGHTNING_BOLT.a(world);
entity.teleportAndSync(location.getX(), location.getY(), location.getZ());
} else if (AreaEffectCloud.class.isAssignableFrom(clazz)) {
entity = new EntityAreaEffectCloud(world, x, y, z);
} else if (EvokerFangs.class.isAssignableFrom(clazz)) {
entity = new EntityEvokerFangs(world, x, y, z, (float) Math.toRadians(yaw), 0, null);
} else if (Marker.class.isAssignableFrom(clazz)) {
entity = EntityTypes.MARKER.a(world);
entity.setPosition(x, y, z);
}
if (entity != null) {
return entity;
}
throw new IllegalArgumentException("Cannot spawn an entity for " + clazz.getName());
}
}

View File

@ -100,9 +100,11 @@ import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.MobSpawner; import net.minecraft.world.level.MobSpawner;
import net.minecraft.world.level.WorldSettings; import net.minecraft.world.level.WorldSettings;
import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.biome.WorldChunkManager;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.dimension.DimensionManager; import net.minecraft.world.level.dimension.DimensionManager;
import net.minecraft.world.level.dimension.WorldDimension; import net.minecraft.world.level.dimension.WorldDimension;
import net.minecraft.world.level.levelgen.ChunkGeneratorAbstract;
import net.minecraft.world.level.levelgen.GeneratorSettings; import net.minecraft.world.level.levelgen.GeneratorSettings;
import net.minecraft.world.level.levelgen.MobSpawnerPatrol; import net.minecraft.world.level.levelgen.MobSpawnerPatrol;
import net.minecraft.world.level.levelgen.MobSpawnerPhantom; import net.minecraft.world.level.levelgen.MobSpawnerPhantom;
@ -154,7 +156,9 @@ import org.bukkit.craftbukkit.command.CraftCommandMap;
import org.bukkit.craftbukkit.command.VanillaCommandWrapper; import org.bukkit.craftbukkit.command.VanillaCommandWrapper;
import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.event.CraftEventFactory; import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.craftbukkit.generator.CraftChunkData; import org.bukkit.craftbukkit.generator.CraftWorldInfo;
import org.bukkit.craftbukkit.generator.CustomWorldChunkManager;
import org.bukkit.craftbukkit.generator.OldCraftChunkData;
import org.bukkit.craftbukkit.help.SimpleHelpMap; import org.bukkit.craftbukkit.help.SimpleHelpMap;
import org.bukkit.craftbukkit.inventory.CraftBlastingRecipe; import org.bukkit.craftbukkit.inventory.CraftBlastingRecipe;
import org.bukkit.craftbukkit.inventory.CraftCampfireRecipe; import org.bukkit.craftbukkit.inventory.CraftCampfireRecipe;
@ -196,7 +200,9 @@ import org.bukkit.event.server.ServerLoadEvent;
import org.bukkit.event.server.TabCompleteEvent; import org.bukkit.event.server.TabCompleteEvent;
import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent; import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.WorldInfo;
import org.bukkit.help.HelpMap; import org.bukkit.help.HelpMap;
import org.bukkit.inventory.BlastingRecipe; import org.bukkit.inventory.BlastingRecipe;
import org.bukkit.inventory.CampfireRecipe; import org.bukkit.inventory.CampfireRecipe;
@ -956,6 +962,7 @@ public final class CraftServer implements Server {
String name = creator.name(); String name = creator.name();
ChunkGenerator generator = creator.generator(); ChunkGenerator generator = creator.generator();
BiomeProvider biomeProvider = creator.biomeProvider();
File folder = new File(getWorldContainer(), name); File folder = new File(getWorldContainer(), name);
World world = getWorld(name); World world = getWorld(name);
@ -971,6 +978,10 @@ public final class CraftServer implements Server {
generator = getGenerator(name); generator = getGenerator(name);
} }
if (biomeProvider == null) {
biomeProvider = getBiomeProvider(name);
}
ResourceKey<WorldDimension> actualDimension; ResourceKey<WorldDimension> actualDimension;
switch (creator.environment()) { switch (creator.environment()) {
case NORMAL: case NORMAL:
@ -1038,6 +1049,18 @@ public final class CraftServer implements Server {
chunkgenerator = worlddimension.c(); chunkgenerator = worlddimension.c();
} }
WorldInfo worldInfo = new CraftWorldInfo(worlddata, worldSession, creator.environment(), dimensionmanager);
if (biomeProvider == null && generator != null) {
biomeProvider = generator.getDefaultBiomeProvider(worldInfo);
}
if (biomeProvider != null) {
WorldChunkManager worldChunkManager = new CustomWorldChunkManager(worldInfo, biomeProvider, console.registryHolder.b(IRegistry.BIOME_REGISTRY));
if (chunkgenerator instanceof ChunkGeneratorAbstract) {
chunkgenerator = new ChunkGeneratorAbstract(worldChunkManager, chunkgenerator.strongholdSeed, ((ChunkGeneratorAbstract) chunkgenerator).settings);
}
}
ResourceKey<net.minecraft.world.level.World> worldKey; ResourceKey<net.minecraft.world.level.World> worldKey;
String levelName = this.getServer().getDedicatedServerProperties().levelName; String levelName = this.getServer().getDedicatedServerProperties().levelName;
if (name.equals(levelName + "_nether")) { if (name.equals(levelName + "_nether")) {
@ -1049,7 +1072,7 @@ public final class CraftServer implements Server {
} }
WorldServer internal = (WorldServer) new WorldServer(console, console.executor, worldSession, worlddata, worldKey, dimensionmanager, getServer().progressListenerFactory.create(11), WorldServer internal = (WorldServer) new WorldServer(console, console.executor, worldSession, worlddata, worldKey, dimensionmanager, getServer().progressListenerFactory.create(11),
chunkgenerator, worlddata.getGeneratorSettings().isDebugWorld(), j, creator.environment() == Environment.NORMAL ? list : ImmutableList.of(), true, creator.environment(), generator); chunkgenerator, worlddata.getGeneratorSettings().isDebugWorld(), j, creator.environment() == Environment.NORMAL ? list : ImmutableList.of(), true, creator.environment(), generator, biomeProvider);
if (!(worlds.containsKey(name.toLowerCase(java.util.Locale.ENGLISH)))) { if (!(worlds.containsKey(name.toLowerCase(java.util.Locale.ENGLISH)))) {
return null; return null;
@ -1424,6 +1447,42 @@ public final class CraftServer implements Server {
return result; return result;
} }
public BiomeProvider getBiomeProvider(String world) {
ConfigurationSection section = configuration.getConfigurationSection("worlds");
BiomeProvider result = null;
if (section != null) {
section = section.getConfigurationSection(world);
if (section != null) {
String name = section.getString("biome-provider");
if ((name != null) && (!name.equals(""))) {
String[] split = name.split(":", 2);
String id = (split.length > 1) ? split[1] : null;
Plugin plugin = pluginManager.getPlugin(split[0]);
if (plugin == null) {
getLogger().severe("Could not set biome provider for default world '" + world + "': Plugin '" + split[0] + "' does not exist");
} else if (!plugin.isEnabled()) {
getLogger().severe("Could not set biome provider for default world '" + world + "': Plugin '" + plugin.getDescription().getFullName() + "' is not enabled yet (is it load:STARTUP?)");
} else {
try {
result = plugin.getDefaultBiomeProvider(world, id);
if (result == null) {
getLogger().severe("Could not set biome provider for default world '" + world + "': Plugin '" + plugin.getDescription().getFullName() + "' lacks a default world biome provider");
}
} catch (Throwable t) {
plugin.getLogger().log(Level.SEVERE, "Could not set biome provider for default world '" + world + "': Plugin '" + plugin.getDescription().getFullName(), t);
}
}
}
}
}
return result;
}
@Override @Override
@Deprecated @Deprecated
public CraftMapView getMap(int id) { public CraftMapView getMap(int id) {
@ -1919,7 +1978,7 @@ public final class CraftServer implements Server {
@Override @Override
public ChunkGenerator.ChunkData createChunkData(World world) { public ChunkGenerator.ChunkData createChunkData(World world) {
Validate.notNull(world, "World cannot be null"); Validate.notNull(world, "World cannot be null");
return new CraftChunkData(world); return new OldCraftChunkData(world);
} }
@Override @Override

View File

@ -13,7 +13,6 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -23,9 +22,6 @@ import java.util.UUID;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import net.minecraft.core.BlockPosition; import net.minecraft.core.BlockPosition;
import net.minecraft.core.EnumDirection;
import net.minecraft.core.IRegistry;
import net.minecraft.data.worldgen.BiomeDecoratorGroups;
import net.minecraft.network.protocol.game.PacketPlayOutCustomSoundEffect; import net.minecraft.network.protocol.game.PacketPlayOutCustomSoundEffect;
import net.minecraft.network.protocol.game.PacketPlayOutUpdateTime; import net.minecraft.network.protocol.game.PacketPlayOutUpdateTime;
import net.minecraft.network.protocol.game.PacketPlayOutWorldEvent; import net.minecraft.network.protocol.game.PacketPlayOutWorldEvent;
@ -39,54 +35,23 @@ import net.minecraft.sounds.SoundCategory;
import net.minecraft.util.ArraySetSorted; import net.minecraft.util.ArraySetSorted;
import net.minecraft.util.Unit; import net.minecraft.util.Unit;
import net.minecraft.world.EnumDifficulty; import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.entity.EntityAreaEffectCloud;
import net.minecraft.world.entity.EntityExperienceOrb;
import net.minecraft.world.entity.EntityInsentient;
import net.minecraft.world.entity.EntityLightning; import net.minecraft.world.entity.EntityLightning;
import net.minecraft.world.entity.EntityTypes; import net.minecraft.world.entity.EntityTypes;
import net.minecraft.world.entity.EnumMobSpawn;
import net.minecraft.world.entity.GroupDataEntity;
import net.minecraft.world.entity.decoration.EntityArmorStand;
import net.minecraft.world.entity.decoration.EntityHanging;
import net.minecraft.world.entity.decoration.EntityItemFrame;
import net.minecraft.world.entity.decoration.EntityLeash;
import net.minecraft.world.entity.decoration.EntityPainting;
import net.minecraft.world.entity.item.EntityFallingBlock; import net.minecraft.world.entity.item.EntityFallingBlock;
import net.minecraft.world.entity.item.EntityItem; import net.minecraft.world.entity.item.EntityItem;
import net.minecraft.world.entity.item.EntityTNTPrimed;
import net.minecraft.world.entity.monster.EntityZombie;
import net.minecraft.world.entity.player.EntityHuman; import net.minecraft.world.entity.player.EntityHuman;
import net.minecraft.world.entity.projectile.EntityArrow; import net.minecraft.world.entity.projectile.EntityArrow;
import net.minecraft.world.entity.projectile.EntityEgg;
import net.minecraft.world.entity.projectile.EntityEnderSignal;
import net.minecraft.world.entity.projectile.EntityEvokerFangs;
import net.minecraft.world.entity.projectile.EntityFireball;
import net.minecraft.world.entity.projectile.EntityFireworks;
import net.minecraft.world.entity.projectile.EntityPotion;
import net.minecraft.world.entity.projectile.EntitySnowball;
import net.minecraft.world.entity.projectile.EntityTippedArrow; import net.minecraft.world.entity.projectile.EntityTippedArrow;
import net.minecraft.world.entity.raid.PersistentRaid; import net.minecraft.world.entity.raid.PersistentRaid;
import net.minecraft.world.entity.vehicle.EntityBoat;
import net.minecraft.world.entity.vehicle.EntityMinecartChest;
import net.minecraft.world.entity.vehicle.EntityMinecartCommandBlock;
import net.minecraft.world.entity.vehicle.EntityMinecartFurnace;
import net.minecraft.world.entity.vehicle.EntityMinecartHopper;
import net.minecraft.world.entity.vehicle.EntityMinecartMobSpawner;
import net.minecraft.world.entity.vehicle.EntityMinecartRideable;
import net.minecraft.world.entity.vehicle.EntityMinecartTNT;
import net.minecraft.world.level.ChunkCoordIntPair; import net.minecraft.world.level.ChunkCoordIntPair;
import net.minecraft.world.level.Explosion; import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.GameRules; import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.RayTrace; import net.minecraft.world.level.RayTrace;
import net.minecraft.world.level.biome.BiomeBase; import net.minecraft.world.level.biome.BiomeBase;
import net.minecraft.world.level.block.BlockChorusFlower;
import net.minecraft.world.level.block.BlockDiodeAbstract;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.IBlockData;
import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.IChunkAccess; import net.minecraft.world.level.chunk.IChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunkExtension; import net.minecraft.world.level.chunk.ProtoChunkExtension;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.StructureGenerator; import net.minecraft.world.level.levelgen.feature.StructureGenerator;
import net.minecraft.world.level.storage.SavedFile; import net.minecraft.world.level.storage.SavedFile;
import net.minecraft.world.phys.AxisAlignedBB; import net.minecraft.world.phys.AxisAlignedBB;
@ -108,16 +73,13 @@ import org.bukkit.Sound;
import org.bukkit.StructureType; import org.bukkit.StructureType;
import org.bukkit.TreeType; import org.bukkit.TreeType;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.WorldBorder; import org.bukkit.WorldBorder;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.boss.DragonBattle; import org.bukkit.boss.DragonBattle;
import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.craftbukkit.block.CraftBlockState;
import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.boss.CraftDragonBattle; import org.bukkit.craftbukkit.boss.CraftDragonBattle;
import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftEntity;
@ -128,139 +90,20 @@ import org.bukkit.craftbukkit.potion.CraftPotionUtil;
import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.craftbukkit.util.CraftRayTraceResult; import org.bukkit.craftbukkit.util.CraftRayTraceResult;
import org.bukkit.entity.AbstractArrow; import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.AbstractSkeleton;
import org.bukkit.entity.AbstractVillager;
import org.bukkit.entity.Ambient;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Arrow; import org.bukkit.entity.Arrow;
import org.bukkit.entity.Axolotl;
import org.bukkit.entity.Bat;
import org.bukkit.entity.Bee;
import org.bukkit.entity.Blaze;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Cat;
import org.bukkit.entity.CaveSpider;
import org.bukkit.entity.ChestedHorse;
import org.bukkit.entity.Chicken;
import org.bukkit.entity.Cod;
import org.bukkit.entity.ComplexLivingEntity;
import org.bukkit.entity.Cow;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Donkey;
import org.bukkit.entity.DragonFireball;
import org.bukkit.entity.Drowned;
import org.bukkit.entity.Egg;
import org.bukkit.entity.ElderGuardian;
import org.bukkit.entity.EnderCrystal;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.EnderPearl;
import org.bukkit.entity.EnderSignal;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Endermite;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Evoker;
import org.bukkit.entity.EvokerFangs;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.FallingBlock; import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Fireball;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Fish;
import org.bukkit.entity.Fox;
import org.bukkit.entity.Ghast;
import org.bukkit.entity.Giant;
import org.bukkit.entity.GlowItemFrame;
import org.bukkit.entity.GlowSquid;
import org.bukkit.entity.Goat;
import org.bukkit.entity.Golem;
import org.bukkit.entity.Guardian;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.Hoglin;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Husk;
import org.bukkit.entity.Illager;
import org.bukkit.entity.Illusioner;
import org.bukkit.entity.IronGolem;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LeashHitch;
import org.bukkit.entity.LightningStrike; import org.bukkit.entity.LightningStrike;
import org.bukkit.entity.LingeringPotion;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Llama;
import org.bukkit.entity.LlamaSpit;
import org.bukkit.entity.MagmaCube;
import org.bukkit.entity.Marker;
import org.bukkit.entity.Minecart;
import org.bukkit.entity.Mule;
import org.bukkit.entity.MushroomCow;
import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Painting;
import org.bukkit.entity.Panda;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.Phantom;
import org.bukkit.entity.Pig;
import org.bukkit.entity.PigZombie;
import org.bukkit.entity.Piglin;
import org.bukkit.entity.PiglinBrute;
import org.bukkit.entity.Pillager;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.PolarBear;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.PufferFish;
import org.bukkit.entity.Rabbit;
import org.bukkit.entity.Ravager;
import org.bukkit.entity.Salmon;
import org.bukkit.entity.Sheep;
import org.bukkit.entity.Shulker;
import org.bukkit.entity.ShulkerBullet;
import org.bukkit.entity.Silverfish;
import org.bukkit.entity.Skeleton;
import org.bukkit.entity.SkeletonHorse;
import org.bukkit.entity.Slime;
import org.bukkit.entity.SmallFireball;
import org.bukkit.entity.Snowball;
import org.bukkit.entity.Snowman;
import org.bukkit.entity.SpectralArrow; import org.bukkit.entity.SpectralArrow;
import org.bukkit.entity.Spellcaster;
import org.bukkit.entity.Spider;
import org.bukkit.entity.Squid;
import org.bukkit.entity.Stray;
import org.bukkit.entity.Strider;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.ThrownExpBottle;
import org.bukkit.entity.ThrownPotion;
import org.bukkit.entity.TippedArrow; import org.bukkit.entity.TippedArrow;
import org.bukkit.entity.TraderLlama;
import org.bukkit.entity.Trident; import org.bukkit.entity.Trident;
import org.bukkit.entity.TropicalFish;
import org.bukkit.entity.Turtle;
import org.bukkit.entity.Vex;
import org.bukkit.entity.Villager;
import org.bukkit.entity.Vindicator;
import org.bukkit.entity.WanderingTrader;
import org.bukkit.entity.Witch;
import org.bukkit.entity.Wither;
import org.bukkit.entity.WitherSkeleton;
import org.bukkit.entity.WitherSkull;
import org.bukkit.entity.Wolf;
import org.bukkit.entity.Zoglin;
import org.bukkit.entity.Zombie;
import org.bukkit.entity.ZombieHorse;
import org.bukkit.entity.ZombieVillager;
import org.bukkit.entity.minecart.CommandMinecart;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.entity.minecart.PoweredMinecart;
import org.bukkit.entity.minecart.SpawnerMinecart;
import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.event.weather.LightningStrikeEvent; import org.bukkit.event.weather.LightningStrikeEvent;
import org.bukkit.event.world.SpawnChangeEvent; import org.bukkit.event.world.SpawnChangeEvent;
import org.bukkit.event.world.TimeSkipEvent; import org.bukkit.event.world.TimeSkipEvent;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -275,7 +118,7 @@ import org.bukkit.util.Consumer;
import org.bukkit.util.RayTraceResult; import org.bukkit.util.RayTraceResult;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
public class CraftWorld implements World { public class CraftWorld extends CraftRegionAccessor implements World {
public static final int CUSTOM_DIMENSION_OFFSET = 10; public static final int CUSTOM_DIMENSION_OFFSET = 10;
private final WorldServer world; private final WorldServer world;
@ -283,6 +126,7 @@ public class CraftWorld implements World {
private Environment environment; private Environment environment;
private final CraftServer server = (CraftServer) Bukkit.getServer(); private final CraftServer server = (CraftServer) Bukkit.getServer();
private final ChunkGenerator generator; private final ChunkGenerator generator;
private final BiomeProvider biomeProvider;
private final List<BlockPopulator> populators = new ArrayList<BlockPopulator>(); private final List<BlockPopulator> populators = new ArrayList<BlockPopulator>();
private final BlockMetadataStore blockMetadata = new BlockMetadataStore(this); private final BlockMetadataStore blockMetadata = new BlockMetadataStore(this);
private int monsterSpawn = -1; private int monsterSpawn = -1;
@ -293,9 +137,10 @@ public class CraftWorld implements World {
private static final Random rand = new Random(); private static final Random rand = new Random();
public CraftWorld(WorldServer world, ChunkGenerator gen, Environment env) { public CraftWorld(WorldServer world, ChunkGenerator gen, BiomeProvider biomeProvider, Environment env) {
this.world = world; this.world = world;
this.generator = gen; this.generator = gen;
this.biomeProvider = biomeProvider;
environment = env; environment = env;
} }
@ -666,11 +511,6 @@ public class CraftWorld implements World {
return (T) arrow.getBukkitEntity(); return (T) arrow.getBukkitEntity();
} }
@Override
public Entity spawnEntity(Location loc, EntityType entityType) {
return spawn(loc, entityType.getEntityClass());
}
@Override @Override
public LightningStrike strikeLightning(Location loc) { public LightningStrike strikeLightning(Location loc) {
EntityLightning lightning = EntityTypes.LIGHTNING_BOLT.a(world); EntityLightning lightning = EntityTypes.LIGHTNING_BOLT.a(world);
@ -690,74 +530,7 @@ public class CraftWorld implements World {
@Override @Override
public boolean generateTree(Location loc, TreeType type) { public boolean generateTree(Location loc, TreeType type) {
BlockPosition pos = new BlockPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); return generateTree(loc, rand, type);
net.minecraft.world.level.levelgen.feature.WorldGenFeatureConfigured gen;
switch (type) {
case BIG_TREE:
gen = BiomeDecoratorGroups.FANCY_OAK;
break;
case BIRCH:
gen = BiomeDecoratorGroups.BIRCH;
break;
case REDWOOD:
gen = BiomeDecoratorGroups.SPRUCE;
break;
case TALL_REDWOOD:
gen = BiomeDecoratorGroups.PINE;
break;
case JUNGLE:
gen = BiomeDecoratorGroups.MEGA_JUNGLE_TREE;
break;
case SMALL_JUNGLE:
gen = BiomeDecoratorGroups.JUNGLE_TREE_NO_VINE;
break;
case COCOA_TREE:
gen = BiomeDecoratorGroups.JUNGLE_TREE;
break;
case JUNGLE_BUSH:
gen = BiomeDecoratorGroups.JUNGLE_BUSH;
break;
case RED_MUSHROOM:
gen = BiomeDecoratorGroups.HUGE_RED_MUSHROOM;
break;
case BROWN_MUSHROOM:
gen = BiomeDecoratorGroups.HUGE_BROWN_MUSHROOM;
break;
case SWAMP:
gen = BiomeDecoratorGroups.SWAMP_OAK;
break;
case ACACIA:
gen = BiomeDecoratorGroups.ACACIA;
break;
case DARK_OAK:
gen = BiomeDecoratorGroups.DARK_OAK;
break;
case MEGA_REDWOOD:
gen = BiomeDecoratorGroups.MEGA_PINE;
break;
case TALL_BIRCH:
gen = BiomeDecoratorGroups.SUPER_BIRCH_BEES_0002;
break;
case CHORUS_PLANT:
((BlockChorusFlower) Blocks.CHORUS_FLOWER).a(world, pos, rand, 8);
return true;
case CRIMSON_FUNGUS:
gen = BiomeDecoratorGroups.CRIMSON_FUNGI_PLANTED;
break;
case WARPED_FUNGUS:
gen = BiomeDecoratorGroups.WARPED_FUNGI_PLANTED;
break;
case AZALEA:
gen = BiomeDecoratorGroups.AZALEA_TREE;
break;
case TREE:
default:
gen = BiomeDecoratorGroups.OAK;
break;
}
return gen.feature.generate(new FeaturePlaceContext(world, world.getChunkProvider().getChunkGenerator(), rand, pos, gen.config));
} }
@Override @Override
@ -904,6 +677,11 @@ public class CraftWorld implements World {
return generator; return generator;
} }
@Override
public BiomeProvider getBiomeProvider() {
return biomeProvider;
}
@Override @Override
public List<BlockPopulator> getPopulators() { public List<BlockPopulator> getPopulators() {
return populators; return populators;
@ -945,11 +723,6 @@ public class CraftWorld implements World {
return getBiome(x, 0, z); return getBiome(x, 0, z);
} }
@Override
public Biome getBiome(int x, int y, int z) {
return CraftBlock.biomeBaseToBiome(getHandle().t().d(IRegistry.BIOME_REGISTRY), this.world.getBiome(x >> 2, y >> 2, z >> 2));
}
@Override @Override
public void setBiome(int x, int z, Biome bio) { public void setBiome(int x, int z, Biome bio) {
for (int y = 0; y < getMaxHeight(); y++) { for (int y = 0; y < getMaxHeight(); y++) {
@ -958,9 +731,7 @@ public class CraftWorld implements World {
} }
@Override @Override
public void setBiome(int x, int y, int z, Biome bio) { public void setBiome(int x, int y, int z, BiomeBase bb) {
Preconditions.checkArgument(bio != Biome.CUSTOM, "Cannot set the biome to %s", bio);
BiomeBase bb = CraftBlock.biomeToBiomeBase(getHandle().t().d(IRegistry.BIOME_REGISTRY), bio);
BlockPosition pos = new BlockPosition(x, 0, z); BlockPosition pos = new BlockPosition(x, 0, z);
if (this.world.isLoaded(pos)) { if (this.world.isLoaded(pos)) {
net.minecraft.world.level.chunk.Chunk chunk = this.world.getChunkAtWorldCoords(pos); net.minecraft.world.level.chunk.Chunk chunk = this.world.getChunkAtWorldCoords(pos);
@ -994,38 +765,6 @@ public class CraftWorld implements World {
return this.world.getBiome(x >> 2, y >> 2, z >> 2).getHumidity(); return this.world.getBiome(x >> 2, y >> 2, z >> 2).getHumidity();
} }
@Override
public List<Entity> getEntities() {
List<Entity> list = new ArrayList<Entity>();
world.getEntities().a().forEach((mcEnt) -> {
Entity bukkitEntity = mcEnt.getBukkitEntity();
// Assuming that bukkitEntity isn't null
if (bukkitEntity != null && bukkitEntity.isValid()) {
list.add(bukkitEntity);
}
});
return list;
}
@Override
public List<LivingEntity> getLivingEntities() {
List<LivingEntity> list = new ArrayList<LivingEntity>();
world.getEntities().a().forEach((mcEnt) -> {
Entity bukkitEntity = mcEnt.getBukkitEntity();
// Assuming that bukkitEntity isn't null
if (bukkitEntity != null && bukkitEntity instanceof LivingEntity && bukkitEntity.isValid()) {
list.add((LivingEntity) bukkitEntity);
}
});
return list;
}
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Deprecated @Deprecated
@ -1034,51 +773,13 @@ public class CraftWorld implements World {
} }
@Override @Override
@SuppressWarnings("unchecked") public Iterable<net.minecraft.world.entity.Entity> getNMSEntities() {
public <T extends Entity> Collection<T> getEntitiesByClass(Class<T> clazz) { return getHandle().getEntities().a();
Collection<T> list = new ArrayList<T>();
world.getEntities().a().forEach((entity) -> {
Entity bukkitEntity = ((net.minecraft.world.entity.Entity) entity).getBukkitEntity();
if (bukkitEntity == null) {
return;
}
Class<?> bukkitClass = bukkitEntity.getClass();
if (clazz.isAssignableFrom(bukkitClass) && bukkitEntity.isValid()) {
list.add((T) bukkitEntity);
}
});
return list;
} }
@Override @Override
public Collection<Entity> getEntitiesByClasses(Class<?>... classes) { public void addEntityToWorld(net.minecraft.world.entity.Entity entity, SpawnReason reason) {
Collection<Entity> list = new ArrayList<Entity>(); getHandle().addEntity(entity, reason);
world.getEntities().a().forEach((entity) -> {
Entity bukkitEntity = ((net.minecraft.world.entity.Entity) entity).getBukkitEntity();
if (bukkitEntity == null) {
return;
}
Class<?> bukkitClass = bukkitEntity.getClass();
for (Class<?> clazz : classes) {
if (clazz.isAssignableFrom(bukkitClass)) {
if (bukkitEntity.isValid()) {
list.add(bukkitEntity);
}
break;
}
}
});
return list;
} }
@Override @Override
@ -1410,16 +1111,6 @@ public class CraftWorld implements World {
} }
} }
@Override
public <T extends Entity> T spawn(Location location, Class<T> clazz) throws IllegalArgumentException {
return spawn(location, clazz, null, SpawnReason.CUSTOM);
}
@Override
public <T extends Entity> T spawn(Location location, Class<T> clazz, Consumer<T> function) throws IllegalArgumentException {
return spawn(location, clazz, function, SpawnReason.CUSTOM);
}
@Override @Override
public FallingBlock spawnFallingBlock(Location location, MaterialData data) throws IllegalArgumentException { public FallingBlock spawnFallingBlock(Location location, MaterialData data) throws IllegalArgumentException {
Validate.notNull(data, "MaterialData cannot be null"); Validate.notNull(data, "MaterialData cannot be null");
@ -1451,401 +1142,6 @@ public class CraftWorld implements World {
return (FallingBlock) entity.getBukkitEntity(); return (FallingBlock) entity.getBukkitEntity();
} }
@SuppressWarnings("unchecked")
public net.minecraft.world.entity.Entity createEntity(Location location, Class<? extends Entity> clazz) throws IllegalArgumentException {
if (location == null || clazz == null) {
throw new IllegalArgumentException("Location or entity class cannot be null");
}
net.minecraft.world.entity.Entity entity = null;
double x = location.getX();
double y = location.getY();
double z = location.getZ();
float pitch = location.getPitch();
float yaw = location.getYaw();
// order is important for some of these
if (Boat.class.isAssignableFrom(clazz)) {
entity = new EntityBoat(world, x, y, z);
entity.setPositionRotation(x, y, z, yaw, pitch);
} else if (FallingBlock.class.isAssignableFrom(clazz)) {
entity = new EntityFallingBlock(world, x, y, z, world.getType(new BlockPosition(x, y, z)));
} else if (Projectile.class.isAssignableFrom(clazz)) {
if (Snowball.class.isAssignableFrom(clazz)) {
entity = new EntitySnowball(world, x, y, z);
} else if (Egg.class.isAssignableFrom(clazz)) {
entity = new EntityEgg(world, x, y, z);
} else if (AbstractArrow.class.isAssignableFrom(clazz)) {
if (TippedArrow.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ARROW.a(world);
((EntityTippedArrow) entity).setType(CraftPotionUtil.fromBukkit(new PotionData(PotionType.WATER, false, false)));
} else if (SpectralArrow.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SPECTRAL_ARROW.a(world);
} else if (Trident.class.isAssignableFrom(clazz)) {
entity = EntityTypes.TRIDENT.a(world);
} else {
entity = EntityTypes.ARROW.a(world);
}
entity.setPositionRotation(x, y, z, 0, 0);
} else if (ThrownExpBottle.class.isAssignableFrom(clazz)) {
entity = EntityTypes.EXPERIENCE_BOTTLE.a(world);
entity.setPositionRotation(x, y, z, 0, 0);
} else if (EnderPearl.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ENDER_PEARL.a(world);
entity.setPositionRotation(x, y, z, 0, 0);
} else if (ThrownPotion.class.isAssignableFrom(clazz)) {
if (LingeringPotion.class.isAssignableFrom(clazz)) {
entity = new EntityPotion(world, x, y, z);
((EntityPotion) entity).setItem(CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.LINGERING_POTION, 1)));
} else {
entity = new EntityPotion(world, x, y, z);
((EntityPotion) entity).setItem(CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.SPLASH_POTION, 1)));
}
} else if (Fireball.class.isAssignableFrom(clazz)) {
if (SmallFireball.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SMALL_FIREBALL.a(world);
} else if (WitherSkull.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WITHER_SKULL.a(world);
} else if (DragonFireball.class.isAssignableFrom(clazz)) {
entity = EntityTypes.DRAGON_FIREBALL.a(world);
} else {
entity = EntityTypes.FIREBALL.a(world);
}
entity.setPositionRotation(x, y, z, yaw, pitch);
Vector direction = location.getDirection().multiply(10);
((EntityFireball) entity).setDirection(direction.getX(), direction.getY(), direction.getZ());
} else if (ShulkerBullet.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SHULKER_BULLET.a(world);
entity.setPositionRotation(x, y, z, yaw, pitch);
} else if (LlamaSpit.class.isAssignableFrom(clazz)) {
entity = EntityTypes.LLAMA_SPIT.a(world);
entity.setPositionRotation(x, y, z, yaw, pitch);
} else if (Firework.class.isAssignableFrom(clazz)) {
entity = new EntityFireworks(world, x, y, z, net.minecraft.world.item.ItemStack.EMPTY);
}
} else if (Minecart.class.isAssignableFrom(clazz)) {
if (PoweredMinecart.class.isAssignableFrom(clazz)) {
entity = new EntityMinecartFurnace(world, x, y, z);
} else if (StorageMinecart.class.isAssignableFrom(clazz)) {
entity = new EntityMinecartChest(world, x, y, z);
} else if (ExplosiveMinecart.class.isAssignableFrom(clazz)) {
entity = new EntityMinecartTNT(world, x, y, z);
} else if (HopperMinecart.class.isAssignableFrom(clazz)) {
entity = new EntityMinecartHopper(world, x, y, z);
} else if (SpawnerMinecart.class.isAssignableFrom(clazz)) {
entity = new EntityMinecartMobSpawner(world, x, y, z);
} else if (CommandMinecart.class.isAssignableFrom(clazz)) {
entity = new EntityMinecartCommandBlock(world, x, y, z);
} else { // Default to rideable minecart for pre-rideable compatibility
entity = new EntityMinecartRideable(world, x, y, z);
}
} else if (EnderSignal.class.isAssignableFrom(clazz)) {
entity = new EntityEnderSignal(world, x, y, z);
} else if (EnderCrystal.class.isAssignableFrom(clazz)) {
entity = EntityTypes.END_CRYSTAL.a(world);
entity.setPositionRotation(x, y, z, 0, 0);
} else if (LivingEntity.class.isAssignableFrom(clazz)) {
if (Chicken.class.isAssignableFrom(clazz)) {
entity = EntityTypes.CHICKEN.a(world);
} else if (Cow.class.isAssignableFrom(clazz)) {
if (MushroomCow.class.isAssignableFrom(clazz)) {
entity = EntityTypes.MOOSHROOM.a(world);
} else {
entity = EntityTypes.COW.a(world);
}
} else if (Golem.class.isAssignableFrom(clazz)) {
if (Snowman.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SNOW_GOLEM.a(world);
} else if (IronGolem.class.isAssignableFrom(clazz)) {
entity = EntityTypes.IRON_GOLEM.a(world);
} else if (Shulker.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SHULKER.a(world);
}
} else if (Creeper.class.isAssignableFrom(clazz)) {
entity = EntityTypes.CREEPER.a(world);
} else if (Ghast.class.isAssignableFrom(clazz)) {
entity = EntityTypes.GHAST.a(world);
} else if (Pig.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PIG.a(world);
} else if (Player.class.isAssignableFrom(clazz)) {
// need a net server handler for this one
} else if (Sheep.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SHEEP.a(world);
} else if (AbstractHorse.class.isAssignableFrom(clazz)) {
if (ChestedHorse.class.isAssignableFrom(clazz)) {
if (Donkey.class.isAssignableFrom(clazz)) {
entity = EntityTypes.DONKEY.a(world);
} else if (Mule.class.isAssignableFrom(clazz)) {
entity = EntityTypes.MULE.a(world);
} else if (Llama.class.isAssignableFrom(clazz)) {
if (TraderLlama.class.isAssignableFrom(clazz)) {
entity = EntityTypes.TRADER_LLAMA.a(world);
} else {
entity = EntityTypes.LLAMA.a(world);
}
}
} else if (SkeletonHorse.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SKELETON_HORSE.a(world);
} else if (ZombieHorse.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ZOMBIE_HORSE.a(world);
} else {
entity = EntityTypes.HORSE.a(world);
}
} else if (AbstractSkeleton.class.isAssignableFrom(clazz)) {
if (Stray.class.isAssignableFrom(clazz)) {
entity = EntityTypes.STRAY.a(world);
} else if (WitherSkeleton.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WITHER_SKELETON.a(world);
} else if (Skeleton.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SKELETON.a(world);
}
} else if (Slime.class.isAssignableFrom(clazz)) {
if (MagmaCube.class.isAssignableFrom(clazz)) {
entity = EntityTypes.MAGMA_CUBE.a(world);
} else {
entity = EntityTypes.SLIME.a(world);
}
} else if (Spider.class.isAssignableFrom(clazz)) {
if (CaveSpider.class.isAssignableFrom(clazz)) {
entity = EntityTypes.CAVE_SPIDER.a(world);
} else {
entity = EntityTypes.SPIDER.a(world);
}
} else if (Squid.class.isAssignableFrom(clazz)) {
if (GlowSquid.class.isAssignableFrom(clazz)) {
entity = EntityTypes.GLOW_SQUID.a(world);
} else {
entity = EntityTypes.SQUID.a(world);
}
} else if (Tameable.class.isAssignableFrom(clazz)) {
if (Wolf.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WOLF.a(world);
} else if (Parrot.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PARROT.a(world);
} else if (Cat.class.isAssignableFrom(clazz)) {
entity = EntityTypes.CAT.a(world);
}
} else if (PigZombie.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ZOMBIFIED_PIGLIN.a(world);
} else if (Zombie.class.isAssignableFrom(clazz)) {
if (Husk.class.isAssignableFrom(clazz)) {
entity = EntityTypes.HUSK.a(world);
} else if (ZombieVillager.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ZOMBIE_VILLAGER.a(world);
} else if (Drowned.class.isAssignableFrom(clazz)) {
entity = EntityTypes.DROWNED.a(world);
} else {
entity = new EntityZombie(world);
}
} else if (Giant.class.isAssignableFrom(clazz)) {
entity = EntityTypes.GIANT.a(world);
} else if (Silverfish.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SILVERFISH.a(world);
} else if (Enderman.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ENDERMAN.a(world);
} else if (Blaze.class.isAssignableFrom(clazz)) {
entity = EntityTypes.BLAZE.a(world);
} else if (AbstractVillager.class.isAssignableFrom(clazz)) {
if (Villager.class.isAssignableFrom(clazz)) {
entity = EntityTypes.VILLAGER.a(world);
} else if (WanderingTrader.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WANDERING_TRADER.a(world);
}
} else if (Witch.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WITCH.a(world);
} else if (Wither.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WITHER.a(world);
} else if (ComplexLivingEntity.class.isAssignableFrom(clazz)) {
if (EnderDragon.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ENDER_DRAGON.a(world);
}
} else if (Ambient.class.isAssignableFrom(clazz)) {
if (Bat.class.isAssignableFrom(clazz)) {
entity = EntityTypes.BAT.a(world);
}
} else if (Rabbit.class.isAssignableFrom(clazz)) {
entity = EntityTypes.RABBIT.a(world);
} else if (Endermite.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ENDERMITE.a(world);
} else if (Guardian.class.isAssignableFrom(clazz)) {
if (ElderGuardian.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ELDER_GUARDIAN.a(world);
} else {
entity = EntityTypes.GUARDIAN.a(world);
}
} else if (ArmorStand.class.isAssignableFrom(clazz)) {
entity = new EntityArmorStand(world, x, y, z);
} else if (PolarBear.class.isAssignableFrom(clazz)) {
entity = EntityTypes.POLAR_BEAR.a(world);
} else if (Vex.class.isAssignableFrom(clazz)) {
entity = EntityTypes.VEX.a(world);
} else if (Illager.class.isAssignableFrom(clazz)) {
if (Spellcaster.class.isAssignableFrom(clazz)) {
if (Evoker.class.isAssignableFrom(clazz)) {
entity = EntityTypes.EVOKER.a(world);
} else if (Illusioner.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ILLUSIONER.a(world);
}
} else if (Vindicator.class.isAssignableFrom(clazz)) {
entity = EntityTypes.VINDICATOR.a(world);
} else if (Pillager.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PILLAGER.a(world);
}
} else if (Turtle.class.isAssignableFrom(clazz)) {
entity = EntityTypes.TURTLE.a(world);
} else if (Phantom.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PHANTOM.a(world);
} else if (Fish.class.isAssignableFrom(clazz)) {
if (Cod.class.isAssignableFrom(clazz)) {
entity = EntityTypes.COD.a(world);
} else if (PufferFish.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PUFFERFISH.a(world);
} else if (Salmon.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SALMON.a(world);
} else if (TropicalFish.class.isAssignableFrom(clazz)) {
entity = EntityTypes.TROPICAL_FISH.a(world);
}
} else if (Dolphin.class.isAssignableFrom(clazz)) {
entity = EntityTypes.DOLPHIN.a(world);
} else if (Ocelot.class.isAssignableFrom(clazz)) {
entity = EntityTypes.OCELOT.a(world);
} else if (Ravager.class.isAssignableFrom(clazz)) {
entity = EntityTypes.RAVAGER.a(world);
} else if (Panda.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PANDA.a(world);
} else if (Fox.class.isAssignableFrom(clazz)) {
entity = EntityTypes.FOX.a(world);
} else if (Bee.class.isAssignableFrom(clazz)) {
entity = EntityTypes.BEE.a(world);
} else if (Hoglin.class.isAssignableFrom(clazz)) {
entity = EntityTypes.HOGLIN.a(world);
} else if (Piglin.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PIGLIN.a(world);
} else if (PiglinBrute.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PIGLIN_BRUTE.a(world);
} else if (Strider.class.isAssignableFrom(clazz)) {
entity = EntityTypes.STRIDER.a(world);
} else if (Zoglin.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ZOGLIN.a(world);
} else if (Axolotl.class.isAssignableFrom(clazz)) {
entity = EntityTypes.AXOLOTL.a(world);
} else if (Goat.class.isAssignableFrom(clazz)) {
entity = EntityTypes.GOAT.a(world);
}
if (entity != null) {
entity.setLocation(x, y, z, yaw, pitch);
entity.setHeadRotation(yaw); // SPIGOT-3587
}
} else if (Hanging.class.isAssignableFrom(clazz)) {
BlockFace face = BlockFace.SELF;
int width = 16; // 1 full block, also painting smallest size.
int height = 16; // 1 full block, also painting smallest size.
if (ItemFrame.class.isAssignableFrom(clazz)) {
width = 12;
height = 12;
} else if (LeashHitch.class.isAssignableFrom(clazz)) {
width = 9;
height = 9;
}
BlockFace[] faces = new BlockFace[]{BlockFace.EAST, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN};
final BlockPosition pos = new BlockPosition(x, y, z);
for (BlockFace dir : faces) {
IBlockData nmsBlock = world.getType(pos.shift(CraftBlock.blockFaceToNotch(dir)));
if (nmsBlock.getMaterial().isBuildable() || BlockDiodeAbstract.isDiode(nmsBlock)) {
boolean taken = false;
AxisAlignedBB bb = (ItemFrame.class.isAssignableFrom(clazz))
? EntityItemFrame.calculateBoundingBox(null, pos, CraftBlock.blockFaceToNotch(dir).opposite(), width, height)
: EntityHanging.calculateBoundingBox(null, pos, CraftBlock.blockFaceToNotch(dir).opposite(), width, height);
List<net.minecraft.world.entity.Entity> list = (List<net.minecraft.world.entity.Entity>) world.getEntities(null, bb);
for (Iterator<net.minecraft.world.entity.Entity> it = list.iterator(); !taken && it.hasNext();) {
net.minecraft.world.entity.Entity e = it.next();
if (e instanceof EntityHanging) {
taken = true; // Hanging entities do not like hanging entities which intersect them.
}
}
if (!taken) {
face = dir;
break;
}
}
}
if (LeashHitch.class.isAssignableFrom(clazz)) {
entity = new EntityLeash(world, new BlockPosition(x, y, z));
} else {
// No valid face found
Preconditions.checkArgument(face != BlockFace.SELF, "Cannot spawn hanging entity for %s at %s (no free face)", clazz.getName(), location);
EnumDirection dir = CraftBlock.blockFaceToNotch(face).opposite();
if (Painting.class.isAssignableFrom(clazz)) {
entity = new EntityPainting(world, new BlockPosition(x, y, z), dir);
} else if (ItemFrame.class.isAssignableFrom(clazz)) {
if (GlowItemFrame.class.isAssignableFrom(clazz)) {
entity = new net.minecraft.world.entity.decoration.GlowItemFrame(world, new BlockPosition(x, y, z), dir);
} else {
entity = new EntityItemFrame(world, new BlockPosition(x, y, z), dir);
}
}
}
if (entity != null && !((EntityHanging) entity).survives()) {
throw new IllegalArgumentException("Cannot spawn hanging entity for " + clazz.getName() + " at " + location);
}
} else if (TNTPrimed.class.isAssignableFrom(clazz)) {
entity = new EntityTNTPrimed(world, x, y, z, null);
} else if (ExperienceOrb.class.isAssignableFrom(clazz)) {
entity = new EntityExperienceOrb(world, x, y, z, 0);
} else if (LightningStrike.class.isAssignableFrom(clazz)) {
entity = EntityTypes.LIGHTNING_BOLT.a(world);
} else if (AreaEffectCloud.class.isAssignableFrom(clazz)) {
entity = new EntityAreaEffectCloud(world, x, y, z);
} else if (EvokerFangs.class.isAssignableFrom(clazz)) {
entity = new EntityEvokerFangs(world, x, y, z, (float) Math.toRadians(yaw), 0, null);
} else if (Marker.class.isAssignableFrom(clazz)) {
entity = EntityTypes.MARKER.a(world);
entity.setPosition(x, y, z);
}
if (entity != null) {
return entity;
}
throw new IllegalArgumentException("Cannot spawn an entity for " + clazz.getName());
}
@SuppressWarnings("unchecked")
public <T extends Entity> T addEntity(net.minecraft.world.entity.Entity entity, SpawnReason reason) throws IllegalArgumentException {
return addEntity(entity, reason, null);
}
@SuppressWarnings("unchecked")
public <T extends Entity> T addEntity(net.minecraft.world.entity.Entity entity, SpawnReason reason, Consumer<T> function) throws IllegalArgumentException {
Preconditions.checkArgument(entity != null, "Cannot spawn null entity");
if (entity instanceof EntityInsentient) {
((EntityInsentient) entity).prepare(getHandle(), getHandle().getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.COMMAND, (GroupDataEntity) null, null);
}
if (function != null) {
function.accept((T) entity.getBukkitEntity());
}
world.addEntity(entity, reason);
return (T) entity.getBukkitEntity();
}
public <T extends Entity> T spawn(Location location, Class<T> clazz, Consumer<T> function, SpawnReason reason) throws IllegalArgumentException {
net.minecraft.world.entity.Entity entity = createEntity(location, clazz);
return addEntity(entity, reason, function);
}
@Override @Override
public ChunkSnapshot getEmptyChunkSnapshot(int x, int z, boolean includeBiome, boolean includeBiomeTempRain) { public ChunkSnapshot getEmptyChunkSnapshot(int x, int z, boolean includeBiome, boolean includeBiomeTempRain) {
return CraftChunk.getEmptyChunkSnapshot(x, z, this, includeBiome, includeBiomeTempRain); return CraftChunk.getEmptyChunkSnapshot(x, z, this, includeBiome, includeBiomeTempRain);

View File

@ -43,9 +43,11 @@ public class CraftBarrel extends CraftLootable<TileEntityBarrel> implements Barr
if (!open) { if (!open) {
getTileEntity().setOpenFlag(blockData, true); getTileEntity().setOpenFlag(blockData, true);
if (getWorldHandle() instanceof net.minecraft.world.level.World) {
getTileEntity().playOpenSound(blockData, SoundEffects.BARREL_OPEN); getTileEntity().playOpenSound(blockData, SoundEffects.BARREL_OPEN);
} }
} }
}
getTileEntity().openersCounter.opened = true; getTileEntity().openersCounter.opened = true;
} }
@ -55,8 +57,10 @@ public class CraftBarrel extends CraftLootable<TileEntityBarrel> implements Barr
if (getTileEntity().openersCounter.opened) { if (getTileEntity().openersCounter.opened) {
IBlockData blockData = getTileEntity().getBlock(); IBlockData blockData = getTileEntity().getBlock();
getTileEntity().setOpenFlag(blockData, false); getTileEntity().setOpenFlag(blockData, false);
if (getWorldHandle() instanceof net.minecraft.world.level.World) {
getTileEntity().playOpenSound(blockData, SoundEffects.BARREL_CLOSE); getTileEntity().playOpenSound(blockData, SoundEffects.BARREL_CLOSE);
} }
}
getTileEntity().openersCounter.opened = false; getTileEntity().openersCounter.opened = false;
} }
} }

View File

@ -1,5 +1,6 @@
package org.bukkit.craftbukkit.block; package org.bukkit.craftbukkit.block;
import com.google.common.base.Preconditions;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import net.minecraft.world.ChestLock; import net.minecraft.world.ChestLock;
@ -27,6 +28,8 @@ public class CraftBeacon extends CraftBlockEntityState<TileEntityBeacon> impleme
@Override @Override
public Collection<LivingEntity> getEntitiesInRange() { public Collection<LivingEntity> getEntitiesInRange() {
Preconditions.checkState(getWorldHandle() instanceof net.minecraft.world.level.World, "Can't get entities during world generation");
TileEntity tileEntity = this.getTileEntityFromWorld(); TileEntity tileEntity = this.getTileEntityFromWorld();
if (tileEntity instanceof TileEntityBeacon) { if (tileEntity instanceof TileEntityBeacon) {
TileEntityBeacon beacon = (TileEntityBeacon) tileEntity; TileEntityBeacon beacon = (TileEntityBeacon) tileEntity;

View File

@ -65,6 +65,8 @@ public class CraftBeehive extends CraftBlockEntityState<TileEntityBeehive> imple
@Override @Override
public List<Bee> releaseEntities() { public List<Bee> releaseEntities() {
Preconditions.checkState(getWorldHandle() instanceof net.minecraft.world.level.World, "Can't release entities during world generation");
List<Bee> bees = new ArrayList<>(); List<Bee> bees = new ArrayList<>();
if (isPlaced()) { if (isPlaced()) {

View File

@ -81,6 +81,10 @@ public class CraftBlock implements Block {
return position; return position;
} }
public GeneratorAccess getHandle() {
return world;
}
@Override @Override
public World getWorld() { public World getWorld() {
return world.getMinecraftWorld().getWorld(); return world.getMinecraftWorld().getWorld();
@ -198,7 +202,7 @@ public class CraftBlock implements Block {
return world.setTypeAndData(position, blockData, 3); return world.setTypeAndData(position, blockData, 3);
} else { } else {
boolean success = world.setTypeAndData(position, blockData, 2 | 16 | 1024); // NOTIFY | NO_OBSERVER | NO_PLACE (custom) boolean success = world.setTypeAndData(position, blockData, 2 | 16 | 1024); // NOTIFY | NO_OBSERVER | NO_PLACE (custom)
if (success) { if (success && world instanceof net.minecraft.world.level.World) {
world.getMinecraftWorld().notify( world.getMinecraftWorld().notify(
position, position,
old, old,

View File

@ -22,8 +22,7 @@ public class CraftBlockEntityState<T extends TileEntity> extends CraftBlockState
this.tileEntityClass = tileEntityClass; this.tileEntityClass = tileEntityClass;
// get tile entity from block: // get tile entity from block:
CraftWorld world = (CraftWorld) this.getWorld(); this.tileEntity = tileEntityClass.cast(getWorldHandle().getTileEntity(this.getPosition()));
this.tileEntity = tileEntityClass.cast(world.getHandle().getTileEntity(this.getPosition()));
Preconditions.checkState(this.tileEntity != null, "Tile is null, asynchronous access? %s", block); Preconditions.checkState(this.tileEntity != null, "Tile is null, asynchronous access? %s", block);
// copy tile entity data: // copy tile entity data:
@ -74,7 +73,7 @@ public class CraftBlockEntityState<T extends TileEntity> extends CraftBlockState
protected TileEntity getTileEntityFromWorld() { protected TileEntity getTileEntityFromWorld() {
requirePlaced(); requirePlaced();
return ((CraftWorld) this.getWorld()).getHandle().getTileEntity(this.getPosition()); return getWorldHandle().getTileEntity(this.getPosition());
} }
// gets the NBT data of the TileEntity represented by this block state // gets the NBT data of the TileEntity represented by this block state

View File

@ -1,6 +1,7 @@
package org.bukkit.craftbukkit.block; package org.bukkit.craftbukkit.block;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import java.lang.ref.WeakReference;
import java.util.List; import java.util.List;
import net.minecraft.core.BlockPosition; import net.minecraft.core.BlockPosition;
import net.minecraft.world.level.GeneratorAccess; import net.minecraft.world.level.GeneratorAccess;
@ -25,12 +26,20 @@ public class CraftBlockState implements BlockState {
private final BlockPosition position; private final BlockPosition position;
protected IBlockData data; protected IBlockData data;
protected int flag; protected int flag;
private WeakReference<GeneratorAccess> weakWorld;
public CraftBlockState(final Block block) { public CraftBlockState(final Block block) {
this.world = (CraftWorld) block.getWorld(); this.world = (CraftWorld) block.getWorld();
this.position = ((CraftBlock) block).getPosition(); this.position = ((CraftBlock) block).getPosition();
this.data = ((CraftBlock) block).getNMS(); this.data = ((CraftBlock) block).getNMS();
this.flag = 3; this.flag = 3;
GeneratorAccess generatorAccess = ((CraftBlock) block).getHandle();
if (generatorAccess instanceof net.minecraft.world.level.World) {
this.weakWorld = null;
} else {
this.weakWorld = new WeakReference<>(generatorAccess);
}
} }
public CraftBlockState(final Block block, int flag) { public CraftBlockState(final Block block, int flag) {
@ -42,6 +51,7 @@ public class CraftBlockState implements BlockState {
world = null; world = null;
data = CraftMagicNumbers.getBlock(material).getBlockData(); data = CraftMagicNumbers.getBlock(material).getBlockData();
position = BlockPosition.ZERO; position = BlockPosition.ZERO;
this.weakWorld = null;
} }
public static CraftBlockState getBlockState(GeneratorAccess world, net.minecraft.core.BlockPosition pos) { public static CraftBlockState getBlockState(GeneratorAccess world, net.minecraft.core.BlockPosition pos) {
@ -52,6 +62,20 @@ public class CraftBlockState implements BlockState {
return new CraftBlockState(CraftBlock.at(world, pos), flag); return new CraftBlockState(CraftBlock.at(world, pos), flag);
} }
public GeneratorAccess getWorldHandle() {
if (weakWorld == null) {
return world.getHandle();
}
GeneratorAccess access = weakWorld.get();
if (access == null) {
weakWorld = null;
return world.getHandle();
}
return access;
}
@Override @Override
public World getWorld() { public World getWorld() {
requirePlaced(); requirePlaced();
@ -154,7 +178,7 @@ public class CraftBlockState implements BlockState {
@Override @Override
public CraftBlock getBlock() { public CraftBlock getBlock() {
requirePlaced(); requirePlaced();
return CraftBlock.at(world.getHandle(), position); return CraftBlock.at(getWorldHandle(), position);
} }
@Override @Override
@ -172,6 +196,7 @@ public class CraftBlockState implements BlockState {
if (!isPlaced()) { if (!isPlaced()) {
return true; return true;
} }
GeneratorAccess access = getWorldHandle();
CraftBlock block = getBlock(); CraftBlock block = getBlock();
if (block.getType() != getType()) { if (block.getType() != getType()) {
@ -182,12 +207,14 @@ public class CraftBlockState implements BlockState {
IBlockData newBlock = this.data; IBlockData newBlock = this.data;
block.setTypeAndData(newBlock, applyPhysics); block.setTypeAndData(newBlock, applyPhysics);
if (access instanceof net.minecraft.world.level.World) {
world.getHandle().notify( world.getHandle().notify(
position, position,
block.getNMS(), block.getNMS(),
newBlock, newBlock,
3 3
); );
}
// Update levers etc // Update levers etc
if (false && applyPhysics && getData() instanceof Attachable) { // Call does not map to new API if (false && applyPhysics && getData() instanceof Attachable) { // Call does not map to new API

View File

@ -1,5 +1,6 @@
package org.bukkit.craftbukkit.block; package org.bukkit.craftbukkit.block;
import com.google.common.base.Preconditions;
import net.minecraft.sounds.SoundEffects; import net.minecraft.sounds.SoundEffects;
import net.minecraft.world.ITileInventory; import net.minecraft.world.ITileInventory;
import net.minecraft.world.level.block.BlockChest; import net.minecraft.world.level.block.BlockChest;
@ -40,6 +41,8 @@ public class CraftChest extends CraftLootable<TileEntityChest> implements Chest
@Override @Override
public Inventory getInventory() { public Inventory getInventory() {
Preconditions.checkState(getWorldHandle() instanceof net.minecraft.world.level.World, "Can't get inventory during world generation, use getBlockInventory() instead");
CraftInventory inventory = (CraftInventory) this.getBlockInventory(); CraftInventory inventory = (CraftInventory) this.getBlockInventory();
if (!isPlaced()) { if (!isPlaced()) {
return inventory; return inventory;
@ -60,7 +63,7 @@ public class CraftChest extends CraftLootable<TileEntityChest> implements Chest
@Override @Override
public void open() { public void open() {
requirePlaced(); requirePlaced();
if (!getTileEntity().openersCounter.opened) { if (!getTileEntity().openersCounter.opened && getWorldHandle() instanceof net.minecraft.world.level.World) {
IBlockData block = getTileEntity().getBlock(); IBlockData block = getTileEntity().getBlock();
getTileEntity().getWorld().playBlockAction(getPosition(), block.getBlock(), 1, getTileEntity().openersCounter.getOpenerCount() + 1); getTileEntity().getWorld().playBlockAction(getPosition(), block.getBlock(), 1, getTileEntity().openersCounter.getOpenerCount() + 1);
TileEntityChest.playOpenSound(getTileEntity().getWorld(), getPosition(), block, SoundEffects.CHEST_OPEN); TileEntityChest.playOpenSound(getTileEntity().getWorld(), getPosition(), block, SoundEffects.CHEST_OPEN);
@ -71,7 +74,7 @@ public class CraftChest extends CraftLootable<TileEntityChest> implements Chest
@Override @Override
public void close() { public void close() {
requirePlaced(); requirePlaced();
if (getTileEntity().openersCounter.opened) { if (getTileEntity().openersCounter.opened && getWorldHandle() instanceof net.minecraft.world.level.World) {
IBlockData block = getTileEntity().getBlock(); IBlockData block = getTileEntity().getBlock();
getTileEntity().getWorld().playBlockAction(getPosition(), block.getBlock(), 1, 0); getTileEntity().getWorld().playBlockAction(getPosition(), block.getBlock(), 1, 0);
TileEntityChest.playOpenSound(getTileEntity().getWorld(), getPosition(), block, SoundEffects.CHEST_CLOSE); TileEntityChest.playOpenSound(getTileEntity().getWorld(), getPosition(), block, SoundEffects.CHEST_CLOSE);

View File

@ -1,5 +1,6 @@
package org.bukkit.craftbukkit.block; package org.bukkit.craftbukkit.block;
import com.google.common.base.Preconditions;
import net.minecraft.world.level.block.BlockDispenser; import net.minecraft.world.level.block.BlockDispenser;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.TileEntityDispenser; import net.minecraft.world.level.block.entity.TileEntityDispenser;
@ -49,6 +50,8 @@ public class CraftDispenser extends CraftLootable<TileEntityDispenser> implement
@Override @Override
public boolean dispense() { public boolean dispense() {
Preconditions.checkState(getWorldHandle() instanceof net.minecraft.world.level.World, "Can't dispense during world generation");
Block block = getBlock(); Block block = getBlock();
if (block.getType() == Material.DISPENSER) { if (block.getType() == Material.DISPENSER) {

View File

@ -1,5 +1,6 @@
package org.bukkit.craftbukkit.block; package org.bukkit.craftbukkit.block;
import com.google.common.base.Preconditions;
import net.minecraft.world.level.block.BlockDropper; import net.minecraft.world.level.block.BlockDropper;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.TileEntityDropper; import net.minecraft.world.level.block.entity.TileEntityDropper;
@ -36,6 +37,8 @@ public class CraftDropper extends CraftLootable<TileEntityDropper> implements Dr
@Override @Override
public void drop() { public void drop() {
Preconditions.checkState(getWorldHandle() instanceof net.minecraft.world.level.World, "Can't drop during world generation");
Block block = getBlock(); Block block = getBlock();
if (block.getType() == Material.DROPPER) { if (block.getType() == Material.DROPPER) {

View File

@ -1,5 +1,6 @@
package org.bukkit.craftbukkit.block; package org.bukkit.craftbukkit.block;
import com.google.common.base.Preconditions;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.BlockJukeBox; import net.minecraft.world.level.block.BlockJukeBox;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
@ -31,9 +32,9 @@ public class CraftJukebox extends CraftBlockEntityState<TileEntityJukeBox> imple
CraftWorld world = (CraftWorld) this.getWorld(); CraftWorld world = (CraftWorld) this.getWorld();
Material record = this.getPlaying(); Material record = this.getPlaying();
if (record == Material.AIR) { if (record == Material.AIR) {
world.getHandle().setTypeAndData(this.getPosition(), Blocks.JUKEBOX.getBlockData().set(BlockJukeBox.HAS_RECORD, false), 3); getWorldHandle().setTypeAndData(this.getPosition(), Blocks.JUKEBOX.getBlockData().set(BlockJukeBox.HAS_RECORD, false), 3);
} else { } else {
world.getHandle().setTypeAndData(this.getPosition(), Blocks.JUKEBOX.getBlockData().set(BlockJukeBox.HAS_RECORD, true), 3); getWorldHandle().setTypeAndData(this.getPosition(), Blocks.JUKEBOX.getBlockData().set(BlockJukeBox.HAS_RECORD, true), 3);
} }
world.playEffect(this.getLocation(), Effect.RECORD_PLAY, record); world.playEffect(this.getLocation(), Effect.RECORD_PLAY, record);
} }
@ -84,6 +85,8 @@ public class CraftJukebox extends CraftBlockEntityState<TileEntityJukeBox> imple
@Override @Override
public boolean eject() { public boolean eject() {
Preconditions.checkState(getWorldHandle() instanceof net.minecraft.world.level.World, "Can't eject during world generation");
requirePlaced(); requirePlaced();
TileEntity tileEntity = this.getTileEntityFromWorld(); TileEntity tileEntity = this.getTileEntityFromWorld();
if (!(tileEntity instanceof TileEntityJukeBox)) return false; if (!(tileEntity instanceof TileEntityJukeBox)) return false;

View File

@ -46,7 +46,7 @@ public class CraftLectern extends CraftBlockEntityState<TileEntityLectern> imple
public boolean update(boolean force, boolean applyPhysics) { public boolean update(boolean force, boolean applyPhysics) {
boolean result = super.update(force, applyPhysics); boolean result = super.update(force, applyPhysics);
if (result && this.isPlaced() && this.getType() == Material.LECTERN) { if (result && this.isPlaced() && this.getType() == Material.LECTERN && getWorldHandle() instanceof net.minecraft.world.level.World) {
BlockLectern.a(this.world.getHandle(), this.getPosition(), this.getHandle()); BlockLectern.a(this.world.getHandle(), this.getPosition(), this.getHandle());
} }

View File

@ -48,7 +48,7 @@ public class CraftShulkerBox extends CraftLootable<TileEntityShulkerBox> impleme
@Override @Override
public void open() { public void open() {
requirePlaced(); requirePlaced();
if (!getTileEntity().opened) { if (!getTileEntity().opened && getWorldHandle() instanceof net.minecraft.world.level.World) {
World world = getTileEntity().getWorld(); World world = getTileEntity().getWorld();
world.playBlockAction(getPosition(), getTileEntity().getBlock().getBlock(), 1, 1); world.playBlockAction(getPosition(), getTileEntity().getBlock().getBlock(), 1, 1);
world.playSound(null, getPosition(), SoundEffects.SHULKER_BOX_OPEN, SoundCategory.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); world.playSound(null, getPosition(), SoundEffects.SHULKER_BOX_OPEN, SoundCategory.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F);
@ -59,7 +59,7 @@ public class CraftShulkerBox extends CraftLootable<TileEntityShulkerBox> impleme
@Override @Override
public void close() { public void close() {
requirePlaced(); requirePlaced();
if (getTileEntity().opened) { if (getTileEntity().opened && getWorldHandle() instanceof net.minecraft.world.level.World) {
World world = getTileEntity().getWorld(); World world = getTileEntity().getWorld();
world.playBlockAction(getPosition(), getTileEntity().getBlock().getBlock(), 1, 0); world.playBlockAction(getPosition(), getTileEntity().getBlock().getBlock(), 1, 0);
world.playSound(null, getPosition(), SoundEffects.SHULKER_BOX_OPEN, SoundCategory.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); world.playSound(null, getPosition(), SoundEffects.SHULKER_BOX_OPEN, SoundCategory.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F);

View File

@ -180,9 +180,19 @@ public class CraftStructureBlock extends CraftBlockEntityState<TileEntityStructu
@Override @Override
protected void applyTo(TileEntityStructure tileEntity) { protected void applyTo(TileEntityStructure tileEntity) {
super.applyTo(tileEntity); super.applyTo(tileEntity);
net.minecraft.world.level.GeneratorAccess access = getWorldHandle();
// Ensure block type is correct // Ensure block type is correct
if (access instanceof net.minecraft.world.level.World) {
tileEntity.setUsageMode(tileEntity.getUsageMode()); tileEntity.setUsageMode(tileEntity.getUsageMode());
} else {
// Custom handle during world generation
// From TileEntityStructure#setUsageMode(BlockPropertyStructureMode)
net.minecraft.world.level.block.state.IBlockData data = access.getType(this.getPosition());
if (data.a(net.minecraft.world.level.block.Blocks.STRUCTURE_BLOCK)) {
access.setTypeAndData(this.getPosition(), data.set(net.minecraft.world.level.block.BlockStructure.MODE, tileEntity.getUsageMode()), 2);
}
}
} }
private static boolean isBetween(int num, int min, int max) { private static boolean isBetween(int num, int min, int max) {

View File

@ -20,24 +20,18 @@ public class CraftCreeper extends CraftMonster implements Creeper {
@Override @Override
public void setPowered(boolean powered) { public void setPowered(boolean powered) {
CraftServer server = this.server; CreeperPowerEvent.PowerCause cause = powered ? CreeperPowerEvent.PowerCause.SET_ON : CreeperPowerEvent.PowerCause.SET_OFF;
Creeper entity = (Creeper) this.getHandle().getBukkitEntity();
if (powered) { // only call event when we are not in world generation
CreeperPowerEvent event = new CreeperPowerEvent(entity, CreeperPowerEvent.PowerCause.SET_ON); if (getHandle().generation || !callPowerEvent(cause)) {
getHandle().setPowered(powered);
}
}
private boolean callPowerEvent(CreeperPowerEvent.PowerCause cause) {
CreeperPowerEvent event = new CreeperPowerEvent((Creeper) getHandle().getBukkitEntity(), cause);
server.getPluginManager().callEvent(event); server.getPluginManager().callEvent(event);
return event.isCancelled();
if (!event.isCancelled()) {
getHandle().setPowered(true);
}
} else {
CreeperPowerEvent event = new CreeperPowerEvent(entity, CreeperPowerEvent.PowerCause.SET_OFF);
server.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
getHandle().setPowered(false);
}
}
} }
@Override @Override

View File

@ -506,6 +506,8 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
// Let the server handle cross world teleports // Let the server handle cross world teleports
if (!location.getWorld().equals(getWorld())) { if (!location.getWorld().equals(getWorld())) {
// Prevent teleportation to an other world during world generation
Preconditions.checkState(!entity.generation, "Cannot teleport entity to an other world during world generation");
entity.teleportTo(((CraftWorld) location.getWorld()).getHandle(), new BlockPosition(location.getX(), location.getY(), location.getZ())); entity.teleportTo(((CraftWorld) location.getWorld()).getHandle(), new BlockPosition(location.getX(), location.getY(), location.getZ()));
return true; return true;
} }
@ -530,6 +532,8 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
@Override @Override
public List<org.bukkit.entity.Entity> getNearbyEntities(double x, double y, double z) { public List<org.bukkit.entity.Entity> getNearbyEntities(double x, double y, double z) {
Preconditions.checkState(!entity.generation, "Cannot get nearby entities during world generation");
List<Entity> notchEntityList = entity.level.getEntities(entity, entity.getBoundingBox().grow(x, y, z), Predicates.alwaysTrue()); List<Entity> notchEntityList = entity.level.getEntities(entity, entity.getBoundingBox().grow(x, y, z), Predicates.alwaysTrue());
List<org.bukkit.entity.Entity> bukkitEntityList = new java.util.ArrayList<org.bukkit.entity.Entity>(notchEntityList.size()); List<org.bukkit.entity.Entity> bukkitEntityList = new java.util.ArrayList<org.bukkit.entity.Entity>(notchEntityList.size());
@ -730,6 +734,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
@Override @Override
public void playEffect(EntityEffect type) { public void playEffect(EntityEffect type) {
Preconditions.checkArgument(type != null, "type"); Preconditions.checkArgument(type != null, "type");
Preconditions.checkState(!entity.generation, "Cannot play effect during world generation");
if (type.getApplicable().isInstance(this)) { if (type.getApplicable().isInstance(this)) {
this.getHandle().level.broadcastEntityEffect(getHandle(), type.getData()); this.getHandle().level.broadcastEntityEffect(getHandle(), type.getData());

View File

@ -42,7 +42,7 @@ public class CraftHanging extends CraftEntity implements Hanging {
getHandle().setDirection(EnumDirection.EAST); getHandle().setDirection(EnumDirection.EAST);
break; break;
} }
if (!force && !hanging.survives()) { if (!force && !getHandle().generation && !hanging.survives()) {
// Revert since it doesn't fit // Revert since it doesn't fit
hanging.setDirection(dir); hanging.setDirection(dir);
return false; return false;

View File

@ -27,7 +27,7 @@ public class CraftItemFrame extends CraftHanging implements ItemFrame {
EnumDirection newDir = CraftBlock.blockFaceToNotch(face); EnumDirection newDir = CraftBlock.blockFaceToNotch(face);
getHandle().setDirection(newDir); getHandle().setDirection(newDir);
if (!force && !hanging.survives()) { if (!force && !getHandle().generation && !hanging.survives()) {
hanging.setDirection(oldDir); hanging.setDirection(oldDir);
return false; return false;
} }
@ -47,8 +47,10 @@ public class CraftItemFrame extends CraftHanging implements ItemFrame {
} }
// update redstone // update redstone
if (!getHandle().generation) {
getHandle().getWorld().updateAdjacentComparators(getHandle().pos, Blocks.AIR); getHandle().getWorld().updateAdjacentComparators(getHandle().pos, Blocks.AIR);
} }
}
@Override @Override
public void setItem(org.bukkit.inventory.ItemStack item) { public void setItem(org.bukkit.inventory.ItemStack item) {
@ -57,7 +59,8 @@ public class CraftItemFrame extends CraftHanging implements ItemFrame {
@Override @Override
public void setItem(org.bukkit.inventory.ItemStack item, boolean playSound) { public void setItem(org.bukkit.inventory.ItemStack item, boolean playSound) {
getHandle().setItem(CraftItemStack.asNMSCopy(item), true, playSound); // only updated redstone and play sound when it is not in generation
getHandle().setItem(CraftItemStack.asNMSCopy(item), !getHandle().generation, !getHandle().generation && playSound);
} }
@Override @Override

View File

@ -114,6 +114,12 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
throw new IllegalArgumentException("Health must be between 0 and " + getMaxHealth() + "(" + health + ")"); throw new IllegalArgumentException("Health must be between 0 and " + getMaxHealth() + "(" + health + ")");
} }
// during world generation, we don't want to run logic for dropping items and xp
if (getHandle().generation && health == 0) {
getHandle().die();
return;
}
getHandle().setHealth((float) health); getHandle().setHealth((float) health);
if (health == 0) { if (health == 0) {
@ -165,6 +171,8 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
} }
private List<Block> getLineOfSight(Set<Material> transparent, int maxDistance, int maxLength) { private List<Block> getLineOfSight(Set<Material> transparent, int maxDistance, int maxLength) {
Preconditions.checkState(!getHandle().generation, "Cannot get line of sight during world generation");
if (transparent == null) { if (transparent == null) {
transparent = Sets.newHashSet(Material.AIR, Material.CAVE_AIR, Material.VOID_AIR); transparent = Sets.newHashSet(Material.AIR, Material.CAVE_AIR, Material.VOID_AIR);
} }
@ -221,6 +229,8 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
@Override @Override
public RayTraceResult rayTraceBlocks(double maxDistance, FluidCollisionMode fluidCollisionMode) { public RayTraceResult rayTraceBlocks(double maxDistance, FluidCollisionMode fluidCollisionMode) {
Preconditions.checkState(!getHandle().generation, "Cannot ray tray blocks during world generation");
Location eyeLocation = this.getEyeLocation(); Location eyeLocation = this.getEyeLocation();
Vector direction = eyeLocation.getDirection(); Vector direction = eyeLocation.getDirection();
return this.getWorld().rayTraceBlocks(eyeLocation, direction, maxDistance, fluidCollisionMode, false); return this.getWorld().rayTraceBlocks(eyeLocation, direction, maxDistance, fluidCollisionMode, false);
@ -274,6 +284,8 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
@Override @Override
public void damage(double amount, org.bukkit.entity.Entity source) { public void damage(double amount, org.bukkit.entity.Entity source) {
Preconditions.checkState(!getHandle().generation, "Cannot damage entity during world generation");
DamageSource reason = DamageSource.GENERIC; DamageSource reason = DamageSource.GENERIC;
if (source instanceof HumanEntity) { if (source instanceof HumanEntity) {
@ -394,6 +406,8 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends Projectile> T launchProjectile(Class<? extends T> projectile, Vector velocity) { public <T extends Projectile> T launchProjectile(Class<? extends T> projectile, Vector velocity) {
Preconditions.checkState(!getHandle().generation, "Cannot launch projectile during world generation");
net.minecraft.world.level.World world = ((CraftWorld) getWorld()).getHandle(); net.minecraft.world.level.World world = ((CraftWorld) getWorld()).getHandle();
net.minecraft.world.entity.Entity launch = null; net.minecraft.world.entity.Entity launch = null;
@ -486,6 +500,8 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
@Override @Override
public boolean hasLineOfSight(Entity other) { public boolean hasLineOfSight(Entity other) {
Preconditions.checkState(!getHandle().generation, "Cannot check line of sight during world generation");
return getHandle().hasLineOfSight(((CraftEntity) other).getHandle()); return getHandle().hasLineOfSight(((CraftEntity) other).getHandle());
} }
@ -559,7 +575,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
@Override @Override
public boolean setLeashHolder(Entity holder) { public boolean setLeashHolder(Entity holder) {
if ((getHandle() instanceof EntityWither) || !(getHandle() instanceof EntityInsentient)) { if (getHandle().generation || (getHandle() instanceof EntityWither) || !(getHandle() instanceof EntityInsentient)) {
return false; return false;
} }
@ -608,6 +624,8 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
@Override @Override
public boolean isClimbing() { public boolean isClimbing() {
Preconditions.checkState(!getHandle().generation, "Cannot check if climbing during world generation");
return getHandle().isClimbing(); return getHandle().isClimbing();
} }
@ -631,17 +649,22 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
@Override @Override
public void attack(Entity target) { public void attack(Entity target) {
Preconditions.checkArgument(target != null, "target == null"); Preconditions.checkArgument(target != null, "target == null");
Preconditions.checkState(!getHandle().generation, "Cannot attack during world generation");
getHandle().attackEntity(((CraftEntity) target).getHandle()); getHandle().attackEntity(((CraftEntity) target).getHandle());
} }
@Override @Override
public void swingMainHand() { public void swingMainHand() {
Preconditions.checkState(!getHandle().generation, "Cannot swing hand during world generation");
getHandle().swingHand(EnumHand.MAIN_HAND, true); getHandle().swingHand(EnumHand.MAIN_HAND, true);
} }
@Override @Override
public void swingOffHand() { public void swingOffHand() {
Preconditions.checkState(!getHandle().generation, "Cannot swing hand during world generation");
getHandle().swingHand(EnumHand.OFF_HAND, true); getHandle().swingHand(EnumHand.OFF_HAND, true);
} }

View File

@ -1,5 +1,6 @@
package org.bukkit.craftbukkit.entity; package org.bukkit.craftbukkit.entity;
import com.google.common.base.Preconditions;
import net.minecraft.world.entity.EntityInsentient; import net.minecraft.world.entity.EntityInsentient;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
@ -16,6 +17,8 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob {
@Override @Override
public void setTarget(LivingEntity target) { public void setTarget(LivingEntity target) {
Preconditions.checkState(!getHandle().generation, "Cannot set target during world generation");
EntityInsentient entity = getHandle(); EntityInsentient entity = getHandle();
if (target == null) { if (target == null) {
entity.setGoalTarget(null, null, false); entity.setGoalTarget(null, null, false);

View File

@ -32,7 +32,7 @@ public class CraftPainting extends CraftHanging implements Painting {
Paintings oldArt = painting.motive; Paintings oldArt = painting.motive;
painting.motive = CraftArt.BukkitToNotch(art); painting.motive = CraftArt.BukkitToNotch(art);
painting.setDirection(painting.getDirection()); painting.setDirection(painting.getDirection());
if (!force && !painting.survives()) { if (!force && !getHandle().generation && !painting.survives()) {
// Revert painting since it doesn't fit // Revert painting since it doesn't fit
painting.motive = oldArt; painting.motive = oldArt;
painting.setDirection(painting.getDirection()); painting.setDirection(painting.getDirection());

View File

@ -1,5 +1,6 @@
package org.bukkit.craftbukkit.entity; package org.bukkit.craftbukkit.entity;
import com.google.common.base.Preconditions;
import net.minecraft.world.entity.projectile.EntityShulkerBullet; import net.minecraft.world.entity.projectile.EntityShulkerBullet;
import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
@ -35,6 +36,8 @@ public class CraftShulkerBullet extends AbstractProjectile implements ShulkerBul
@Override @Override
public void setTarget(org.bukkit.entity.Entity target) { public void setTarget(org.bukkit.entity.Entity target) {
Preconditions.checkState(!getHandle().generation, "Cannot set target during world generation");
getHandle().setTarget(target == null ? null : ((CraftEntity) target).getHandle()); getHandle().setTarget(target == null ? null : ((CraftEntity) target).getHandle());
} }

View File

@ -89,6 +89,7 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
Preconditions.checkArgument(location != null, "Location cannot be null"); Preconditions.checkArgument(location != null, "Location cannot be null");
Preconditions.checkArgument(location.getWorld() != null, "Location needs to be in a world"); Preconditions.checkArgument(location.getWorld() != null, "Location needs to be in a world");
Preconditions.checkArgument(location.getWorld().equals(getWorld()), "Cannot sleep across worlds"); Preconditions.checkArgument(location.getWorld().equals(getWorld()), "Cannot sleep across worlds");
Preconditions.checkState(!getHandle().generation, "Cannot sleep during world generation");
BlockPosition position = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); BlockPosition position = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ());
IBlockData iblockdata = getHandle().level.getType(position); IBlockData iblockdata = getHandle().level.getType(position);
@ -103,6 +104,7 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
@Override @Override
public void wakeup() { public void wakeup() {
Preconditions.checkState(isSleeping(), "Cannot wakeup if not sleeping"); Preconditions.checkState(isSleeping(), "Cannot wakeup if not sleeping");
Preconditions.checkState(!getHandle().generation, "Cannot wakeup during world generation");
getHandle().entityWakeup(); getHandle().entityWakeup();
} }

View File

@ -1,14 +1,20 @@
package org.bukkit.craftbukkit.generator; package org.bukkit.craftbukkit.generator;
import java.util.HashSet; import java.lang.ref.WeakReference;
import java.util.Set;
import net.minecraft.core.BlockPosition; import net.minecraft.core.BlockPosition;
import net.minecraft.core.IRegistry;
import net.minecraft.world.level.biome.BiomeBase;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.ITileEntity;
import net.minecraft.world.level.block.entity.TileEntity;
import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.level.block.state.IBlockData;
import net.minecraft.world.level.chunk.ChunkSection; import net.minecraft.world.level.chunk.BiomeStorage;
import net.minecraft.world.level.chunk.IChunkAccess;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
@ -18,20 +24,37 @@ import org.bukkit.material.MaterialData;
* Data to be used for the block types and data in a newly generated chunk. * Data to be used for the block types and data in a newly generated chunk.
*/ */
public final class CraftChunkData implements ChunkGenerator.ChunkData { public final class CraftChunkData implements ChunkGenerator.ChunkData {
private final int minHeight;
private final int maxHeight; private final int maxHeight;
private final ChunkSection[] sections; private final int minHeight;
private Set<BlockPosition> tiles; private final WeakReference<IChunkAccess> weakChunk;
private final Set<BlockPosition> lights = new HashSet<>();
public CraftChunkData(World world) { public CraftChunkData(World world, IChunkAccess chunkAccess) {
this(world.getMinHeight(), world.getMaxHeight()); this(world.getMaxHeight(), world.getMinHeight(), chunkAccess);
} }
/* pp for tests */ CraftChunkData(int minHeight, int maxHeight) { CraftChunkData(int maxHeight, int minHeight, IChunkAccess chunkAccess) {
this.minHeight = minHeight;
this.maxHeight = maxHeight; this.maxHeight = maxHeight;
sections = new ChunkSection[(((maxHeight - 1) >> 4) + 1) - (minHeight >> 4)]; this.minHeight = minHeight;
this.weakChunk = new WeakReference<>(chunkAccess);
}
public IChunkAccess getHandle() {
IChunkAccess access = weakChunk.get();
if (access == null) {
throw new IllegalStateException("IChunkAccess no longer present, are you using it in a different tick?");
}
return access;
}
public void breakLink() {
weakChunk.clear();
}
@Override
public int getMaxHeight() {
return maxHeight;
} }
@Override @Override
@ -40,8 +63,9 @@ public final class CraftChunkData implements ChunkGenerator.ChunkData {
} }
@Override @Override
public int getMaxHeight() { public Biome getBiome(int x, int y, int z) {
return maxHeight; BiomeStorage biomeStorage = getHandle().getBiomeIndex();
return CraftBlock.biomeBaseToBiome((IRegistry<BiomeBase>) biomeStorage.biomeRegistry, biomeStorage.getBiome(x >> 2, y >> 2, z >> 2));
} }
@Override @Override
@ -116,11 +140,9 @@ public final class CraftChunkData implements ChunkGenerator.ChunkData {
return; return;
} }
for (int y = yMin; y < yMax; y++) { for (int y = yMin; y < yMax; y++) {
ChunkSection section = getChunkSection(y, true);
int offsetBase = y & 0xf;
for (int x = xMin; x < xMax; x++) { for (int x = xMin; x < xMax; x++) {
for (int z = zMin; z < zMax; z++) { for (int z = zMin; z < zMax; z++) {
section.setType(x, offsetBase, z, type); setBlock(x, y, z, type);
} }
} }
} }
@ -130,12 +152,9 @@ public final class CraftChunkData implements ChunkGenerator.ChunkData {
if (x != (x & 0xf) || y < minHeight || y >= maxHeight || z != (z & 0xf)) { if (x != (x & 0xf) || y < minHeight || y >= maxHeight || z != (z & 0xf)) {
return Blocks.AIR.getBlockData(); return Blocks.AIR.getBlockData();
} }
ChunkSection section = getChunkSection(y, false);
if (section == null) { IChunkAccess access = getHandle();
return Blocks.AIR.getBlockData(); return access.getType(new BlockPosition(access.getPos().d() + x, y, access.getPos().e() + z));
} else {
return section.getType(x, y & 0xf, z);
}
} }
@Override @Override
@ -147,43 +166,22 @@ public final class CraftChunkData implements ChunkGenerator.ChunkData {
if (x != (x & 0xf) || y < minHeight || y >= maxHeight || z != (z & 0xf)) { if (x != (x & 0xf) || y < minHeight || y >= maxHeight || z != (z & 0xf)) {
return; return;
} }
ChunkSection section = getChunkSection(y, true);
section.setType(x, y & 0xf, z, type);
// SPIGOT-1753: Capture light blocks, for light updates IChunkAccess access = getHandle();
if (type.f() > 0) { // PAIL rename getLightEmission BlockPosition blockPosition = new BlockPosition(access.getPos().d() + x, y, access.getPos().e() + z);
lights.add(new BlockPosition(x, y, z)); IBlockData oldBlockData = access.setType(blockPosition, type, false);
} else {
lights.remove(new BlockPosition(x, y, z));
}
if (type.isTileEntity()) { if (type.isTileEntity()) {
if (tiles == null) { TileEntity tileEntity = ((ITileEntity) type.getBlock()).createTile(blockPosition, type);
tiles = new HashSet<>();
}
tiles.add(new BlockPosition(x, y, z)); // createTile can return null, currently only the case with material MOVING_PISTON
if (tileEntity == null) {
access.removeTileEntity(blockPosition);
} else {
access.setTileEntity(tileEntity);
}
} else if (oldBlockData != null && oldBlockData.isTileEntity()) {
access.removeTileEntity(blockPosition);
} }
} }
private ChunkSection getChunkSection(int y, boolean create) {
int offset = (y - minHeight) >> 4;
ChunkSection section = sections[offset];
if (create && section == null) {
sections[offset] = section = new ChunkSection(offset + (minHeight >> 4));
}
return section;
}
ChunkSection[] getRawChunkData() {
return sections;
}
Set<BlockPosition> getTiles() {
return tiles;
}
Set<BlockPosition> getLights() {
return lights;
}
} }

View File

@ -0,0 +1,186 @@
package org.bukkit.craftbukkit.generator;
import com.google.common.base.Preconditions;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.level.RegionLimitedWorldAccess;
import net.minecraft.world.entity.EntityTypes;
import net.minecraft.world.level.GeneratorAccessSeed;
import net.minecraft.world.level.biome.BiomeBase;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.IChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.TreeType;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.CraftRegionAccessor;
import org.bukkit.entity.Entity;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.LimitedRegion;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Consumer;
public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRegion {
private final WeakReference<GeneratorAccessSeed> weakAccess;
private final int centerChunkX;
private final int centerChunkZ;
// Buffer is one chunk (16 blocks), can be seen in ChunkStatus#q
// there the order is {..., FEATURES, LIQUID_CARVERS, STRUCTURE_STARTS, ...}
private final int buffer = 16;
private final BoundingBox region;
// Minecraft saves the entities as NBTTagCompound during chunk generation. This causes that
// changes made to the returned bukkit entity are not saved. To combat this we keep them and
// save them when the population is finished.
private final List<net.minecraft.world.entity.Entity> entities = new ArrayList<>();
public CraftLimitedRegion(RegionLimitedWorldAccess access) {
this.weakAccess = new WeakReference<>(access);
centerChunkX = access.a().x; // PAIL rename getCenter
centerChunkZ = access.a().z; // PAIL rename getCenter
// load entities which are already present
for (int x = -(buffer >> 4); x <= (buffer >> 4); x++) {
for (int z = -(buffer >> 4); z <= (buffer >> 4); z++) {
ProtoChunk chunk = (ProtoChunk) access.getChunkAt(centerChunkX + x, centerChunkZ + z);
for (NBTTagCompound compound : chunk.z()) { // PAIL rename getGenerationEntities
EntityTypes.a(compound, access.getMinecraftWorld(), (entity) -> { // PAIL rename fromNBTTag
entity.generation = true;
entities.add(entity);
return entity;
});
}
}
}
World world = access.getMinecraftWorld().getWorld();
int xCenter = centerChunkX << 4;
int zCenter = centerChunkZ << 4;
int xMin = xCenter - getBuffer();
int zMin = zCenter - getBuffer();
int xMax = xCenter + getBuffer() + 16;
int zMax = zCenter + getBuffer() + 16;
this.region = new BoundingBox(xMin, world.getMinHeight(), zMin, xMax, world.getMaxHeight(), zMax);
}
public GeneratorAccessSeed getHandle() {
GeneratorAccessSeed handle = weakAccess.get();
if (handle == null) {
throw new IllegalStateException("GeneratorAccessSeed no longer present, are you using it in a different tick?");
}
return handle;
}
public void saveEntities() {
GeneratorAccessSeed access = getHandle();
for (int x = -(buffer >> 4); x <= (buffer >> 4); x++) {
for (int z = -(buffer >> 4); z <= (buffer >> 4); z++) {
ProtoChunk chunk = (ProtoChunk) access.getChunkAt(centerChunkX + x, centerChunkZ + z);
chunk.z().clear(); // PAIL rename getGenerationEntities
}
}
for (net.minecraft.world.entity.Entity entity : entities) {
if (entity.isAlive()) {
// check if entity is still in region or if it got teleported outside it
Preconditions.checkState(isInRegion((int) entity.locX(), (int) entity.locY(), (int) entity.locZ()), "Entity %s is not in the region", entity);
access.addEntity(entity);
}
}
}
public void breakLink() {
weakAccess.clear();
}
@Override
public int getBuffer() {
return buffer;
}
@Override
public boolean isInRegion(Location location) {
return isInRegion(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
@Override
public boolean isInRegion(int x, int y, int z) {
return region.contains(x, y, z);
}
@Override
public Biome getBiome(int x, int y, int z) {
Preconditions.checkArgument(isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z);
return super.getBiome(x, y, z);
}
@Override
public void setBiome(int x, int y, int z, BiomeBase biomeBase) {
Preconditions.checkArgument(isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z);
IChunkAccess chunk = getHandle().getChunkAt(x >> 4, z >> 4, ChunkStatus.EMPTY);
chunk.getBiomeIndex().setBiome(x >> 2, y >> 2, z >> 2, biomeBase);
}
@Override
public BlockState getBlockState(int x, int y, int z) {
Preconditions.checkArgument(isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z);
return super.getBlockState(x, y, z);
}
@Override
public BlockData getBlockData(int x, int y, int z) {
Preconditions.checkArgument(isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z);
return super.getBlockData(x, y, z);
}
@Override
public Material getType(int x, int y, int z) {
Preconditions.checkArgument(isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z);
return super.getType(x, y, z);
}
@Override
public void setBlockData(int x, int y, int z, BlockData blockData) {
Preconditions.checkArgument(isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z);
super.setBlockData(x, y, z, blockData);
}
@Override
public boolean generateTree(Location location, Random random, TreeType treeType) {
Preconditions.checkArgument(isInRegion(location), "Coordinates %s, %s, %s are not in the region", location.getBlockX(), location.getBlockY(), location.getBlockZ());
return super.generateTree(location, random, treeType);
}
@Override
public boolean generateTree(Location location, Random random, TreeType treeType, Consumer<BlockState> consumer) {
Preconditions.checkArgument(isInRegion(location), "Coordinates %s, %s, %s are not in the region", location.getBlockX(), location.getBlockY(), location.getBlockZ());
return super.generateTree(location, random, treeType, consumer);
}
@Override
public Collection<net.minecraft.world.entity.Entity> getNMSEntities() {
return new ArrayList<>(entities);
}
@Override
public <T extends Entity> T spawn(Location location, Class<T> clazz, Consumer<T> function, CreatureSpawnEvent.SpawnReason reason) throws IllegalArgumentException {
Preconditions.checkArgument(isInRegion(location), "Coordinates %s, %s, %s are not in the region", location.getBlockX(), location.getBlockY(), location.getBlockZ());
return super.spawn(location, clazz, function, reason);
}
@Override
public void addEntityToWorld(net.minecraft.world.entity.Entity entity, CreatureSpawnEvent.SpawnReason reason) {
entities.add(entity);
}
}

View File

@ -0,0 +1,68 @@
package org.bukkit.craftbukkit.generator;
import java.util.UUID;
import net.minecraft.world.level.dimension.DimensionManager;
import net.minecraft.world.level.storage.Convertable;
import net.minecraft.world.level.storage.IWorldDataServer;
import net.minecraft.world.level.storage.WorldDataServer;
import org.bukkit.World;
import org.bukkit.craftbukkit.util.WorldUUID;
import org.bukkit.generator.WorldInfo;
public class CraftWorldInfo implements WorldInfo {
private final String name;
private final UUID uuid;
private final World.Environment environment;
private final long seed;
private final int minHeight;
private final int maxHeight;
public CraftWorldInfo(IWorldDataServer worldDataServer, Convertable.ConversionSession session, World.Environment environment, DimensionManager dimensionManager) {
this.name = worldDataServer.getName();
this.uuid = WorldUUID.getUUID(session.levelPath.toFile());
this.environment = environment;
this.seed = ((WorldDataServer) worldDataServer).getGeneratorSettings().getSeed();
this.minHeight = dimensionManager.getMinY();
this.maxHeight = dimensionManager.getMinY() + dimensionManager.getHeight();
}
public CraftWorldInfo(String name, UUID uuid, World.Environment environment, long seed, int minHeight, int maxHeight) {
this.name = name;
this.uuid = uuid;
this.environment = environment;
this.seed = seed;
this.minHeight = minHeight;
this.maxHeight = maxHeight;
}
@Override
public String getName() {
return name;
}
@Override
public UUID getUID() {
return uuid;
}
@Override
public World.Environment getEnvironment() {
return environment;
}
@Override
public long getSeed() {
return seed;
}
@Override
public int getMinHeight() {
return minHeight;
}
@Override
public int getMaxHeight() {
return maxHeight;
}
}

View File

@ -7,15 +7,11 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import net.minecraft.core.BlockPosition; import net.minecraft.core.BlockPosition;
import net.minecraft.core.IRegistry; import net.minecraft.core.IRegistry;
import net.minecraft.core.IRegistryCustom;
import net.minecraft.server.level.RegionLimitedWorldAccess; import net.minecraft.server.level.RegionLimitedWorldAccess;
import net.minecraft.server.level.WorldServer; import net.minecraft.server.level.WorldServer;
import net.minecraft.util.random.WeightedRandomList; import net.minecraft.util.random.WeightedRandomList;
import net.minecraft.world.entity.EnumCreatureType; import net.minecraft.world.entity.EnumCreatureType;
import net.minecraft.world.level.BlockColumn; import net.minecraft.world.level.BlockColumn;
import net.minecraft.world.level.GeneratorAccess;
import net.minecraft.world.level.GeneratorAccessSeed;
import net.minecraft.world.level.IBlockAccess;
import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.StructureManager; import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.biome.BiomeBase; import net.minecraft.world.level.biome.BiomeBase;
@ -30,9 +26,10 @@ import net.minecraft.world.level.chunk.ChunkSection;
import net.minecraft.world.level.chunk.IChunkAccess; import net.minecraft.world.level.chunk.IChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.levelgen.HeightMap; import net.minecraft.world.level.levelgen.HeightMap;
import net.minecraft.world.level.levelgen.SeededRandom;
import net.minecraft.world.level.levelgen.WorldGenStage; import net.minecraft.world.level.levelgen.WorldGenStage;
import net.minecraft.world.level.levelgen.structure.templatesystem.DefinedStructureManager;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.CraftHeightMap;
import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.ChunkGenerator.BiomeGrid; import org.bukkit.generator.ChunkGenerator.BiomeGrid;
@ -44,7 +41,10 @@ public class CustomChunkGenerator extends InternalChunkGenerator {
private final ChunkGenerator generator; private final ChunkGenerator generator;
private final WorldServer world; private final WorldServer world;
private final Random random = new Random(); private final Random random = new Random();
private boolean newApi;
private boolean implementBaseHeight = true;
@Deprecated
private class CustomBiomeGrid implements BiomeGrid { private class CustomBiomeGrid implements BiomeGrid {
private final BiomeStorage biome; // SPIGOT-5529: stored in 4x4 grid private final BiomeStorage biome; // SPIGOT-5529: stored in 4x4 grid
@ -90,21 +90,11 @@ public class CustomChunkGenerator extends InternalChunkGenerator {
return new CustomChunkGenerator(this.world, delegate.withSeed(i), this.generator); return new CustomChunkGenerator(this.world, delegate.withSeed(i), this.generator);
} }
@Override
public void createBiomes(IRegistry<BiomeBase> iregistry, IChunkAccess ichunkaccess) {
// Don't allow the server to override any custom biomes that have been set
}
@Override @Override
public WorldChunkManager getWorldChunkManager() { public WorldChunkManager getWorldChunkManager() {
return delegate.getWorldChunkManager(); return delegate.getWorldChunkManager();
} }
@Override
public void storeStructures(GeneratorAccessSeed generatoraccessseed, StructureManager structuremanager, IChunkAccess ichunkaccess) {
delegate.storeStructures(generatoraccessseed, structuremanager, ichunkaccess);
}
@Override @Override
public int getSeaLevel() { public int getSeaLevel() {
return delegate.getSeaLevel(); return delegate.getSeaLevel();
@ -112,25 +102,56 @@ public class CustomChunkGenerator extends InternalChunkGenerator {
@Override @Override
public void buildBase(RegionLimitedWorldAccess regionlimitedworldaccess, IChunkAccess ichunkaccess) { public void buildBase(RegionLimitedWorldAccess regionlimitedworldaccess, IChunkAccess ichunkaccess) {
// Call the bukkit ChunkGenerator before structure generation so correct biome information is available. if (generator.shouldGenerateSurface()) {
delegate.buildSurface(regionlimitedworldaccess, ichunkaccess);
}
CraftChunkData chunkData = new CraftChunkData(this.world.getWorld(), ichunkaccess);
SeededRandom random = new SeededRandom();
int x = ichunkaccess.getPos().x; int x = ichunkaccess.getPos().x;
int z = ichunkaccess.getPos().z; int z = ichunkaccess.getPos().z;
random.setSeed((long) x * 341873128712L + (long) z * 132897987541L); random.a(x, z); // PAIL rename surfaceSeeded
generator.generateSurface(this.world.getWorld(), random, x, z, chunkData);
if (generator.shouldGenerateBedrock()) {
random = new SeededRandom();
random.a(x, z); // PAIL rename surfaceSeeded
delegate.buildBedrock(ichunkaccess, random);
}
random = new SeededRandom();
random.a(x, z); // PAIL rename surfaceSeeded
generator.generateBedrock(this.world.getWorld(), random, x, z, chunkData);
chunkData.breakLink();
// return if new api is used
if (newApi) {
return;
}
// old ChunkGenerator logic, for backwards compatibility
// Call the bukkit ChunkGenerator before structure generation so correct biome information is available.
this.random.setSeed((long) x * 341873128712L + (long) z * 132897987541L);
// Get default biome data for chunk // Get default biome data for chunk
CustomBiomeGrid biomegrid = new CustomBiomeGrid(new BiomeStorage(world.t().d(IRegistry.BIOME_REGISTRY), regionlimitedworldaccess, ichunkaccess.getPos(), this.getWorldChunkManager())); CustomBiomeGrid biomegrid = new CustomBiomeGrid(new BiomeStorage(world.t().d(IRegistry.BIOME_REGISTRY), regionlimitedworldaccess, ichunkaccess.getPos(), this.getWorldChunkManager()));
ChunkData data; ChunkData data;
try {
if (generator.isParallelCapable()) { if (generator.isParallelCapable()) {
data = generator.generateChunkData(this.world.getWorld(), random, x, z, biomegrid); data = generator.generateChunkData(this.world.getWorld(), this.random, x, z, biomegrid);
} else { } else {
synchronized (this) { synchronized (this) {
data = generator.generateChunkData(this.world.getWorld(), random, x, z, biomegrid); data = generator.generateChunkData(this.world.getWorld(), this.random, x, z, biomegrid);
} }
} }
} catch (UnsupportedOperationException exception) {
newApi = true;
return;
}
Preconditions.checkArgument(data instanceof CraftChunkData, "Plugins must use createChunkData(World) rather than implementing ChunkData: %s", data); Preconditions.checkArgument(data instanceof OldCraftChunkData, "Plugins must use createChunkData(World) rather than implementing ChunkData: %s", data);
CraftChunkData craftData = (CraftChunkData) data; OldCraftChunkData craftData = (OldCraftChunkData) data;
ChunkSection[] sections = craftData.getRawChunkData(); ChunkSection[] sections = craftData.getRawChunkData();
ChunkSection[] csect = ichunkaccess.getSections(); ChunkSection[] csect = ichunkaccess.getSections();
@ -170,30 +191,60 @@ public class CustomChunkGenerator extends InternalChunkGenerator {
} }
@Override @Override
public void createStructures(IRegistryCustom iregistrycustom, StructureManager structuremanager, IChunkAccess ichunkaccess, DefinedStructureManager definedstructuremanager, long i) { public void doCarving(long seed, BiomeManager biomemanager, IChunkAccess ichunkaccess, WorldGenStage.Features worldgenstage_features) {
if (generator.shouldGenerateStructures()) {
// Still need a way of getting the biome of this chunk to pass to createStructures
// Using default biomes for now.
delegate.createStructures(iregistrycustom, structuremanager, ichunkaccess, definedstructuremanager, i);
}
}
@Override
public void doCarving(long i, BiomeManager biomemanager, IChunkAccess ichunkaccess, WorldGenStage.Features worldgenstage_features) {
if (generator.shouldGenerateCaves()) { if (generator.shouldGenerateCaves()) {
delegate.doCarving(i, biomemanager, ichunkaccess, worldgenstage_features); super.doCarving(seed, biomemanager, ichunkaccess, worldgenstage_features);
}
if (worldgenstage_features == WorldGenStage.Features.LIQUID) { // stage check ensures that the method is only called once
CraftChunkData chunkData = new CraftChunkData(this.world.getWorld(), ichunkaccess);
SeededRandom random = new SeededRandom();
int x = ichunkaccess.getPos().x;
int z = ichunkaccess.getPos().z;
random.c(seed, 0, 0); // PAIL rename carvingSeeded
generator.generateCaves(this.world.getWorld(), random, x, z, chunkData);
chunkData.breakLink();
} }
} }
@Override @Override
public CompletableFuture<IChunkAccess> buildNoise(Executor executor, StructureManager structuremanager, IChunkAccess ichunkaccess) { public CompletableFuture<IChunkAccess> buildNoise(Executor executor, StructureManager structuremanager, IChunkAccess ichunkaccess) {
// Disable vanilla generation CompletableFuture<IChunkAccess> future = null;
return CompletableFuture.completedFuture(ichunkaccess); if (generator.shouldGenerateNoise()) {
future = delegate.buildNoise(executor, structuremanager, ichunkaccess);
}
java.util.function.Function<IChunkAccess, IChunkAccess> function = (ichunkaccess1) -> {
CraftChunkData chunkData = new CraftChunkData(this.world.getWorld(), ichunkaccess1);
SeededRandom random = new SeededRandom();
int x = ichunkaccess1.getPos().x;
int z = ichunkaccess1.getPos().z;
random.setSeed((long) x * 341873128712L + (long) z * 132897987541L);
generator.generateNoise(this.world.getWorld(), random, x, z, chunkData);
chunkData.breakLink();
return ichunkaccess1;
};
return future == null ? CompletableFuture.supplyAsync(() -> function.apply(ichunkaccess), net.minecraft.SystemUtils.f()) : future.thenApply(function);
} }
@Override @Override
public int getBaseHeight(int i, int j, HeightMap.Type heightmap_type, LevelHeightAccessor levelheightaccessor) { public int getBaseHeight(int i, int j, HeightMap.Type heightmap_type, LevelHeightAccessor levelheightaccessor) {
if (implementBaseHeight) {
try {
SeededRandom random = new SeededRandom();
int xChunk = i >> 4;
int zChunk = j >> 4;
random.setSeed((long) xChunk * 341873128712L + (long) zChunk * 132897987541L);
return generator.getBaseHeight(this.world.getWorld(), random, i, j, CraftHeightMap.fromNMS(heightmap_type));
} catch (UnsupportedOperationException exception) {
implementBaseHeight = false;
}
}
return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor); return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor);
} }
@ -204,9 +255,7 @@ public class CustomChunkGenerator extends InternalChunkGenerator {
@Override @Override
public void addDecorations(RegionLimitedWorldAccess regionlimitedworldaccess, StructureManager structuremanager) { public void addDecorations(RegionLimitedWorldAccess regionlimitedworldaccess, StructureManager structuremanager) {
if (generator.shouldGenerateDecorations()) { super.addDecorations(regionlimitedworldaccess, structuremanager, generator.shouldGenerateDecorations());
delegate.addDecorations(regionlimitedworldaccess, structuremanager);
}
} }
@Override @Override

View File

@ -0,0 +1,58 @@
package org.bukkit.craftbukkit.generator;
import com.google.common.base.Preconditions;
import com.mojang.serialization.Codec;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.core.IRegistry;
import net.minecraft.world.level.biome.BiomeBase;
import net.minecraft.world.level.biome.WorldChunkManager;
import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.WorldInfo;
public class CustomWorldChunkManager extends WorldChunkManager {
private final WorldInfo worldInfo;
private final BiomeProvider biomeProvider;
private final IRegistry<BiomeBase> registry;
private static List<BiomeBase> biomeListToBiomeBaseList(List<Biome> biomes, IRegistry<BiomeBase> registry) {
List<BiomeBase> biomeBases = new ArrayList<>();
for (Biome biome : biomes) {
Preconditions.checkArgument(biome != Biome.CUSTOM, "Cannot use the biome %s", biome);
biomeBases.add(CraftBlock.biomeToBiomeBase(registry, biome));
}
return biomeBases;
}
public CustomWorldChunkManager(WorldInfo worldInfo, BiomeProvider biomeProvider, IRegistry<BiomeBase> registry) {
super(biomeListToBiomeBaseList(biomeProvider.getBiomes(worldInfo), registry));
this.worldInfo = worldInfo;
this.biomeProvider = biomeProvider;
this.registry = registry;
}
@Override
protected Codec<? extends WorldChunkManager> a() {
throw new UnsupportedOperationException("Cannot serialize CustomWorldChunkManager");
}
@Override
public WorldChunkManager a(long l) {
// TODO check method further
throw new UnsupportedOperationException("Cannot copy CustomWorldChunkManager");
}
@Override
public BiomeBase getBiome(int x, int y, int z) {
Biome biome = biomeProvider.getBiome(worldInfo, x << 2, y << 2, z << 2);
Preconditions.checkArgument(biome != Biome.CUSTOM, "Cannot set the biome to %s", biome);
return CraftBlock.biomeToBiomeBase(registry, biome);
}
}

View File

@ -0,0 +1,196 @@
package org.bukkit.craftbukkit.generator;
import java.util.HashSet;
import java.util.Set;
import net.minecraft.core.BlockPosition;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.IBlockData;
import net.minecraft.world.level.chunk.ChunkSection;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.material.MaterialData;
/**
* Data to be used for the block types and data in a newly generated chunk.
*/
@Deprecated
public final class OldCraftChunkData implements ChunkGenerator.ChunkData {
private final int minHeight;
private final int maxHeight;
private final ChunkSection[] sections;
private Set<BlockPosition> tiles;
private final Set<BlockPosition> lights = new HashSet<>();
public OldCraftChunkData(World world) {
this(world.getMinHeight(), world.getMaxHeight());
}
/* pp for tests */ OldCraftChunkData(int minHeight, int maxHeight) {
this.minHeight = minHeight;
this.maxHeight = maxHeight;
sections = new ChunkSection[(((maxHeight - 1) >> 4) + 1) - (minHeight >> 4)];
}
@Override
public int getMinHeight() {
return minHeight;
}
@Override
public int getMaxHeight() {
return maxHeight;
}
@Override
public Biome getBiome(int x, int y, int z) {
throw new UnsupportedOperationException("Unsupported, in older chunk generator api");
}
@Override
public void setBlock(int x, int y, int z, Material material) {
setBlock(x, y, z, material.createBlockData());
}
@Override
public void setBlock(int x, int y, int z, MaterialData material) {
setBlock(x, y, z, CraftMagicNumbers.getBlock(material));
}
@Override
public void setBlock(int x, int y, int z, BlockData blockData) {
setBlock(x, y, z, ((CraftBlockData) blockData).getState());
}
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, Material material) {
setRegion(xMin, yMin, zMin, xMax, yMax, zMax, material.createBlockData());
}
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, MaterialData material) {
setRegion(xMin, yMin, zMin, xMax, yMax, zMax, CraftMagicNumbers.getBlock(material));
}
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, BlockData blockData) {
setRegion(xMin, yMin, zMin, xMax, yMax, zMax, ((CraftBlockData) blockData).getState());
}
@Override
public Material getType(int x, int y, int z) {
return CraftMagicNumbers.getMaterial(getTypeId(x, y, z).getBlock());
}
@Override
public MaterialData getTypeAndData(int x, int y, int z) {
return CraftMagicNumbers.getMaterial(getTypeId(x, y, z));
}
@Override
public BlockData getBlockData(int x, int y, int z) {
return CraftBlockData.fromData(getTypeId(x, y, z));
}
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, IBlockData type) {
// Clamp to sane values.
if (xMin > 0xf || yMin >= maxHeight || zMin > 0xf) {
return;
}
if (xMin < 0) {
xMin = 0;
}
if (yMin < minHeight) {
yMin = minHeight;
}
if (zMin < 0) {
zMin = 0;
}
if (xMax > 0x10) {
xMax = 0x10;
}
if (yMax > maxHeight) {
yMax = maxHeight;
}
if (zMax > 0x10) {
zMax = 0x10;
}
if (xMin >= xMax || yMin >= yMax || zMin >= zMax) {
return;
}
for (int y = yMin; y < yMax; y++) {
ChunkSection section = getChunkSection(y, true);
int offsetBase = y & 0xf;
for (int x = xMin; x < xMax; x++) {
for (int z = zMin; z < zMax; z++) {
section.setType(x, offsetBase, z, type);
}
}
}
}
public IBlockData getTypeId(int x, int y, int z) {
if (x != (x & 0xf) || y < minHeight || y >= maxHeight || z != (z & 0xf)) {
return Blocks.AIR.getBlockData();
}
ChunkSection section = getChunkSection(y, false);
if (section == null) {
return Blocks.AIR.getBlockData();
} else {
return section.getType(x, y & 0xf, z);
}
}
@Override
public byte getData(int x, int y, int z) {
return CraftMagicNumbers.toLegacyData(getTypeId(x, y, z));
}
private void setBlock(int x, int y, int z, IBlockData type) {
if (x != (x & 0xf) || y < minHeight || y >= maxHeight || z != (z & 0xf)) {
return;
}
ChunkSection section = getChunkSection(y, true);
section.setType(x, y & 0xf, z, type);
// SPIGOT-1753: Capture light blocks, for light updates
if (type.f() > 0) { // PAIL rename getLightEmission
lights.add(new BlockPosition(x, y, z));
} else {
lights.remove(new BlockPosition(x, y, z));
}
if (type.isTileEntity()) {
if (tiles == null) {
tiles = new HashSet<>();
}
tiles.add(new BlockPosition(x, y, z));
}
}
private ChunkSection getChunkSection(int y, boolean create) {
int offset = (y - minHeight) >> 4;
ChunkSection section = sections[offset];
if (create && section == null) {
sections[offset] = section = new ChunkSection(offset + (minHeight >> 4));
}
return section;
}
ChunkSection[] getRawChunkData() {
return sections;
}
Set<BlockPosition> getTiles() {
return tiles;
}
Set<BlockPosition> getLights() {
return lights;
}
}

View File

@ -4,22 +4,25 @@ import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate;
import net.minecraft.core.BlockPosition; import net.minecraft.core.BlockPosition;
import net.minecraft.world.level.World; import net.minecraft.world.level.GeneratorAccess;
import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.level.block.state.IBlockData;
import net.minecraft.world.level.dimension.DimensionManager;
import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluid;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.block.CraftBlockState;
public class BlockStateListPopulator extends DummyGeneratorAccess { public class BlockStateListPopulator extends DummyGeneratorAccess {
private final World world; private final GeneratorAccess world;
private final LinkedHashMap<BlockPosition, CraftBlockState> list; private final LinkedHashMap<BlockPosition, CraftBlockState> list;
public BlockStateListPopulator(World world) { public BlockStateListPopulator(GeneratorAccess world) {
this(world, new LinkedHashMap<>()); this(world, new LinkedHashMap<>());
} }
public BlockStateListPopulator(World world, LinkedHashMap<BlockPosition, CraftBlockState> list) { public BlockStateListPopulator(GeneratorAccess world, LinkedHashMap<BlockPosition, CraftBlockState> list) {
this.world = world; this.world = world;
this.list = list; this.list = list;
} }
@ -38,7 +41,8 @@ public class BlockStateListPopulator extends DummyGeneratorAccess {
@Override @Override
public boolean setTypeAndData(BlockPosition position, IBlockData data, int flag) { public boolean setTypeAndData(BlockPosition position, IBlockData data, int flag) {
CraftBlockState state = CraftBlockState.getBlockState(world, position, flag); CraftBlockState state = (CraftBlockState) CraftBlock.at(world, position).getState();
state.setFlag(flag);
state.setData(data); state.setData(data);
// remove first to keep insertion order // remove first to keep insertion order
list.remove(position); list.remove(position);
@ -60,7 +64,28 @@ public class BlockStateListPopulator extends DummyGeneratorAccess {
return new ArrayList<>(list.values()); return new ArrayList<>(list.values());
} }
public World getWorld() { public GeneratorAccess getWorld() {
return world; return world;
} }
// For tree generation
@Override
public int getMinBuildHeight() {
return getWorld().getMinBuildHeight();
}
@Override
public int getHeight() {
return getWorld().getHeight();
}
@Override
public boolean a(BlockPosition blockposition, Predicate<IBlockData> predicate) {
return predicate.test(getType(blockposition));
}
@Override
public DimensionManager getDimensionManager() {
return world.getDimensionManager();
}
} }

View File

@ -3,9 +3,11 @@ package org.bukkit.craftbukkit.util;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Stream;
import net.minecraft.core.BlockPosition; import net.minecraft.core.BlockPosition;
import net.minecraft.core.EnumDirection; import net.minecraft.core.EnumDirection;
import net.minecraft.core.IRegistryCustom; import net.minecraft.core.IRegistryCustom;
import net.minecraft.core.SectionPosition;
import net.minecraft.core.particles.ParticleParam; import net.minecraft.core.particles.ParticleParam;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.WorldServer; import net.minecraft.server.level.WorldServer;
@ -14,7 +16,7 @@ import net.minecraft.sounds.SoundEffect;
import net.minecraft.world.DifficultyDamageScaler; import net.minecraft.world.DifficultyDamageScaler;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.EntityHuman; import net.minecraft.world.entity.player.EntityHuman;
import net.minecraft.world.level.GeneratorAccess; import net.minecraft.world.level.GeneratorAccessSeed;
import net.minecraft.world.level.TickList; import net.minecraft.world.level.TickList;
import net.minecraft.world.level.TickListEmpty; import net.minecraft.world.level.TickListEmpty;
import net.minecraft.world.level.biome.BiomeBase; import net.minecraft.world.level.biome.BiomeBase;
@ -31,6 +33,8 @@ import net.minecraft.world.level.dimension.DimensionManager;
import net.minecraft.world.level.entity.EntityTypeTest; import net.minecraft.world.level.entity.EntityTypeTest;
import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.levelgen.HeightMap; import net.minecraft.world.level.levelgen.HeightMap;
import net.minecraft.world.level.levelgen.feature.StructureGenerator;
import net.minecraft.world.level.levelgen.structure.StructureStart;
import net.minecraft.world.level.lighting.LightEngine; import net.minecraft.world.level.lighting.LightEngine;
import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidType; import net.minecraft.world.level.material.FluidType;
@ -38,9 +42,9 @@ import net.minecraft.world.level.material.FluidTypes;
import net.minecraft.world.level.storage.WorldData; import net.minecraft.world.level.storage.WorldData;
import net.minecraft.world.phys.AxisAlignedBB; import net.minecraft.world.phys.AxisAlignedBB;
public class DummyGeneratorAccess implements GeneratorAccess { public class DummyGeneratorAccess implements GeneratorAccessSeed {
public static final GeneratorAccess INSTANCE = new DummyGeneratorAccess(); public static final GeneratorAccessSeed INSTANCE = new DummyGeneratorAccess();
protected DummyGeneratorAccess() { protected DummyGeneratorAccess() {
} }
@ -100,6 +104,11 @@ public class DummyGeneratorAccess implements GeneratorAccess {
throw new UnsupportedOperationException("Not supported yet."); throw new UnsupportedOperationException("Not supported yet.");
} }
@Override
public WorldServer getLevel() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override @Override
public WorldServer getMinecraftWorld() { public WorldServer getMinecraftWorld() {
throw new UnsupportedOperationException("Not supported yet."); throw new UnsupportedOperationException("Not supported yet.");
@ -219,4 +228,14 @@ public class DummyGeneratorAccess implements GeneratorAccess {
public boolean a(BlockPosition blockposition, boolean flag, Entity entity, int i) { public boolean a(BlockPosition blockposition, boolean flag, Entity entity, int i) {
return false; // SPIGOT-6515 return false; // SPIGOT-6515
} }
@Override
public long getSeed() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Stream<? extends StructureStart<?>> a(SectionPosition sectionPosition, StructureGenerator<?> structureGenerator) {
throw new UnsupportedOperationException("Not supported yet.");
}
} }

View File

@ -11,12 +11,12 @@ public class ChunkDataTest extends AbstractTestingBase {
private static final BlockData RED_WOOL = Material.RED_WOOL.createBlockData(); private static final BlockData RED_WOOL = Material.RED_WOOL.createBlockData();
private static final BlockData AIR = Material.AIR.createBlockData(); private static final BlockData AIR = Material.AIR.createBlockData();
private boolean testSetBlock(CraftChunkData data, int x, int y, int z, BlockData type, BlockData expected) { private boolean testSetBlock(OldCraftChunkData data, int x, int y, int z, BlockData type, BlockData expected) {
data.setBlock(x, y, z, type); data.setBlock(x, y, z, type);
return expected.equals(data.getBlockData(x, y, z)) && expected.getMaterial().equals(data.getType(x, y, z)); return expected.equals(data.getBlockData(x, y, z)) && expected.getMaterial().equals(data.getType(x, y, z));
} }
private void testSetRegion(CraftChunkData data, int minx, int miny, int minz, int maxx, int maxy, int maxz, BlockData type) { private void testSetRegion(OldCraftChunkData data, int minx, int miny, int minz, int maxx, int maxy, int maxz, BlockData type) {
data.setRegion(minx, miny, minz, maxx, maxy, maxz, type); data.setRegion(minx, miny, minz, maxx, maxy, maxz, type);
for (int y = 0; y < data.getMaxHeight(); y++) { for (int y = 0; y < data.getMaxHeight(); y++) {
for (int z = 0; z < 16; z++) { for (int z = 0; z < 16; z++) {
@ -34,21 +34,21 @@ public class ChunkDataTest extends AbstractTestingBase {
@Test @Test
public void testMinHeight() { public void testMinHeight() {
CraftChunkData data = new CraftChunkData(-128, 128); OldCraftChunkData data = new OldCraftChunkData(-128, 128);
assertTrue("Could not set block below min height", testSetBlock(data, 0, -256, 0, RED_WOOL, AIR)); assertTrue("Could not set block below min height", testSetBlock(data, 0, -256, 0, RED_WOOL, AIR));
assertTrue("Could set block above min height", testSetBlock(data, 0, -64, 0, RED_WOOL, RED_WOOL)); assertTrue("Could set block above min height", testSetBlock(data, 0, -64, 0, RED_WOOL, RED_WOOL));
} }
@Test @Test
public void testMaxHeight() { public void testMaxHeight() {
CraftChunkData data = new CraftChunkData(0, 128); OldCraftChunkData data = new OldCraftChunkData(0, 128);
assertTrue("Could not set block above max height", testSetBlock(data, 0, 128, 0, RED_WOOL, AIR)); assertTrue("Could not set block above max height", testSetBlock(data, 0, 128, 0, RED_WOOL, AIR));
assertTrue("Could set block below max height", testSetBlock(data, 0, 127, 0, RED_WOOL, RED_WOOL)); assertTrue("Could set block below max height", testSetBlock(data, 0, 127, 0, RED_WOOL, RED_WOOL));
} }
@Test @Test
public void testBoundsCheckingSingle() { public void testBoundsCheckingSingle() {
CraftChunkData data = new CraftChunkData(0, 256); OldCraftChunkData data = new OldCraftChunkData(0, 256);
assertTrue("Can set block inside chunk bounds", testSetBlock(data, 0, 0, 0, RED_WOOL, RED_WOOL)); assertTrue("Can set block inside chunk bounds", testSetBlock(data, 0, 0, 0, RED_WOOL, RED_WOOL));
assertTrue("Can set block inside chunk bounds", testSetBlock(data, 15, 255, 15, RED_WOOL, RED_WOOL)); assertTrue("Can set block inside chunk bounds", testSetBlock(data, 15, 255, 15, RED_WOOL, RED_WOOL));
assertTrue("Can no set block outside chunk bounds", testSetBlock(data, -1, 0, 0, RED_WOOL, AIR)); assertTrue("Can no set block outside chunk bounds", testSetBlock(data, -1, 0, 0, RED_WOOL, AIR));
@ -61,7 +61,7 @@ public class ChunkDataTest extends AbstractTestingBase {
@Test @Test
public void testSetRegion() { public void testSetRegion() {
CraftChunkData data = new CraftChunkData(0, 256); OldCraftChunkData data = new OldCraftChunkData(0, 256);
testSetRegion(data, -100, 0, -100, 0, 256, 0, RED_WOOL); // exclusively outside testSetRegion(data, -100, 0, -100, 0, 256, 0, RED_WOOL); // exclusively outside
testSetRegion(data, 16, 256, 16, 0, 0, 0, RED_WOOL); // minimum >= maximum testSetRegion(data, 16, 256, 16, 0, 0, 0, RED_WOOL); // minimum >= maximum
testSetRegion(data, 0, 0, 0, 0, 0, 0, RED_WOOL); // minimum == maximum testSetRegion(data, 0, 0, 0, 0, 0, 0, RED_WOOL); // minimum == maximum