mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-07-19 13:26:01 +00:00
Headless Classload
This commit is contained in:
@@ -23,6 +23,7 @@ import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||
import art.arcane.iris.core.service.ObjectStudioSaveService;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.IrisStructureLocator;
|
||||
import art.arcane.iris.engine.platform.EngineBukkitOps;
|
||||
import art.arcane.iris.engine.framework.StructureReachability;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisRegion;
|
||||
@@ -57,7 +58,7 @@ public class CommandFind implements DirectorExecutor {
|
||||
return;
|
||||
}
|
||||
|
||||
e.gotoBiome(biome, player(), teleport);
|
||||
EngineBukkitOps.gotoBiome(e, biome, player(), teleport);
|
||||
}
|
||||
|
||||
@Director(description = "Find a region")
|
||||
@@ -74,7 +75,7 @@ public class CommandFind implements DirectorExecutor {
|
||||
return;
|
||||
}
|
||||
|
||||
e.gotoRegion(region, player(), teleport);
|
||||
EngineBukkitOps.gotoRegion(e, region, player(), teleport);
|
||||
}
|
||||
|
||||
@Director(description = "Find a point of interest.")
|
||||
@@ -90,7 +91,7 @@ public class CommandFind implements DirectorExecutor {
|
||||
return;
|
||||
}
|
||||
|
||||
e.gotoPOI(type, player(), teleport);
|
||||
EngineBukkitOps.gotoPOI(e, type, player(), teleport);
|
||||
}
|
||||
|
||||
@Director(description = "Find a structure (a vanilla key like minecraft:village_plains or minecraft:stronghold, or an imported iris structure key)")
|
||||
@@ -106,7 +107,7 @@ public class CommandFind implements DirectorExecutor {
|
||||
}
|
||||
|
||||
if (IrisStructureLocator.isPlaced(e, structure)) {
|
||||
e.gotoStructure(structure, player(), true);
|
||||
EngineBukkitOps.gotoStructure(e, structure, player(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -180,7 +181,7 @@ public class CommandFind implements DirectorExecutor {
|
||||
}
|
||||
|
||||
if (e.hasObjectPlacement(object)) {
|
||||
e.gotoObject(object, player(), teleport);
|
||||
EngineBukkitOps.gotoObject(e, object, player(), teleport);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -32,6 +32,7 @@ import art.arcane.iris.core.structure.StructureImporter;
|
||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.object.*;
|
||||
import art.arcane.iris.engine.platform.EngineBukkitOps;
|
||||
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
@@ -246,11 +247,11 @@ public class CommandStudio implements DirectorExecutor {
|
||||
) {
|
||||
if (noStudio()) return;
|
||||
|
||||
KList<IrisLootTable> tables = engine().getLootTables(RNG.r, player().getLocation().getBlock());
|
||||
KList<IrisLootTable> tables = EngineBukkitOps.getLootTables(engine(), RNG.r, player().getLocation().getBlock());
|
||||
Inventory inv = Bukkit.createInventory(null, 27 * 2);
|
||||
|
||||
try {
|
||||
engine().addItems(true, inv, RNG.r, tables, InventorySlotType.STORAGE, player().getWorld(), player().getLocation().getBlockX(), player().getLocation().getBlockY(), player().getLocation().getBlockZ(), 1);
|
||||
EngineBukkitOps.addItems(engine(), true, inv, RNG.r, tables, InventorySlotType.STORAGE, player().getWorld(), player().getLocation().getBlockX(), player().getLocation().getBlockY(), player().getLocation().getBlockZ(), 1);
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
sender().sendMessage(C.RED + "Cannot add items to virtual inventory because of: " + e.getMessage());
|
||||
@@ -277,7 +278,7 @@ public class CommandStudio implements DirectorExecutor {
|
||||
inv.clear();
|
||||
}
|
||||
|
||||
engine.addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player.getWorld(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ(), 1);
|
||||
EngineBukkitOps.addItems(engine, true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player.getWorld(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ(), 1);
|
||||
}, fast ? 5 : 35));
|
||||
|
||||
sender().sendMessage(C.GREEN + "Opening inventory now!");
|
||||
|
||||
@@ -26,6 +26,7 @@ import art.arcane.iris.core.edit.BlockSignal;
|
||||
import art.arcane.iris.core.nms.INMS;
|
||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.platform.EngineBukkitOps;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisRegion;
|
||||
import art.arcane.iris.util.common.director.DirectorExecutor;
|
||||
@@ -96,7 +97,7 @@ public class CommandWhat implements DirectorExecutor {
|
||||
public void region() {
|
||||
try {
|
||||
Chunk chunk = world().getChunkAt(player().getLocation().getBlockZ() / 16, player().getLocation().getBlockZ() / 16);
|
||||
IrisRegion r = engine().getRegion(chunk);
|
||||
IrisRegion r = EngineBukkitOps.getRegion(engine(), chunk);
|
||||
sender().sendMessage("IRegion: " + r.getLoadKey() + " (" + r.getName() + ")");
|
||||
|
||||
} catch (Throwable e) {
|
||||
|
||||
+4
-3
@@ -21,6 +21,7 @@ package art.arcane.iris.core.link;
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.platform.EngineBukkitOps;
|
||||
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import org.bukkit.Location;
|
||||
@@ -73,15 +74,15 @@ public class IrisPapiExpansion extends PlaceholderExpansion {
|
||||
}
|
||||
} else if (p.equalsIgnoreCase("region_name")) {
|
||||
if (a != null) {
|
||||
return a.getEngine().getRegion(l).getName();
|
||||
return EngineBukkitOps.getRegion(a.getEngine(), l).getName();
|
||||
}
|
||||
} else if (p.equalsIgnoreCase("region_id")) {
|
||||
if (a != null) {
|
||||
return a.getEngine().getRegion(l).getLoadKey();
|
||||
return EngineBukkitOps.getRegion(a.getEngine(), l).getLoadKey();
|
||||
}
|
||||
} else if (p.equalsIgnoreCase("region_file")) {
|
||||
if (a != null) {
|
||||
return a.getEngine().getRegion(l).getLoadFile().getPath();
|
||||
return EngineBukkitOps.getRegion(a.getEngine(), l).getLoadFile().getPath();
|
||||
}
|
||||
} else if (p.equalsIgnoreCase("terrain_slope")) {
|
||||
if (a != null) {
|
||||
|
||||
@@ -51,7 +51,6 @@ art/arcane/iris/core/runtime/ChunkClearer.java
|
||||
art/arcane/iris/core/runtime/ChunkJobReporter.java
|
||||
art/arcane/iris/core/runtime/GoldenHashScanner.java
|
||||
art/arcane/iris/core/runtime/InPlaceChunkRegenerator.java
|
||||
art/arcane/iris/core/runtime/ObjectStudioLayout.java
|
||||
art/arcane/iris/core/runtime/PaperLikeRuntimeControlBackend.java
|
||||
art/arcane/iris/core/runtime/StudioOpenCoordinator.java
|
||||
art/arcane/iris/core/runtime/WorldRuntimeControlBackend.java
|
||||
@@ -83,12 +82,10 @@ art/arcane/iris/engine/actuator/IrisBiomeActuator.java
|
||||
art/arcane/iris/engine/data/chunk/LinkedTerrainChunk.java
|
||||
art/arcane/iris/engine/data/chunk/TerrainChunk.java
|
||||
art/arcane/iris/engine/decorator/DecoratorCore.java
|
||||
art/arcane/iris/engine/framework/BlockUpdater.java
|
||||
art/arcane/iris/engine/framework/Engine.java
|
||||
art/arcane/iris/engine/framework/EngineAssignedWorldManager.java
|
||||
art/arcane/iris/engine/framework/EnginePlayer.java
|
||||
art/arcane/iris/engine/framework/EngineWorldManager.java
|
||||
art/arcane/iris/engine/framework/LootProvider.java
|
||||
art/arcane/iris/engine/framework/placer/WorldObjectPlacer.java
|
||||
art/arcane/iris/engine/mantle/EngineMantle.java
|
||||
art/arcane/iris/engine/mantle/MantleWriter.java
|
||||
@@ -123,7 +120,6 @@ art/arcane/iris/engine/object/IrisLootTable.java
|
||||
art/arcane/iris/engine/object/IrisObject.java
|
||||
art/arcane/iris/engine/object/IrisObjectPlacement.java
|
||||
art/arcane/iris/engine/object/IrisObjectRotation.java
|
||||
art/arcane/iris/engine/object/IrisObjectTranslate.java
|
||||
art/arcane/iris/engine/object/IrisPotionEffect.java
|
||||
art/arcane/iris/engine/object/IrisProceduralBlocks.java
|
||||
art/arcane/iris/engine/object/IrisSurface.java
|
||||
@@ -151,6 +147,7 @@ art/arcane/iris/engine/object/tree/TreePlausibility.java
|
||||
art/arcane/iris/engine/platform/BukkitChunkGenerator.java
|
||||
art/arcane/iris/engine/platform/DummyBiomeProvider.java
|
||||
art/arcane/iris/engine/platform/DummyChunkGenerator.java
|
||||
art/arcane/iris/engine/platform/EngineBukkitOps.java
|
||||
art/arcane/iris/engine/platform/studio/generators/ObjectStudioGenerator.java
|
||||
art/arcane/iris/platform/bukkit/BukkitBiome.java
|
||||
art/arcane/iris/platform/bukkit/BukkitBlockResolution.java
|
||||
@@ -162,7 +159,6 @@ art/arcane/iris/platform/bukkit/BukkitRegistries.java
|
||||
art/arcane/iris/platform/bukkit/BukkitScheduler.java
|
||||
art/arcane/iris/platform/bukkit/BukkitWorld.java
|
||||
art/arcane/iris/util/common/data/IrisCustomData.java
|
||||
art/arcane/iris/util/common/data/VectorMap.java
|
||||
art/arcane/iris/util/common/data/registry/Attributes.java
|
||||
art/arcane/iris/util/common/data/registry/KeyedRegistry.java
|
||||
art/arcane/iris/util/common/data/registry/Materials.java
|
||||
@@ -183,7 +179,6 @@ art/arcane/iris/util/common/inventorygui/Window.java
|
||||
art/arcane/iris/util/common/inventorygui/WindowResolution.java
|
||||
art/arcane/iris/util/common/math/AxisAlignedBB.java
|
||||
art/arcane/iris/util/common/math/Direction.java
|
||||
art/arcane/iris/util/common/math/Vector3i.java
|
||||
art/arcane/iris/util/common/math/VectorMath.java
|
||||
art/arcane/iris/util/common/misc/Bindings.java
|
||||
art/arcane/iris/util/common/nbt/mca/Chunk.java
|
||||
|
||||
@@ -21,6 +21,7 @@ package art.arcane.iris.core.runtime;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.core.nms.INMS;
|
||||
import art.arcane.iris.engine.data.chunk.TerrainChunk;
|
||||
import art.arcane.iris.engine.platform.EngineBukkitOps;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.mantle.EngineMantle;
|
||||
import art.arcane.iris.spi.PlatformBiome;
|
||||
@@ -175,7 +176,7 @@ public final class InPlaceChunkRegenerator {
|
||||
}
|
||||
}
|
||||
|
||||
engine.updateChunk(chunk);
|
||||
EngineBukkitOps.updateChunk(engine, chunk);
|
||||
world.refreshChunk(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import art.arcane.iris.core.tools.IrisToolbelt;
|
||||
import art.arcane.iris.engine.data.cache.Cache;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.EngineAssignedWorldManager;
|
||||
import art.arcane.iris.engine.platform.EngineBukkitOps;
|
||||
import art.arcane.iris.engine.object.*;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
@@ -281,7 +282,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
warmupMantleChunkAsync(chunkX, chunkZ);
|
||||
return;
|
||||
}
|
||||
getEngine().updateChunk(chunk);
|
||||
EngineBukkitOps.updateChunk(getEngine(), chunk);
|
||||
}
|
||||
|
||||
if (!isEntitySpawningEnabledForCurrentWorld()) {
|
||||
@@ -585,7 +586,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
Predicate<IrisSpawner> filter = i -> i.canSpawn(getEngine(), c.getX(), c.getZ());
|
||||
ChunkCounter counter = new ChunkCounter(c.getEntities());
|
||||
|
||||
IrisBiome biome = getEngine().getSurfaceBiome(c);
|
||||
IrisBiome biome = EngineBukkitOps.getSurfaceBiome(getEngine(), c);
|
||||
IrisEntitySpawn v = spawnRandomly(Stream.concat(getData().getSpawnerLoader()
|
||||
.loadAll(getDimension().getEntitySpawners())
|
||||
.shuffleCopy(RNG.r)
|
||||
@@ -978,11 +979,11 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
});
|
||||
|
||||
KList<ItemStack> d = new KList<>();
|
||||
IrisBiome b = getEngine().getBiome(e.getBlock().getLocation().clone().subtract(0, getEngine().getWorld().minHeight(), 0));
|
||||
IrisBiome b = EngineBukkitOps.getBiome(getEngine(), e.getBlock().getLocation().clone().subtract(0, getEngine().getWorld().minHeight(), 0));
|
||||
List<IrisBlockDrops> dropProviders = filterDrops(b.getBlockDrops(), e, getData());
|
||||
|
||||
if (dropProviders.stream().noneMatch(IrisBlockDrops::isSkipParents)) {
|
||||
IrisRegion r = getEngine().getRegion(e.getBlock().getLocation());
|
||||
IrisRegion r = EngineBukkitOps.getRegion(getEngine(), e.getBlock().getLocation());
|
||||
dropProviders.addAll(filterDrops(r.getBlockDrops(), e, getData()));
|
||||
dropProviders.addAll(filterDrops(getEngine().getDimension().getBlockDrops(), e, getData()));
|
||||
}
|
||||
|
||||
@@ -19,16 +19,8 @@
|
||||
package art.arcane.iris.engine.framework;
|
||||
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.volmlib.util.mantle.runtime.MantleChunk;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import art.arcane.volmlib.util.matter.Matter;
|
||||
import org.bukkit.Chunk;
|
||||
|
||||
public interface BlockUpdater {
|
||||
|
||||
void catchBlockUpdates(int x, int y, int z, PlatformBlockState data);
|
||||
|
||||
void updateChunk(Chunk c);
|
||||
|
||||
void update(int x, int y, int z, Chunk c, MantleChunk<Matter> mc, RNG rf);
|
||||
}
|
||||
|
||||
@@ -20,30 +20,23 @@ package art.arcane.iris.engine.framework;
|
||||
|
||||
import art.arcane.iris.platform.bukkit.BukkitBlockResolution;
|
||||
|
||||
import art.arcane.iris.spi.IrisServices;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.iris.core.events.IrisLootEvent;
|
||||
import art.arcane.iris.engine.framework.render.RenderType;
|
||||
import art.arcane.iris.engine.framework.render.Renderer;
|
||||
import art.arcane.iris.core.gui.PregeneratorJob;
|
||||
import art.arcane.iris.core.link.Identifier;
|
||||
import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.core.loader.IrisRegistrant;
|
||||
import art.arcane.iris.core.nms.container.BlockPos;
|
||||
import art.arcane.iris.core.nms.container.Pair;
|
||||
import art.arcane.iris.core.service.ExternalDataSVC;
|
||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||
import art.arcane.iris.engine.IrisComplex;
|
||||
import art.arcane.iris.engine.UpperDimensionContext;
|
||||
import art.arcane.iris.engine.data.cache.Cache;
|
||||
import art.arcane.iris.engine.data.chunk.TerrainChunk;
|
||||
import art.arcane.iris.engine.mantle.EngineMantle;
|
||||
import art.arcane.iris.engine.object.*;
|
||||
import art.arcane.iris.platform.bukkit.BukkitBlockState;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.spi.PlatformBiome;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.util.project.matter.TileWrapper;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import art.arcane.iris.util.project.context.ChunkContext;
|
||||
@@ -52,48 +45,30 @@ import art.arcane.iris.util.common.data.DataProvider;
|
||||
import art.arcane.iris.util.common.data.IrisCustomData;
|
||||
import art.arcane.volmlib.util.documentation.BlockCoordinates;
|
||||
import art.arcane.volmlib.util.documentation.ChunkCoordinates;
|
||||
import art.arcane.iris.util.common.format.C;
|
||||
import art.arcane.volmlib.util.function.Function2;
|
||||
import art.arcane.iris.util.project.hunk.Hunk;
|
||||
import art.arcane.volmlib.util.mantle.runtime.MantleChunk;
|
||||
import art.arcane.volmlib.util.mantle.flag.MantleFlag;
|
||||
import art.arcane.volmlib.util.math.BlockPosition;
|
||||
import art.arcane.volmlib.util.format.Form;
|
||||
import art.arcane.volmlib.util.math.M;
|
||||
import art.arcane.volmlib.util.math.Position2;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import art.arcane.volmlib.util.matter.Matter;
|
||||
import art.arcane.volmlib.util.matter.MatterCavern;
|
||||
import art.arcane.volmlib.util.matter.MatterUpdate;
|
||||
import art.arcane.iris.util.common.parallel.BurstExecutor;
|
||||
import art.arcane.iris.util.common.parallel.MultiBurst;
|
||||
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||
import art.arcane.iris.util.common.reflect.KeyedType;
|
||||
import art.arcane.iris.util.common.reflect.W;
|
||||
import art.arcane.volmlib.util.scheduling.ChronoLatch;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import art.arcane.iris.util.common.scheduling.jobs.SingleJob;
|
||||
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
||||
import art.arcane.iris.util.project.stream.ProceduralStream;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@@ -339,243 +314,6 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
|
||||
void blockUpdatedMetric();
|
||||
|
||||
@ChunkCoordinates
|
||||
@Override
|
||||
default void updateChunk(Chunk c) {
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int z = -1; z <= 1; z++) {
|
||||
if (c.getWorld().isChunkLoaded(c.getX() + x, c.getZ() + z))
|
||||
continue;
|
||||
var msg = "Chunk %s, %s [%s, %s] is not loaded".formatted(c.getX() + x, c.getZ() + z, x, z);
|
||||
IrisLogging.debug(msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
var mantle = getMantle().getMantle();
|
||||
if (!mantle.isLoaded(c)) {
|
||||
var msg = "Mantle Chunk " + c.getX() + "," + c.getZ() + " is not loaded";
|
||||
IrisLogging.debug(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!J.isFolia() && !J.isPrimaryThread()) {
|
||||
CompletableFuture<?> scheduled = J.sfut(() -> updateChunk(c));
|
||||
if (scheduled != null) {
|
||||
try {
|
||||
scheduled.join();
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.reportError(e);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var chunk = mantle.getChunk(c).use();
|
||||
try {
|
||||
Runnable tileTask = () -> {
|
||||
chunk.iterate(TileWrapper.class, (x, y, z, v) -> {
|
||||
Block block = c.getBlock(x & 15, y + getWorld().minHeight(), z & 15);
|
||||
if (!TileData.setTileState(block, v.getData())) {
|
||||
NamespacedKey blockTypeKey = KeyedType.getKey(block.getType());
|
||||
NamespacedKey tileTypeKey = KeyedType.getKey(v.getData().getMaterial());
|
||||
String blockType = blockTypeKey == null ? block.getType().name() : blockTypeKey.toString();
|
||||
String tileType = tileTypeKey == null ? v.getData().getMaterial().name() : tileTypeKey.toString();
|
||||
IrisLogging.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", block.getX(), block.getY(), block.getZ(), blockType, tileType);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Runnable customTask = () -> {
|
||||
chunk.iterate(Identifier.class, (x, y, z, v) -> {
|
||||
IrisServices.get(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
|
||||
});
|
||||
};
|
||||
|
||||
Runnable updateTask = () -> {
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
int[][] grid = new int[16][16];
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
grid[x][z] = Integer.MIN_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
RNG rng = new RNG(Cache.key(c.getX(), c.getZ()));
|
||||
chunk.iterate(MatterCavern.class, (x, yf, z, v) -> {
|
||||
int y = yf + getWorld().minHeight();
|
||||
x &= 15;
|
||||
z &= 15;
|
||||
Block block = c.getBlock(x, y, z);
|
||||
if (!BukkitBlockResolution.isFluid(block.getBlockData())) {
|
||||
return;
|
||||
}
|
||||
boolean u = BukkitBlockResolution.isAir(block.getRelative(BlockFace.DOWN).getBlockData())
|
||||
|| BukkitBlockResolution.isAir(block.getRelative(BlockFace.WEST).getBlockData())
|
||||
|| BukkitBlockResolution.isAir(block.getRelative(BlockFace.EAST).getBlockData())
|
||||
|| BukkitBlockResolution.isAir(block.getRelative(BlockFace.SOUTH).getBlockData())
|
||||
|| BukkitBlockResolution.isAir(block.getRelative(BlockFace.NORTH).getBlockData());
|
||||
|
||||
if (u) grid[x][z] = Math.max(grid[x][z], y);
|
||||
});
|
||||
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
if (grid[x][z] == Integer.MIN_VALUE) {
|
||||
continue;
|
||||
}
|
||||
update(x, grid[x][z], z, c, chunk, rng);
|
||||
}
|
||||
}
|
||||
|
||||
chunk.iterate(MatterUpdate.class, (x, yf, z, v) -> {
|
||||
int y = yf + getWorld().minHeight();
|
||||
if (v != null && v.isUpdate()) {
|
||||
update(x, y, z, c, chunk, rng);
|
||||
}
|
||||
});
|
||||
chunk.deleteSlices(MatterUpdate.class);
|
||||
getMetrics().getUpdates().put(p.getMilliseconds());
|
||||
};
|
||||
|
||||
if (shouldRunChunkUpdateInline(c)) {
|
||||
chunk.raiseFlagUnchecked(MantleFlag.ETCHED, () -> {
|
||||
chunk.raiseFlagUnchecked(MantleFlag.TILE, tileTask);
|
||||
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, customTask);
|
||||
chunk.raiseFlagUnchecked(MantleFlag.UPDATE, updateTask);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Semaphore semaphore = new Semaphore(1024);
|
||||
chunk.raiseFlagUnchecked(MantleFlag.ETCHED, () -> {
|
||||
chunk.raiseFlagUnchecked(MantleFlag.TILE, run(semaphore, c, tileTask, 0));
|
||||
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, run(semaphore, c, customTask, 0));
|
||||
chunk.raiseFlagUnchecked(MantleFlag.UPDATE, run(semaphore, c, updateTask, RNG.r.i(1, 20)));
|
||||
});
|
||||
|
||||
try {
|
||||
semaphore.acquire(1024);
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
IrisLogging.reportError(ex);
|
||||
}
|
||||
} finally {
|
||||
chunk.release();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldRunChunkUpdateInline(Chunk chunk) {
|
||||
if (chunk == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!J.isFolia()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return J.isOwnedByCurrentRegion(chunk.getWorld(), chunk.getX(), chunk.getZ());
|
||||
}
|
||||
|
||||
private static Runnable run(Semaphore semaphore, Chunk contextChunk, Runnable runnable, int delay) {
|
||||
return () -> {
|
||||
try {
|
||||
semaphore.acquire();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
int effectiveDelay = J.isFolia() ? 0 : delay;
|
||||
boolean scheduled = J.runRegion(contextChunk.getWorld(), contextChunk.getX(), contextChunk.getZ(), () -> {
|
||||
try {
|
||||
runnable.run();
|
||||
} finally {
|
||||
semaphore.release();
|
||||
}
|
||||
}, effectiveDelay);
|
||||
|
||||
if (!scheduled) {
|
||||
try {
|
||||
if (J.isPrimaryThread()) {
|
||||
runnable.run();
|
||||
}
|
||||
} finally {
|
||||
semaphore.release();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@BlockCoordinates
|
||||
@Override
|
||||
|
||||
default void update(int x, int y, int z, Chunk c, MantleChunk<Matter> mc, RNG rf) {
|
||||
Block block = c.getBlock(x, y, z);
|
||||
BlockData data = block.getBlockData();
|
||||
blockUpdatedMetric();
|
||||
if (BukkitBlockResolution.isStorage(data)) {
|
||||
RNG rx = rf.nextParallelRNG(BlockPosition.toLong(x, y, z));
|
||||
InventorySlotType slot = null;
|
||||
|
||||
if (BukkitBlockResolution.isStorageChest(data)) {
|
||||
slot = InventorySlotType.STORAGE;
|
||||
}
|
||||
|
||||
if (slot != null) {
|
||||
KList<IrisLootTable> tables = getLootTables(rx, block, mc);
|
||||
|
||||
try {
|
||||
Bukkit.getPluginManager().callEvent(new IrisLootEvent(this, block, slot, tables));
|
||||
if (tables.isEmpty()) return;
|
||||
InventoryHolder m = (InventoryHolder) block.getState();
|
||||
addItems(false, m.getInventory(), rx, tables, slot, c.getWorld(), x, y, z, 15);
|
||||
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.reportError(e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
block.setType(Material.AIR, false);
|
||||
block.setBlockData(data, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
default void scramble(Inventory inventory, RNG rng) {
|
||||
org.bukkit.inventory.ItemStack[] items = inventory.getContents();
|
||||
org.bukkit.inventory.ItemStack[] nitems = new org.bukkit.inventory.ItemStack[inventory.getSize()];
|
||||
System.arraycopy(items, 0, nitems, 0, items.length);
|
||||
boolean packedFull = false;
|
||||
|
||||
splitting:
|
||||
for (int i = 0; i < nitems.length; i++) {
|
||||
ItemStack is = nitems[i];
|
||||
|
||||
if (is != null && is.getAmount() > 1 && !packedFull) {
|
||||
for (int j = 0; j < nitems.length; j++) {
|
||||
if (nitems[j] == null) {
|
||||
int take = rng.nextInt(is.getAmount());
|
||||
take = take == 0 ? 1 : take;
|
||||
is.setAmount(is.getAmount() - take);
|
||||
nitems[j] = is.clone();
|
||||
nitems[j].setAmount(take);
|
||||
continue splitting;
|
||||
}
|
||||
}
|
||||
|
||||
packedFull = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = nitems.length; i > 1; i--) {
|
||||
int j = rng.nextInt(i);
|
||||
ItemStack tmp = nitems[i - 1];
|
||||
nitems[i - 1] = nitems[j];
|
||||
nitems[j] = tmp;
|
||||
}
|
||||
|
||||
inventory.setContents(nitems);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void injectTables(KList<IrisLootTable> list, IrisLootReference r, boolean fallback) {
|
||||
if (r.getMode().equals(IrisLootMode.FALLBACK) && !fallback)
|
||||
@@ -588,101 +326,6 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
list.addAll(r.getLootTables(getComplex()));
|
||||
}
|
||||
|
||||
@BlockCoordinates
|
||||
@Override
|
||||
default KList<IrisLootTable> getLootTables(RNG rng, Block b) {
|
||||
MantleChunk<Matter> mc = getMantle().getMantle().getChunk(b.getChunk()).use();
|
||||
try {
|
||||
return getLootTables(rng, b, mc);
|
||||
} finally {
|
||||
mc.release();
|
||||
}
|
||||
}
|
||||
|
||||
@BlockCoordinates
|
||||
default KList<IrisLootTable> getLootTables(RNG rng, Block b, MantleChunk<Matter> mc) {
|
||||
int rx = b.getX();
|
||||
int rz = b.getZ();
|
||||
int ry = b.getY() - getWorld().minHeight();
|
||||
double he = getComplex().getHeightStream().get(rx, rz);
|
||||
KList<IrisLootTable> tables = new KList<>();
|
||||
|
||||
PlacedObject po = getObjectPlacement(rx, ry, rz, mc);
|
||||
if (po != null && po.getPlacement() != null) {
|
||||
if (BukkitBlockResolution.isStorageChest(b.getBlockData())) {
|
||||
IrisLootTable table = po.getPlacement().getTable(BukkitBlockState.of(b.getBlockData()), getData());
|
||||
if (table != null) {
|
||||
tables.add(table);
|
||||
if (po.getPlacement().isOverrideGlobalLoot()) {
|
||||
return new KList<>(table);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IrisRegion region = getComplex().getRegionStream().get(rx, rz);
|
||||
IrisBiome biomeSurface = getComplex().getTrueBiomeStream().get(rx, rz);
|
||||
IrisBiome biomeUnder = ry < he ? getCaveBiome(rx, ry, rz) : biomeSurface;
|
||||
|
||||
double multiplier = 1D * getDimension().getLoot().getMultiplier() * region.getLoot().getMultiplier() * biomeSurface.getLoot().getMultiplier() * biomeUnder.getLoot().getMultiplier();
|
||||
boolean fallback = tables.isEmpty();
|
||||
injectTables(tables, getDimension().getLoot(), fallback);
|
||||
injectTables(tables, region.getLoot(), fallback);
|
||||
injectTables(tables, biomeSurface.getLoot(), fallback);
|
||||
injectTables(tables, biomeUnder.getLoot(), fallback);
|
||||
|
||||
if (tables.isNotEmpty()) {
|
||||
int target = (int) Math.round(tables.size() * multiplier);
|
||||
|
||||
while (tables.size() < target && tables.isNotEmpty()) {
|
||||
tables.add(tables.get(rng.i(tables.size() - 1)));
|
||||
}
|
||||
|
||||
while (tables.size() > target && tables.isNotEmpty()) {
|
||||
tables.remove(rng.i(tables.size() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
@Override
|
||||
default void addItems(boolean debug, Inventory inv, RNG rng, KList<IrisLootTable> tables, InventorySlotType slot, World world, int x, int y, int z, int mgf) {
|
||||
KList<ItemStack> items = new KList<>();
|
||||
|
||||
for (IrisLootTable i : tables) {
|
||||
if (i == null)
|
||||
continue;
|
||||
items.addAll(i.getLoot(debug, rng, slot, world, x, y, z));
|
||||
}
|
||||
if (IrisLootEvent.callLootEvent(items, inv, world, x, y, z))
|
||||
return;
|
||||
|
||||
if (PaperLib.isPaper() && getWorld().hasRealWorld()) {
|
||||
PaperLib.getChunkAtAsync(getWorld().realWorld(), x >> 4, z >> 4).thenAccept((c) -> {
|
||||
Runnable r = () -> {
|
||||
for (ItemStack i : items) {
|
||||
inv.addItem(i);
|
||||
}
|
||||
|
||||
scramble(inv, rng);
|
||||
};
|
||||
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
J.s(r);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
for (ItemStack i : items) {
|
||||
inv.addItem(i);
|
||||
}
|
||||
|
||||
scramble(inv, rng);
|
||||
}
|
||||
}
|
||||
|
||||
EngineEffects getEffects();
|
||||
|
||||
default MultiBurst burst() {
|
||||
@@ -693,16 +336,6 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
burst().lazy(() -> getMantle().trim(10));
|
||||
}
|
||||
|
||||
@BlockCoordinates
|
||||
default IrisBiome getBiome(Location l) {
|
||||
return getBiome(l.getBlockX(), l.getBlockY() - getWorld().minHeight(), l.getBlockZ());
|
||||
}
|
||||
|
||||
@BlockCoordinates
|
||||
default IrisRegion getRegion(Location l) {
|
||||
return getRegion(l.getBlockX(), l.getBlockZ());
|
||||
}
|
||||
|
||||
IrisBiome getFocus();
|
||||
|
||||
IrisRegion getFocusRegion();
|
||||
@@ -710,14 +343,6 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
|
||||
IrisEngineData getEngineData();
|
||||
|
||||
default IrisBiome getSurfaceBiome(Chunk c) {
|
||||
return getSurfaceBiome((c.getX() << 4) + 8, (c.getZ() << 4) + 8);
|
||||
}
|
||||
|
||||
default IrisRegion getRegion(Chunk c) {
|
||||
return getRegion((c.getX() << 4) + 8, (c.getZ() << 4) + 8);
|
||||
}
|
||||
|
||||
default KList<IrisBiome> getAllBiomes() {
|
||||
KMap<String, IrisBiome> v = new KMap<>();
|
||||
|
||||
@@ -981,107 +606,6 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
|
||||
int getCacheID();
|
||||
|
||||
default IrisBiome getBiomeOrMantle(Location l) {
|
||||
return getBiomeOrMantle(l.getBlockX(), l.getBlockY(), l.getBlockZ());
|
||||
}
|
||||
|
||||
default void gotoBiome(IrisBiome biome, Player player, boolean teleport) {
|
||||
find(Locator.surfaceBiome(biome.getLoadKey()), player, teleport, "Biome " + biome.getName());
|
||||
}
|
||||
|
||||
private static void find(Locator<?> locator, Player player, boolean teleport, String message) {
|
||||
find(locator, player, 120_000, location -> {
|
||||
if (location == null) {
|
||||
player.sendMessage(C.RED + "Could not find " + message + " within search range.");
|
||||
return;
|
||||
}
|
||||
if (teleport) {
|
||||
J.runEntity(player, () -> teleportAsyncSafely(player, location));
|
||||
player.sendMessage(C.GREEN + "Teleporting to " + message + "...");
|
||||
} else {
|
||||
player.sendMessage(C.GREEN + message + " at: " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void find(Locator<?> locator, Player player, long timeout, Consumer<Location> consumer) {
|
||||
AtomicLong checks = new AtomicLong();
|
||||
long ms = M.ms();
|
||||
new SingleJob("Searching", () -> {
|
||||
try {
|
||||
World world = player.getWorld();
|
||||
Engine engine = IrisToolbelt.access(world).getEngine();
|
||||
Position2 at = locator.find(engine, new Position2(player.getLocation().getBlockX() >> 4, player.getLocation().getBlockZ() >> 4), timeout, checks::set).get();
|
||||
|
||||
if (at != null) {
|
||||
int bx = (at.getX() << 4) + 8;
|
||||
int bz = (at.getZ() << 4) + 8;
|
||||
consumer.accept(new Location(world, bx,
|
||||
world.getHighestBlockYAt(bx, bz) + 2,
|
||||
bz));
|
||||
} else {
|
||||
consumer.accept(null);
|
||||
}
|
||||
} catch (WrongEngineBroException | InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Searched " + Form.f(checks.get()) + " Chunks";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalWork() {
|
||||
return (int) timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWorkCompleted() {
|
||||
return (int) Math.min(M.ms() - ms, timeout - 1);
|
||||
}
|
||||
}.execute(new VolmitSender(player));
|
||||
}
|
||||
|
||||
private static void teleportAsyncSafely(Player player, Location location) {
|
||||
if (player == null || location == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (invokeNativeTeleportAsync(player, location)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
CompletableFuture<Boolean> teleportFuture = PaperLib.teleportAsync(player, location);
|
||||
if (teleportFuture != null) {
|
||||
teleportFuture.exceptionally(throwable -> {
|
||||
IrisLogging.reportError(throwable);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
IrisLogging.reportError(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean invokeNativeTeleportAsync(Player player, Location location) {
|
||||
try {
|
||||
Method teleportAsyncMethod = player.getClass().getMethod("teleportAsync", Location.class);
|
||||
teleportAsyncMethod.invoke(player, location);
|
||||
return true;
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
return false;
|
||||
} catch (Throwable throwable) {
|
||||
IrisLogging.reportError(throwable);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
default void gotoObject(String s, Player player, boolean teleport) {
|
||||
find(Locator.object(s), player, teleport, "Object " + s);
|
||||
}
|
||||
|
||||
default boolean hasObjectPlacement(String objectKey) {
|
||||
String normalizedObjectKey = normalizeObjectPlacementKey(objectKey);
|
||||
if (normalizedObjectKey.isBlank()) {
|
||||
@@ -1100,23 +624,6 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
return !regionKeys.isEmpty();
|
||||
}
|
||||
|
||||
default void gotoRegion(IrisRegion r, Player player, boolean teleport) {
|
||||
if (!getDimension().getRegions().contains(r.getLoadKey())) {
|
||||
player.sendMessage(C.RED + r.getName() + " is not defined in the dimension!");
|
||||
return;
|
||||
}
|
||||
|
||||
find(Locator.region(r.getLoadKey()), player, teleport, "Region " + r.getName());
|
||||
}
|
||||
|
||||
default void gotoPOI(String type, Player p, boolean teleport) {
|
||||
find(Locator.poi(type), p, teleport, "POI " + type);
|
||||
}
|
||||
|
||||
default void gotoStructure(String key, Player player, boolean teleport) {
|
||||
find(Locator.structure(key), player, teleport, "Structure " + key);
|
||||
}
|
||||
|
||||
private static boolean containsObjectPlacement(KList<IrisObjectPlacement> placements, String normalizedObjectKey) {
|
||||
if (placements == null || placements.isEmpty() || normalizedObjectKey.isBlank()) {
|
||||
return false;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package art.arcane.iris.engine.framework;
|
||||
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.iris.engine.platform.EngineBukkitOps;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisEffect;
|
||||
import art.arcane.iris.engine.object.IrisRegion;
|
||||
@@ -87,8 +88,8 @@ public class EnginePlayer {
|
||||
if (ticksSinceLastSample() > 55 && current.distanceSquared(lastLocation) > 9 * 9) {
|
||||
lastLocation = current;
|
||||
lastSample = M.ms();
|
||||
biome = engine.getBiome(current);
|
||||
region = engine.getRegion(current);
|
||||
biome = EngineBukkitOps.getBiome(engine, current);
|
||||
region = EngineBukkitOps.getRegion(engine, current);
|
||||
}
|
||||
return false;
|
||||
} catch (Throwable e) {
|
||||
|
||||
@@ -18,21 +18,10 @@
|
||||
|
||||
package art.arcane.iris.engine.framework;
|
||||
|
||||
import art.arcane.iris.engine.object.InventorySlotType;
|
||||
import art.arcane.iris.engine.object.IrisLootReference;
|
||||
import art.arcane.iris.engine.object.IrisLootTable;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
|
||||
public interface LootProvider {
|
||||
void scramble(Inventory inventory, RNG rng);
|
||||
|
||||
void injectTables(KList<IrisLootTable> list, IrisLootReference r, boolean fallback);
|
||||
|
||||
KList<IrisLootTable> getLootTables(RNG rng, Block b);
|
||||
|
||||
void addItems(boolean debug, Inventory inv, RNG rng, KList<IrisLootTable> tables, InventorySlotType slot, World world, int x, int y, int z, int mgf);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import art.arcane.iris.engine.data.cache.Cache;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.core.events.IrisLootEvent;
|
||||
import art.arcane.iris.engine.mantle.EngineMantle;
|
||||
import art.arcane.iris.engine.platform.EngineBukkitOps;
|
||||
import art.arcane.iris.engine.object.IObjectPlacer;
|
||||
import art.arcane.iris.engine.object.InventorySlotType;
|
||||
import art.arcane.iris.engine.object.IrisLootTable;
|
||||
@@ -71,7 +72,7 @@ public class WorldObjectPlacer implements IObjectPlacer {
|
||||
|
||||
if (slot != null) {
|
||||
RNG rx = new RNG(Cache.key(x, z));
|
||||
KList<IrisLootTable> tables = engine.getLootTables(rx, block);
|
||||
KList<IrisLootTable> tables = EngineBukkitOps.getLootTables(engine, rx, block);
|
||||
|
||||
try {
|
||||
Bukkit.getPluginManager().callEvent(new IrisLootEvent(engine, block, slot, tables));
|
||||
@@ -83,7 +84,7 @@ public class WorldObjectPlacer implements IObjectPlacer {
|
||||
if (tables.isEmpty())
|
||||
return;
|
||||
InventoryHolder m = (InventoryHolder) block.getState();
|
||||
engine.addItems(false, m.getInventory(), rx, tables, slot, world, x, y, z, 15);
|
||||
EngineBukkitOps.addItems(engine, false, m.getInventory(), rx, tables, slot, world, x, y, z, 15);
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.reportError(e);
|
||||
}
|
||||
|
||||
@@ -179,6 +179,12 @@ public class IrisEffect {
|
||||
});
|
||||
}
|
||||
|
||||
private static final class BukkitFx {
|
||||
private static void run(Player p, Runnable r) {
|
||||
J.runEntity(p, r);
|
||||
}
|
||||
}
|
||||
|
||||
public void apply(Player p, Engine g) {
|
||||
if (!canTick()) {
|
||||
return;
|
||||
@@ -188,7 +194,7 @@ public class IrisEffect {
|
||||
return;
|
||||
}
|
||||
|
||||
J.runEntity(p, () -> {
|
||||
BukkitFx.run(p, () -> {
|
||||
if (sound != null) {
|
||||
Location part = p.getLocation().clone().add(RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance));
|
||||
p.playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch));
|
||||
|
||||
@@ -24,6 +24,7 @@ import art.arcane.iris.core.link.Identifier;
|
||||
import art.arcane.iris.core.loader.IrisRegistrant;
|
||||
import art.arcane.iris.core.service.ExternalDataSVC;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.platform.EngineBukkitOps;
|
||||
import art.arcane.iris.engine.object.annotations.*;
|
||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||
import art.arcane.iris.platform.bukkit.BukkitWorld;
|
||||
@@ -247,34 +248,7 @@ public class IrisEntity extends IrisRegistrant {
|
||||
Lootable l = (Lootable) e;
|
||||
|
||||
if (getLoot().getTables().isNotEmpty()) {
|
||||
Location finalAt = at;
|
||||
l.setLootTable(new LootTable() {
|
||||
@Override
|
||||
public NamespacedKey getKey() {
|
||||
return new NamespacedKey("iris", "loot-" + IrisEntity.this.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ItemStack> populateLoot(Random random, LootContext context) {
|
||||
KList<ItemStack> items = new KList<>();
|
||||
|
||||
for (String fi : getLoot().getTables()) {
|
||||
IrisLootTable i = gen.getData().getLootLoader().load(fi);
|
||||
items.addAll(i.getLoot(gen.isStudio(), rng.nextParallelRNG(345911), InventorySlotType.STORAGE, finalAt.getWorld(), finalAt.getBlockX(), finalAt.getBlockY(), finalAt.getBlockZ()));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillInventory(Inventory inventory, Random random, LootContext context) {
|
||||
for (ItemStack i : populateLoot(random, context)) {
|
||||
inventory.addItem(i);
|
||||
}
|
||||
|
||||
gen.scramble(inventory, rng);
|
||||
}
|
||||
});
|
||||
BukkitOps.bindLoot(this, gen, l, at, rng);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,7 +300,7 @@ public class IrisEntity extends IrisRegistrant {
|
||||
if (e instanceof Villager) {
|
||||
Villager villager = (Villager) e;
|
||||
villager.setRemoveWhenFarAway(false);
|
||||
J.runEntity(villager, () -> villager.setPersistent(true), 1);
|
||||
BukkitOps.persistVillager(villager);
|
||||
}
|
||||
|
||||
if (e instanceof Mob) {
|
||||
@@ -458,6 +432,42 @@ public class IrisEntity extends IrisRegistrant {
|
||||
return specialType != null && !specialType.equals("");
|
||||
}
|
||||
|
||||
private static final class BukkitOps {
|
||||
private static void persistVillager(Villager villager) {
|
||||
J.runEntity(villager, () -> villager.setPersistent(true), 1);
|
||||
}
|
||||
|
||||
private static void bindLoot(IrisEntity entity, Engine gen, Lootable l, Location finalAt, RNG rng) {
|
||||
l.setLootTable(new LootTable() {
|
||||
@Override
|
||||
public NamespacedKey getKey() {
|
||||
return new NamespacedKey("iris", "loot-" + entity.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ItemStack> populateLoot(Random random, LootContext context) {
|
||||
KList<ItemStack> items = new KList<>();
|
||||
|
||||
for (String fi : entity.getLoot().getTables()) {
|
||||
IrisLootTable i = gen.getData().getLootLoader().load(fi);
|
||||
items.addAll(i.getLoot(gen.isStudio(), rng.nextParallelRNG(345911), InventorySlotType.STORAGE, finalAt.getWorld(), finalAt.getBlockX(), finalAt.getBlockY(), finalAt.getBlockZ()));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillInventory(Inventory inventory, Random random, LootContext context) {
|
||||
for (ItemStack i : populateLoot(random, context)) {
|
||||
inventory.addItem(i);
|
||||
}
|
||||
|
||||
EngineBukkitOps.scramble(gen, inventory, rng);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFolderName() {
|
||||
return "entities";
|
||||
|
||||
@@ -1059,8 +1059,8 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
if (placer.isPreventingDecay() && ((BlockData) data.nativeHandle()) instanceof Leaves && !((Leaves) ((BlockData) data.nativeHandle())).isPersistent()) {
|
||||
Leaves leaves = (Leaves) ((BlockData) data.nativeHandle()).clone();
|
||||
leaves.setPersistent(true);
|
||||
BlockData leaves = ((BlockData) data.nativeHandle()).clone();
|
||||
((Leaves) leaves).setPersistent(true);
|
||||
data = BukkitBlockState.of(leaves);
|
||||
}
|
||||
|
||||
@@ -1119,13 +1119,14 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
if (((BlockData) data.nativeHandle()) instanceof Waterlogged && shouldAutoWaterlogBlock(placer, config, yv, xx, yy, zz)) {
|
||||
Waterlogged waterlogged = (Waterlogged) ((BlockData) data.nativeHandle()).clone();
|
||||
waterlogged.setWaterlogged(true);
|
||||
BlockData waterlogged = ((BlockData) data.nativeHandle()).clone();
|
||||
((Waterlogged) waterlogged).setWaterlogged(true);
|
||||
data = BukkitBlockState.of(waterlogged);
|
||||
}
|
||||
|
||||
if (BukkitBlockResolution.isVineBlock((BlockData) data.nativeHandle())) {
|
||||
MultipleFacing f = (MultipleFacing) ((BlockData) data.nativeHandle()).clone();
|
||||
BlockData fData = ((BlockData) data.nativeHandle()).clone();
|
||||
MultipleFacing f = (MultipleFacing) fData;
|
||||
boolean facesChanged = false;
|
||||
for (BlockFace face : f.getAllowedFaces()) {
|
||||
PlatformBlockState facingState = placer.get(xx + face.getModX(), yy + face.getModY(), zz + face.getModZ());
|
||||
@@ -1136,7 +1137,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
}
|
||||
if (facesChanged) {
|
||||
data = BukkitBlockState.of(f);
|
||||
data = BukkitBlockState.of(fData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1344,8 +1345,8 @@ public class IrisObject extends IrisRegistrant {
|
||||
int highest = placer.getHighest(xx, zz, getLoader(), true);
|
||||
|
||||
if (((BlockData) d.nativeHandle()) instanceof Waterlogged && shouldAutoWaterlogBlock(placer, config, yv, xx, highest, zz)) {
|
||||
Waterlogged waterlogged = (Waterlogged) ((BlockData) d.nativeHandle()).clone();
|
||||
waterlogged.setWaterlogged(true);
|
||||
BlockData waterlogged = ((BlockData) d.nativeHandle()).clone();
|
||||
((Waterlogged) waterlogged).setWaterlogged(true);
|
||||
d = BukkitBlockState.of(waterlogged);
|
||||
}
|
||||
|
||||
@@ -1385,7 +1386,8 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
if (BukkitBlockResolution.isVineBlock((BlockData) d.nativeHandle())) {
|
||||
MultipleFacing f = (MultipleFacing) ((BlockData) d.nativeHandle()).clone();
|
||||
BlockData fData = ((BlockData) d.nativeHandle()).clone();
|
||||
MultipleFacing f = (MultipleFacing) fData;
|
||||
boolean facesChanged = false;
|
||||
for (BlockFace face : f.getAllowedFaces()) {
|
||||
PlatformBlockState facingState = placer.get(xx + face.getModX(), j + face.getModY(), zz + face.getModZ());
|
||||
@@ -1396,7 +1398,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
}
|
||||
if (facesChanged) {
|
||||
d = BukkitBlockState.of(f);
|
||||
d = BukkitBlockState.of(fData);
|
||||
}
|
||||
}
|
||||
placer.set(xx, j, zz, d);
|
||||
|
||||
@@ -47,7 +47,9 @@ import java.util.Map;
|
||||
@Desc("Configures rotation for iris")
|
||||
@Data
|
||||
public class IrisObjectRotation {
|
||||
private static final List<BlockFace> WALL_FACES = List.of(BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST);
|
||||
private static final class Faces {
|
||||
private static final List<BlockFace> WALL_FACES = List.of(BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST);
|
||||
}
|
||||
|
||||
@Desc("If this rotator is enabled or not")
|
||||
private boolean enabled = true;
|
||||
@@ -332,17 +334,17 @@ public class IrisObjectRotation {
|
||||
} else if (d instanceof Wall wall) {
|
||||
KMap<BlockFace, Wall.Height> faces = new KMap<>();
|
||||
|
||||
for (BlockFace i : WALL_FACES) {
|
||||
for (BlockFace i : Faces.WALL_FACES) {
|
||||
Wall.Height h = wall.getHeight(i);
|
||||
IrisBlockVector bv = new IrisBlockVector(i.getModX(), i.getModY(), i.getModZ());
|
||||
bv = rotate(bv.clone(), spinx, spiny, spinz);
|
||||
BlockFace r = getFace(bv);
|
||||
if (WALL_FACES.contains(r)) {
|
||||
if (Faces.WALL_FACES.contains(r)) {
|
||||
faces.put(r, h);
|
||||
}
|
||||
}
|
||||
|
||||
for (BlockFace i : WALL_FACES) {
|
||||
for (BlockFace i : Faces.WALL_FACES) {
|
||||
wall.setHeight(i, faces.getOrDefault(i, Wall.Height.NONE));
|
||||
}
|
||||
} else if (d instanceof RedstoneWire wire) {
|
||||
|
||||
@@ -36,18 +36,12 @@ import java.util.stream.StreamSupport;
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class LegacyTileData extends TileData {
|
||||
private static final Map<Integer, Pair<Builder, IOFunction<DataInputStream, Handler>>> legacy = Map.of(
|
||||
0, new Pair<>(SignHandler::fromBukkit, SignHandler::new),
|
||||
1, new Pair<>(SpawnerHandler::fromBukkit, SpawnerHandler::new),
|
||||
2, new Pair<>(BannerHandler::fromBukkit, BannerHandler::new),
|
||||
3, new Pair<>(LootableHandler::fromBukkit, LootableHandler::new));
|
||||
private static final AtomicCache<Tag<Material>> SIGNS = new AtomicCache<>();
|
||||
private final int id;
|
||||
private final Handler handler;
|
||||
|
||||
public LegacyTileData(DataInputStream in) throws IOException {
|
||||
id = in.readShort();
|
||||
var factory = legacy.get(id);
|
||||
Pair<Builder, IOFunction<DataInputStream, Handler>> factory = Handlers.LEGACY.get(id);
|
||||
if (factory == null)
|
||||
throw new IOException("Unknown tile type: " + id);
|
||||
handler = factory.getB().apply(in);
|
||||
@@ -60,16 +54,24 @@ public class LegacyTileData extends TileData {
|
||||
|
||||
@Nullable
|
||||
public static LegacyTileData fromBukkit(@NonNull BlockState tileState) {
|
||||
var type = tileState.getType();
|
||||
for (var id : legacy.keySet()) {
|
||||
var factory = legacy.get(id);
|
||||
var handler = factory.getA().apply(tileState, type);
|
||||
Material type = tileState.getType();
|
||||
for (Integer id : Handlers.LEGACY.keySet()) {
|
||||
Pair<Builder, IOFunction<DataInputStream, Handler>> factory = Handlers.LEGACY.get(id);
|
||||
Handler handler = factory.getA().apply(tileState, type);
|
||||
if (handler != null)
|
||||
return new LegacyTileData(id, handler);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final class Handlers {
|
||||
private static final Map<Integer, Pair<Builder, IOFunction<DataInputStream, Handler>>> LEGACY = Map.of(
|
||||
0, new Pair<>(SignHandler::fromBukkit, SignHandler::new),
|
||||
1, new Pair<>(SpawnerHandler::fromBukkit, SpawnerHandler::new),
|
||||
2, new Pair<>(BannerHandler::fromBukkit, BannerHandler::new),
|
||||
3, new Pair<>(LootableHandler::fromBukkit, LootableHandler::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull KMap<String, Object> getProperties() {
|
||||
return new KMap<>();
|
||||
@@ -411,34 +413,42 @@ public class LegacyTileData extends TileData {
|
||||
}
|
||||
|
||||
private static Tag<Material> signsTag() {
|
||||
return SIGNS.aquire(() -> {
|
||||
var signs = Bukkit.getTag("blocks", NamespacedKey.minecraft("all_signs"), Material.class);
|
||||
if (signs != null)
|
||||
return signs;
|
||||
return new Tag<>() {
|
||||
@Override
|
||||
public boolean isTagged(@NotNull Material item) {
|
||||
NamespacedKey key = KeyedType.getKey(item);
|
||||
if (key != null) {
|
||||
return key.getKey().endsWith("_sign");
|
||||
return SignTags.get();
|
||||
}
|
||||
|
||||
private static final class SignTags {
|
||||
private static final AtomicCache<Tag<Material>> SIGNS = new AtomicCache<>();
|
||||
|
||||
private static Tag<Material> get() {
|
||||
return SIGNS.aquire(() -> {
|
||||
Tag<Material> signs = Bukkit.getTag("blocks", NamespacedKey.minecraft("all_signs"), Material.class);
|
||||
if (signs != null)
|
||||
return signs;
|
||||
return new Tag<>() {
|
||||
@Override
|
||||
public boolean isTagged(@NotNull Material item) {
|
||||
NamespacedKey key = KeyedType.getKey(item);
|
||||
if (key != null) {
|
||||
return key.getKey().endsWith("_sign");
|
||||
}
|
||||
return item.name().toLowerCase(Locale.ROOT).endsWith("_sign");
|
||||
}
|
||||
return item.name().toLowerCase(Locale.ROOT).endsWith("_sign");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Material> getValues() {
|
||||
return StreamSupport.stream(Registry.MATERIAL.spliterator(), false)
|
||||
.filter(this::isTagged)
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Material> getValues() {
|
||||
return StreamSupport.stream(Registry.MATERIAL.spliterator(), false)
|
||||
.filter(this::isTagged)
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public NamespacedKey getKey() {
|
||||
return NamespacedKey.minecraft("all_signs");
|
||||
}
|
||||
};
|
||||
});
|
||||
@NotNull
|
||||
@Override
|
||||
public NamespacedKey getKey() {
|
||||
return NamespacedKey.minecraft("all_signs");
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.engine.platform;
|
||||
|
||||
import art.arcane.iris.core.events.IrisLootEvent;
|
||||
import art.arcane.iris.core.link.Identifier;
|
||||
import art.arcane.iris.core.service.ExternalDataSVC;
|
||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||
import art.arcane.iris.engine.data.cache.Cache;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.Locator;
|
||||
import art.arcane.iris.engine.framework.PlacedObject;
|
||||
import art.arcane.iris.engine.framework.WrongEngineBroException;
|
||||
import art.arcane.iris.engine.object.InventorySlotType;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisLootTable;
|
||||
import art.arcane.iris.engine.object.IrisRegion;
|
||||
import art.arcane.iris.engine.object.TileData;
|
||||
import art.arcane.iris.platform.bukkit.BukkitBlockResolution;
|
||||
import art.arcane.iris.platform.bukkit.BukkitBlockState;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.spi.IrisServices;
|
||||
import art.arcane.iris.util.common.format.C;
|
||||
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||
import art.arcane.iris.util.common.reflect.KeyedType;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import art.arcane.iris.util.common.scheduling.jobs.SingleJob;
|
||||
import art.arcane.iris.util.project.matter.TileWrapper;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.format.Form;
|
||||
import art.arcane.volmlib.util.mantle.flag.MantleFlag;
|
||||
import art.arcane.volmlib.util.mantle.runtime.Mantle;
|
||||
import art.arcane.volmlib.util.mantle.runtime.MantleChunk;
|
||||
import art.arcane.volmlib.util.math.BlockPosition;
|
||||
import art.arcane.volmlib.util.math.M;
|
||||
import art.arcane.volmlib.util.math.Position2;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import art.arcane.volmlib.util.matter.Matter;
|
||||
import art.arcane.volmlib.util.matter.MatterCavern;
|
||||
import art.arcane.volmlib.util.matter.MatterUpdate;
|
||||
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class EngineBukkitOps {
|
||||
private EngineBukkitOps() {
|
||||
}
|
||||
|
||||
public static void updateChunk(Engine engine, Chunk c) {
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int z = -1; z <= 1; z++) {
|
||||
if (c.getWorld().isChunkLoaded(c.getX() + x, c.getZ() + z))
|
||||
continue;
|
||||
String msg = "Chunk %s, %s [%s, %s] is not loaded".formatted(c.getX() + x, c.getZ() + z, x, z);
|
||||
IrisLogging.debug(msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Mantle<Matter> mantle = engine.getMantle().getMantle();
|
||||
if (!mantle.isLoaded(c)) {
|
||||
String msg = "Mantle Chunk " + c.getX() + "," + c.getZ() + " is not loaded";
|
||||
IrisLogging.debug(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!J.isFolia() && !J.isPrimaryThread()) {
|
||||
CompletableFuture<?> scheduled = J.sfut(() -> updateChunk(engine, c));
|
||||
if (scheduled != null) {
|
||||
try {
|
||||
scheduled.join();
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.reportError(e);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
MantleChunk<Matter> chunk = mantle.getChunk(c).use();
|
||||
try {
|
||||
Runnable tileTask = () -> {
|
||||
chunk.iterate(TileWrapper.class, (x, y, z, v) -> {
|
||||
Block block = c.getBlock(x & 15, y + engine.getWorld().minHeight(), z & 15);
|
||||
if (!TileData.setTileState(block, v.getData())) {
|
||||
NamespacedKey blockTypeKey = KeyedType.getKey(block.getType());
|
||||
NamespacedKey tileTypeKey = KeyedType.getKey(v.getData().getMaterial());
|
||||
String blockType = blockTypeKey == null ? block.getType().name() : blockTypeKey.toString();
|
||||
String tileType = tileTypeKey == null ? v.getData().getMaterial().name() : tileTypeKey.toString();
|
||||
IrisLogging.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", block.getX(), block.getY(), block.getZ(), blockType, tileType);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Runnable customTask = () -> {
|
||||
chunk.iterate(Identifier.class, (x, y, z, v) -> {
|
||||
IrisServices.get(ExternalDataSVC.class).processUpdate(engine, c.getBlock(x & 15, y + engine.getWorld().minHeight(), z & 15), v);
|
||||
});
|
||||
};
|
||||
|
||||
Runnable updateTask = () -> {
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
int[][] grid = new int[16][16];
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
grid[x][z] = Integer.MIN_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
RNG rng = new RNG(Cache.key(c.getX(), c.getZ()));
|
||||
chunk.iterate(MatterCavern.class, (x, yf, z, v) -> {
|
||||
int y = yf + engine.getWorld().minHeight();
|
||||
x &= 15;
|
||||
z &= 15;
|
||||
Block block = c.getBlock(x, y, z);
|
||||
if (!BukkitBlockResolution.isFluid(block.getBlockData())) {
|
||||
return;
|
||||
}
|
||||
boolean u = BukkitBlockResolution.isAir(block.getRelative(BlockFace.DOWN).getBlockData())
|
||||
|| BukkitBlockResolution.isAir(block.getRelative(BlockFace.WEST).getBlockData())
|
||||
|| BukkitBlockResolution.isAir(block.getRelative(BlockFace.EAST).getBlockData())
|
||||
|| BukkitBlockResolution.isAir(block.getRelative(BlockFace.SOUTH).getBlockData())
|
||||
|| BukkitBlockResolution.isAir(block.getRelative(BlockFace.NORTH).getBlockData());
|
||||
|
||||
if (u) grid[x][z] = Math.max(grid[x][z], y);
|
||||
});
|
||||
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
if (grid[x][z] == Integer.MIN_VALUE) {
|
||||
continue;
|
||||
}
|
||||
update(engine, x, grid[x][z], z, c, chunk, rng);
|
||||
}
|
||||
}
|
||||
|
||||
chunk.iterate(MatterUpdate.class, (x, yf, z, v) -> {
|
||||
int y = yf + engine.getWorld().minHeight();
|
||||
if (v != null && v.isUpdate()) {
|
||||
update(engine, x, y, z, c, chunk, rng);
|
||||
}
|
||||
});
|
||||
chunk.deleteSlices(MatterUpdate.class);
|
||||
engine.getMetrics().getUpdates().put(p.getMilliseconds());
|
||||
};
|
||||
|
||||
if (shouldRunChunkUpdateInline(c)) {
|
||||
chunk.raiseFlagUnchecked(MantleFlag.ETCHED, () -> {
|
||||
chunk.raiseFlagUnchecked(MantleFlag.TILE, tileTask);
|
||||
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, customTask);
|
||||
chunk.raiseFlagUnchecked(MantleFlag.UPDATE, updateTask);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Semaphore semaphore = new Semaphore(1024);
|
||||
chunk.raiseFlagUnchecked(MantleFlag.ETCHED, () -> {
|
||||
chunk.raiseFlagUnchecked(MantleFlag.TILE, run(semaphore, c, tileTask, 0));
|
||||
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, run(semaphore, c, customTask, 0));
|
||||
chunk.raiseFlagUnchecked(MantleFlag.UPDATE, run(semaphore, c, updateTask, RNG.r.i(1, 20)));
|
||||
});
|
||||
|
||||
try {
|
||||
semaphore.acquire(1024);
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
IrisLogging.reportError(ex);
|
||||
}
|
||||
} finally {
|
||||
chunk.release();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldRunChunkUpdateInline(Chunk chunk) {
|
||||
if (chunk == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!J.isFolia()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return J.isOwnedByCurrentRegion(chunk.getWorld(), chunk.getX(), chunk.getZ());
|
||||
}
|
||||
|
||||
private static Runnable run(Semaphore semaphore, Chunk contextChunk, Runnable runnable, int delay) {
|
||||
return () -> {
|
||||
try {
|
||||
semaphore.acquire();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
int effectiveDelay = J.isFolia() ? 0 : delay;
|
||||
boolean scheduled = J.runRegion(contextChunk.getWorld(), contextChunk.getX(), contextChunk.getZ(), () -> {
|
||||
try {
|
||||
runnable.run();
|
||||
} finally {
|
||||
semaphore.release();
|
||||
}
|
||||
}, effectiveDelay);
|
||||
|
||||
if (!scheduled) {
|
||||
try {
|
||||
if (J.isPrimaryThread()) {
|
||||
runnable.run();
|
||||
}
|
||||
} finally {
|
||||
semaphore.release();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void update(Engine engine, int x, int y, int z, Chunk c, MantleChunk<Matter> mc, RNG rf) {
|
||||
Block block = c.getBlock(x, y, z);
|
||||
BlockData data = block.getBlockData();
|
||||
engine.blockUpdatedMetric();
|
||||
if (BukkitBlockResolution.isStorage(data)) {
|
||||
RNG rx = rf.nextParallelRNG(BlockPosition.toLong(x, y, z));
|
||||
InventorySlotType slot = null;
|
||||
|
||||
if (BukkitBlockResolution.isStorageChest(data)) {
|
||||
slot = InventorySlotType.STORAGE;
|
||||
}
|
||||
|
||||
if (slot != null) {
|
||||
KList<IrisLootTable> tables = getLootTables(engine, rx, block, mc);
|
||||
|
||||
try {
|
||||
Bukkit.getPluginManager().callEvent(new IrisLootEvent(engine, block, slot, tables));
|
||||
if (tables.isEmpty()) return;
|
||||
InventoryHolder m = (InventoryHolder) block.getState();
|
||||
addItems(engine, false, m.getInventory(), rx, tables, slot, c.getWorld(), x, y, z, 15);
|
||||
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.reportError(e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
block.setType(Material.AIR, false);
|
||||
block.setBlockData(data, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void scramble(Engine engine, Inventory inventory, RNG rng) {
|
||||
org.bukkit.inventory.ItemStack[] items = inventory.getContents();
|
||||
org.bukkit.inventory.ItemStack[] nitems = new org.bukkit.inventory.ItemStack[inventory.getSize()];
|
||||
System.arraycopy(items, 0, nitems, 0, items.length);
|
||||
boolean packedFull = false;
|
||||
|
||||
splitting:
|
||||
for (int i = 0; i < nitems.length; i++) {
|
||||
ItemStack is = nitems[i];
|
||||
|
||||
if (is != null && is.getAmount() > 1 && !packedFull) {
|
||||
for (int j = 0; j < nitems.length; j++) {
|
||||
if (nitems[j] == null) {
|
||||
int take = rng.nextInt(is.getAmount());
|
||||
take = take == 0 ? 1 : take;
|
||||
is.setAmount(is.getAmount() - take);
|
||||
nitems[j] = is.clone();
|
||||
nitems[j].setAmount(take);
|
||||
continue splitting;
|
||||
}
|
||||
}
|
||||
|
||||
packedFull = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = nitems.length; i > 1; i--) {
|
||||
int j = rng.nextInt(i);
|
||||
ItemStack tmp = nitems[i - 1];
|
||||
nitems[i - 1] = nitems[j];
|
||||
nitems[j] = tmp;
|
||||
}
|
||||
|
||||
inventory.setContents(nitems);
|
||||
}
|
||||
|
||||
public static KList<IrisLootTable> getLootTables(Engine engine, RNG rng, Block b) {
|
||||
MantleChunk<Matter> mc = engine.getMantle().getMantle().getChunk(b.getChunk()).use();
|
||||
try {
|
||||
return getLootTables(engine, rng, b, mc);
|
||||
} finally {
|
||||
mc.release();
|
||||
}
|
||||
}
|
||||
|
||||
public static KList<IrisLootTable> getLootTables(Engine engine, RNG rng, Block b, MantleChunk<Matter> mc) {
|
||||
int rx = b.getX();
|
||||
int rz = b.getZ();
|
||||
int ry = b.getY() - engine.getWorld().minHeight();
|
||||
double he = engine.getComplex().getHeightStream().get(rx, rz);
|
||||
KList<IrisLootTable> tables = new KList<>();
|
||||
|
||||
PlacedObject po = engine.getObjectPlacement(rx, ry, rz, mc);
|
||||
if (po != null && po.getPlacement() != null) {
|
||||
if (BukkitBlockResolution.isStorageChest(b.getBlockData())) {
|
||||
IrisLootTable table = po.getPlacement().getTable(BukkitBlockState.of(b.getBlockData()), engine.getData());
|
||||
if (table != null) {
|
||||
tables.add(table);
|
||||
if (po.getPlacement().isOverrideGlobalLoot()) {
|
||||
return new KList<>(table);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IrisRegion region = engine.getComplex().getRegionStream().get(rx, rz);
|
||||
IrisBiome biomeSurface = engine.getComplex().getTrueBiomeStream().get(rx, rz);
|
||||
IrisBiome biomeUnder = ry < he ? engine.getCaveBiome(rx, ry, rz) : biomeSurface;
|
||||
|
||||
double multiplier = 1D * engine.getDimension().getLoot().getMultiplier() * region.getLoot().getMultiplier() * biomeSurface.getLoot().getMultiplier() * biomeUnder.getLoot().getMultiplier();
|
||||
boolean fallback = tables.isEmpty();
|
||||
engine.injectTables(tables, engine.getDimension().getLoot(), fallback);
|
||||
engine.injectTables(tables, region.getLoot(), fallback);
|
||||
engine.injectTables(tables, biomeSurface.getLoot(), fallback);
|
||||
engine.injectTables(tables, biomeUnder.getLoot(), fallback);
|
||||
|
||||
if (tables.isNotEmpty()) {
|
||||
int target = (int) Math.round(tables.size() * multiplier);
|
||||
|
||||
while (tables.size() < target && tables.isNotEmpty()) {
|
||||
tables.add(tables.get(rng.i(tables.size() - 1)));
|
||||
}
|
||||
|
||||
while (tables.size() > target && tables.isNotEmpty()) {
|
||||
tables.remove(rng.i(tables.size() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
public static void addItems(Engine engine, boolean debug, Inventory inv, RNG rng, KList<IrisLootTable> tables, InventorySlotType slot, World world, int x, int y, int z, int mgf) {
|
||||
KList<ItemStack> items = new KList<>();
|
||||
|
||||
for (IrisLootTable i : tables) {
|
||||
if (i == null)
|
||||
continue;
|
||||
items.addAll(i.getLoot(debug, rng, slot, world, x, y, z));
|
||||
}
|
||||
if (IrisLootEvent.callLootEvent(items, inv, world, x, y, z))
|
||||
return;
|
||||
|
||||
if (PaperLib.isPaper() && engine.getWorld().hasRealWorld()) {
|
||||
PaperLib.getChunkAtAsync(engine.getWorld().realWorld(), x >> 4, z >> 4).thenAccept((c) -> {
|
||||
Runnable r = () -> {
|
||||
for (ItemStack i : items) {
|
||||
inv.addItem(i);
|
||||
}
|
||||
|
||||
scramble(engine, inv, rng);
|
||||
};
|
||||
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
J.s(r);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
for (ItemStack i : items) {
|
||||
inv.addItem(i);
|
||||
}
|
||||
|
||||
scramble(engine, inv, rng);
|
||||
}
|
||||
}
|
||||
|
||||
public static IrisBiome getBiome(Engine engine, Location l) {
|
||||
return engine.getBiome(l.getBlockX(), l.getBlockY() - engine.getWorld().minHeight(), l.getBlockZ());
|
||||
}
|
||||
|
||||
public static IrisRegion getRegion(Engine engine, Location l) {
|
||||
return engine.getRegion(l.getBlockX(), l.getBlockZ());
|
||||
}
|
||||
|
||||
public static IrisBiome getBiomeOrMantle(Engine engine, Location l) {
|
||||
return engine.getBiomeOrMantle(l.getBlockX(), l.getBlockY(), l.getBlockZ());
|
||||
}
|
||||
|
||||
public static IrisBiome getSurfaceBiome(Engine engine, Chunk c) {
|
||||
return engine.getSurfaceBiome((c.getX() << 4) + 8, (c.getZ() << 4) + 8);
|
||||
}
|
||||
|
||||
public static IrisRegion getRegion(Engine engine, Chunk c) {
|
||||
return engine.getRegion((c.getX() << 4) + 8, (c.getZ() << 4) + 8);
|
||||
}
|
||||
|
||||
public static void gotoBiome(Engine engine, IrisBiome biome, Player player, boolean teleport) {
|
||||
find(Locator.surfaceBiome(biome.getLoadKey()), player, teleport, "Biome " + biome.getName());
|
||||
}
|
||||
|
||||
public static void gotoObject(Engine engine, String s, Player player, boolean teleport) {
|
||||
find(Locator.object(s), player, teleport, "Object " + s);
|
||||
}
|
||||
|
||||
public static void gotoRegion(Engine engine, IrisRegion r, Player player, boolean teleport) {
|
||||
if (!engine.getDimension().getRegions().contains(r.getLoadKey())) {
|
||||
player.sendMessage(C.RED + r.getName() + " is not defined in the dimension!");
|
||||
return;
|
||||
}
|
||||
|
||||
find(Locator.region(r.getLoadKey()), player, teleport, "Region " + r.getName());
|
||||
}
|
||||
|
||||
public static void gotoPOI(Engine engine, String type, Player p, boolean teleport) {
|
||||
find(Locator.poi(type), p, teleport, "POI " + type);
|
||||
}
|
||||
|
||||
public static void gotoStructure(Engine engine, String key, Player player, boolean teleport) {
|
||||
find(Locator.structure(key), player, teleport, "Structure " + key);
|
||||
}
|
||||
|
||||
private static void find(Locator<?> locator, Player player, boolean teleport, String message) {
|
||||
find(locator, player, 120_000, location -> {
|
||||
if (location == null) {
|
||||
player.sendMessage(C.RED + "Could not find " + message + " within search range.");
|
||||
return;
|
||||
}
|
||||
if (teleport) {
|
||||
J.runEntity(player, () -> teleportAsyncSafely(player, location));
|
||||
player.sendMessage(C.GREEN + "Teleporting to " + message + "...");
|
||||
} else {
|
||||
player.sendMessage(C.GREEN + message + " at: " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void find(Locator<?> locator, Player player, long timeout, Consumer<Location> consumer) {
|
||||
AtomicLong checks = new AtomicLong();
|
||||
long ms = M.ms();
|
||||
new SingleJob("Searching", () -> {
|
||||
try {
|
||||
World world = player.getWorld();
|
||||
Engine engine = IrisToolbelt.access(world).getEngine();
|
||||
Position2 at = locator.find(engine, new Position2(player.getLocation().getBlockX() >> 4, player.getLocation().getBlockZ() >> 4), timeout, checks::set).get();
|
||||
|
||||
if (at != null) {
|
||||
int bx = (at.getX() << 4) + 8;
|
||||
int bz = (at.getZ() << 4) + 8;
|
||||
consumer.accept(new Location(world, bx,
|
||||
world.getHighestBlockYAt(bx, bz) + 2,
|
||||
bz));
|
||||
} else {
|
||||
consumer.accept(null);
|
||||
}
|
||||
} catch (WrongEngineBroException | InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Searched " + Form.f(checks.get()) + " Chunks";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalWork() {
|
||||
return (int) timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWorkCompleted() {
|
||||
return (int) Math.min(M.ms() - ms, timeout - 1);
|
||||
}
|
||||
}.execute(new VolmitSender(player));
|
||||
}
|
||||
|
||||
private static void teleportAsyncSafely(Player player, Location location) {
|
||||
if (player == null || location == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (invokeNativeTeleportAsync(player, location)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
CompletableFuture<Boolean> teleportFuture = PaperLib.teleportAsync(player, location);
|
||||
if (teleportFuture != null) {
|
||||
teleportFuture.exceptionally(throwable -> {
|
||||
IrisLogging.reportError(throwable);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
IrisLogging.reportError(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean invokeNativeTeleportAsync(Player player, Location location) {
|
||||
try {
|
||||
Method teleportAsyncMethod = player.getClass().getMethod("teleportAsync", Location.class);
|
||||
teleportAsyncMethod.invoke(player, location);
|
||||
return true;
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
return false;
|
||||
} catch (Throwable throwable) {
|
||||
IrisLogging.reportError(throwable);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -20,6 +20,7 @@ package art.arcane.iris.util.common.director.context;
|
||||
|
||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.platform.EngineBukkitOps;
|
||||
import art.arcane.iris.util.common.director.DirectorContextHandler;
|
||||
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||
|
||||
@@ -32,7 +33,7 @@ public class BiomeContextHandler implements DirectorContextHandler<IrisBiome> {
|
||||
if (sender.isPlayer()
|
||||
&& IrisToolbelt.isIrisWorld(sender.player().getWorld())
|
||||
&& IrisToolbelt.access(sender.player().getWorld()).getEngine() != null) {
|
||||
return IrisToolbelt.access(sender.player().getWorld()).getEngine().getBiomeOrMantle(sender.player().getLocation());
|
||||
return EngineBukkitOps.getBiomeOrMantle(IrisToolbelt.access(sender.player().getWorld()).getEngine(), sender.player().getLocation());
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
+2
-1
@@ -21,6 +21,7 @@ package art.arcane.iris.util.common.director.context;
|
||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.object.IrisGenerator;
|
||||
import art.arcane.iris.engine.platform.EngineBukkitOps;
|
||||
import art.arcane.iris.util.common.director.DirectorContextHandler;
|
||||
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||
|
||||
@@ -36,7 +37,7 @@ public class GeneratorContextHandler implements DirectorContextHandler<IrisGener
|
||||
&& IrisToolbelt.isIrisWorld(sender.player().getWorld())
|
||||
&& IrisToolbelt.access(sender.player().getWorld()).getEngine() != null) {
|
||||
Engine engine = IrisToolbelt.access(sender.player().getWorld()).getEngine();
|
||||
return engine.getData().getGeneratorLoader().load(engine.getBiome(sender.player().getLocation()).getGenerators().getRandom().getGenerator());
|
||||
return engine.getData().getGeneratorLoader().load(EngineBukkitOps.getBiome(engine, sender.player().getLocation()).getGenerators().getRandom().getGenerator());
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@ package art.arcane.iris.util.common.director.context;
|
||||
|
||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||
import art.arcane.iris.engine.object.IrisRegion;
|
||||
import art.arcane.iris.engine.platform.EngineBukkitOps;
|
||||
import art.arcane.iris.util.common.director.DirectorContextHandler;
|
||||
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||
|
||||
@@ -32,7 +33,7 @@ public class RegionContextHandler implements DirectorContextHandler<IrisRegion>
|
||||
if (sender.isPlayer()
|
||||
&& IrisToolbelt.isIrisWorld(sender.player().getWorld())
|
||||
&& IrisToolbelt.access(sender.player().getWorld()).getEngine() != null) {
|
||||
return IrisToolbelt.access(sender.player().getWorld()).getEngine().getRegion(sender.player().getLocation());
|
||||
return EngineBukkitOps.getRegion(IrisToolbelt.access(sender.player().getWorld()).getEngine(), sender.player().getLocation());
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -47,6 +47,11 @@ public final class ClassloadProbe {
|
||||
"art.arcane.iris.util.common.misc.Bindings",
|
||||
"art.arcane.iris.util.common.misc.SlimJar",
|
||||
"art.arcane.iris.util.common.misc.ServerProperties",
|
||||
"art.arcane.iris.util.common.data.IrisCustomData",
|
||||
"art.arcane.iris.engine.IrisWorldManager",
|
||||
"art.arcane.iris.engine.framework.EngineAssignedWorldManager",
|
||||
"art.arcane.iris.engine.object.StudioMode",
|
||||
"art.arcane.iris.engine.framework.placer.WorldObjectPlacer",
|
||||
};
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
@@ -87,6 +92,9 @@ public final class ClassloadProbe {
|
||||
Class.forName(name, true, ClassloadProbe.class.getClassLoader());
|
||||
loaded++;
|
||||
} catch (Throwable failure) {
|
||||
if (System.getenv("PROBE_TRACE") != null && name.contains(System.getenv("PROBE_TRACE"))) {
|
||||
failure.printStackTrace(System.out);
|
||||
}
|
||||
String cause = rootCause(failure);
|
||||
if (critical) {
|
||||
criticalFailures.put(name, cause);
|
||||
|
||||
Reference in New Issue
Block a user