mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-08-27 04:37:47 +00:00
F
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
[23:25:34] [Test worker/INFO]: [STDERR]: [Iris/WARN] Native structure terrain envelope at 0,0 was clipped to Minecraft's 8-chunk structure reference range
|
||||
[23:25:34] [Test worker/INFO]: [STDERR]: [Iris/WARN] Native structure burial at 0,0 clamped to world floor: wanted -19, used -4
|
||||
[23:25:34] [Test worker/INFO]: [STDERR]: [Iris/WARN] Native structure burial at 0,0 clamped to world floor: wanted -5, used -2
|
||||
[20:01:46] [Test worker/INFO]: [STDERR]: [Iris/WARN] Native structure terrain envelope at 0,0 was clipped to Minecraft's 8-chunk structure reference range
|
||||
[20:01:46] [Test worker/INFO]: [STDERR]: [Iris/WARN] Native structure burial at 0,0 clamped to world floor: wanted -19, used -4
|
||||
[20:01:46] [Test worker/INFO]: [STDERR]: [Iris/WARN] Native structure burial at 0,0 clamped to world floor: wanted -5, used -2
|
||||
|
||||
+393
@@ -0,0 +1,393 @@
|
||||
package art.arcane.iris.core.nms.v26_2_R1;
|
||||
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.NativeFeatureGenerationPolicy;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisBiomeCustom;
|
||||
import art.arcane.iris.engine.object.IrisDecorationStep;
|
||||
import art.arcane.iris.engine.object.IrisDimension;
|
||||
import art.arcane.iris.engine.object.IrisImportedFeatureControl;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import it.unimi.dsi.fastutil.ints.IntArraySet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.BiomeGenerationSettings;
|
||||
import net.minecraft.world.level.biome.FeatureSorter;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.RandomSupport;
|
||||
import net.minecraft.world.level.levelgen.WorldgenRandom;
|
||||
import net.minecraft.world.level.levelgen.XoroshiroRandomSource;
|
||||
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Bukkit twin of the modded imported-feature stage. Same control, same semantics, same seeds: with
|
||||
* {@code importedFeatures.enabled} the vanilla placed-feature pass runs over Iris terrain, and with the
|
||||
* control off nothing here allocates or runs.
|
||||
*
|
||||
* <p>Iris does its own native structure pass and calls the delegate with {@code addVanillaDecorations=false},
|
||||
* so the vanilla feature half never runs on its own. This reproduces that half only - structures are never
|
||||
* placed twice.
|
||||
*
|
||||
* <p>Threading: called from {@code applyBiomeDecoration} on the worldgen thread that owns the chunk. The
|
||||
* FEATURES chunk step is not parallel-safe.
|
||||
*/
|
||||
final class ImportedFeatureStage {
|
||||
private static final String CYCLE_MARKER = "Feature order cycle found";
|
||||
|
||||
private final Engine engine;
|
||||
private volatile FeatureTable featureTable;
|
||||
private volatile IrisDimension inertDimension;
|
||||
|
||||
ImportedFeatureStage(Engine engine) {
|
||||
this.engine = engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generation settings for one biome holder, mapping Iris custom biomes onto their vanilla derivative.
|
||||
* Pass-through while the control is off, which is what keeps {@code BiomeFilter} behaving exactly as it
|
||||
* does today.
|
||||
*/
|
||||
BiomeGenerationSettings generationSettings(Holder<Biome> biome) {
|
||||
FeatureTable table = featureTable;
|
||||
if (table == null) {
|
||||
return null;
|
||||
}
|
||||
Holder<Biome> mapped = table.derivatives().get(holderKey(biome));
|
||||
return mapped == null ? null : mapped.value().getGenerationSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the table on the first decorated chunk, or leaves the stage inert. A feature-order cycle is
|
||||
* reported once here and degrades to features-off; it never reaches chunk generation as a crash.
|
||||
*
|
||||
* <p>The volatile fast path is unlocked, so a prepared stage costs two reads per chunk. The build is
|
||||
* synchronized: every worldgen thread decorating a chunk calls this, and two threads that both found the
|
||||
* stage unprepared would each run {@code FeatureSorter}, whose cycle detection is the expensive part.
|
||||
*/
|
||||
void prepare(WorldGenLevel level) {
|
||||
IrisDimension dimension = engine.getDimension();
|
||||
if (settled(dimension)) {
|
||||
return;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (settled(dimension)) {
|
||||
return;
|
||||
}
|
||||
build(level, dimension);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean settled(IrisDimension dimension) {
|
||||
FeatureTable current = featureTable;
|
||||
if (current != null && current.dimension() == dimension) {
|
||||
return true;
|
||||
}
|
||||
return inertDimension == dimension;
|
||||
}
|
||||
|
||||
private void build(WorldGenLevel level, IrisDimension dimension) {
|
||||
IrisImportedFeatureControl control;
|
||||
try {
|
||||
control = NativeFeatureGenerationPolicy.control(engine);
|
||||
} catch (RuntimeException error) {
|
||||
IrisLogging.error("Iris could not read importedFeatures for this dimension; features off: "
|
||||
+ error);
|
||||
markInert(dimension);
|
||||
return;
|
||||
}
|
||||
if (!control.shouldGenerateFeatures()) {
|
||||
markInert(dimension);
|
||||
return;
|
||||
}
|
||||
FeatureTable built;
|
||||
try {
|
||||
built = buildTable(level, control, dimension);
|
||||
} catch (Throwable error) {
|
||||
IrisLogging.error("Iris importedFeatures is off for " + dimensionKey()
|
||||
+ ": feature table construction failed: " + error);
|
||||
markInert(dimension);
|
||||
return;
|
||||
}
|
||||
if (built == null) {
|
||||
markInert(dimension);
|
||||
return;
|
||||
}
|
||||
featureTable = built;
|
||||
inertDimension = null;
|
||||
IrisLogging.info("Iris importedFeatures on for " + dimensionKey() + ": " + built.biomes().size()
|
||||
+ " biomes, " + built.steps().size() + " steps, " + built.derivatives().size()
|
||||
+ " custom-biome derivative maps");
|
||||
}
|
||||
|
||||
private void markInert(IrisDimension dimension) {
|
||||
featureTable = null;
|
||||
inertDimension = dimension;
|
||||
}
|
||||
|
||||
private FeatureTable buildTable(WorldGenLevel level, IrisImportedFeatureControl control,
|
||||
IrisDimension dimension) {
|
||||
Registry<Biome> registry = level.registryAccess().lookupOrThrow(Registries.BIOME);
|
||||
Set<String> visibleKeys = visibleBiomeKeys();
|
||||
// Registry-ordered walk, never a hash-ordered set: FeatureSorter's cycle detection walks this list and
|
||||
// an unordered walk makes detection depend on JVM hash order.
|
||||
List<Holder<Biome>> biomes = new ArrayList<>();
|
||||
Map<String, Holder<Biome>> byKey = new HashMap<>();
|
||||
registry.listElements().forEach((Holder.Reference<Biome> reference) -> {
|
||||
String key = holderKey(reference);
|
||||
if (key != null && visibleKeys.contains(key)) {
|
||||
biomes.add(reference);
|
||||
byKey.put(key, reference);
|
||||
}
|
||||
});
|
||||
if (biomes.isEmpty()) {
|
||||
IrisLogging.error("Iris importedFeatures is on but " + dimensionKey()
|
||||
+ " exposes no registered biomes; features off");
|
||||
return null;
|
||||
}
|
||||
Map<String, Holder<Biome>> derivatives = customBiomeDerivatives(registry, byKey);
|
||||
List<FeatureSorter.StepFeatureData> steps;
|
||||
try {
|
||||
steps = FeatureSorter.buildFeaturesPerStep(biomes,
|
||||
(Holder<Biome> biome) -> settingsFor(biome, derivatives).features(), true);
|
||||
} catch (IllegalStateException error) {
|
||||
String message = error.getMessage();
|
||||
if (message == null || !message.contains(CYCLE_MARKER)) {
|
||||
throw error;
|
||||
}
|
||||
IrisLogging.error("Iris importedFeatures is off for " + dimensionKey()
|
||||
+ ": the registered placed features cannot be ordered. " + message
|
||||
+ ". Remove or reorder the conflicting content, or leave importedFeatures.enabled false.");
|
||||
return null;
|
||||
}
|
||||
boolean filtered = control.getDisabled() != null && !control.getDisabled().isEmpty();
|
||||
return new FeatureTable(dimension, control, List.copyOf(biomes), Set.copyOf(biomes),
|
||||
Map.copyOf(byKey), steps, Map.copyOf(derivatives), filtered);
|
||||
}
|
||||
|
||||
/**
|
||||
* Every biome key Iris can write into a chunk section: the structure derivative, the raw derivative, every
|
||||
* scatter entry, and every generated custom biome.
|
||||
*/
|
||||
private Set<String> visibleBiomeKeys() {
|
||||
Set<String> keys = new LinkedHashSet<>();
|
||||
String namespace = engine.getDimension().getLoadKey().toLowerCase(Locale.ROOT);
|
||||
for (IrisBiome irisBiome : engine.getAllBiomes()) {
|
||||
addKey(keys, irisBiome.getStructureDerivativeKey());
|
||||
addKey(keys, irisBiome.getDerivativeKey());
|
||||
addKey(keys, irisBiome.getVanillaDerivativeKey());
|
||||
for (String scatter : irisBiome.getBiomeScatter()) {
|
||||
addKey(keys, scatter);
|
||||
}
|
||||
for (String scatter : irisBiome.getBiomeSkyScatter()) {
|
||||
addKey(keys, scatter);
|
||||
}
|
||||
if (!irisBiome.isCustom()) {
|
||||
continue;
|
||||
}
|
||||
for (IrisBiomeCustom customBiome : irisBiome.getCustomDerivitives()) {
|
||||
addKey(keys, namespace + ":" + customBiome.getId());
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps every generated Iris custom biome key onto the registry holder of its Iris biome's vanilla
|
||||
* derivative. The custom biome's own datapack JSON carries no features by design.
|
||||
*/
|
||||
private Map<String, Holder<Biome>> customBiomeDerivatives(Registry<Biome> registry,
|
||||
Map<String, Holder<Biome>> byKey) {
|
||||
Map<String, Holder<Biome>> derivatives = new HashMap<>();
|
||||
String namespace = engine.getDimension().getLoadKey().toLowerCase(Locale.ROOT);
|
||||
for (IrisBiome irisBiome : engine.getAllBiomes()) {
|
||||
if (!irisBiome.isCustom()) {
|
||||
continue;
|
||||
}
|
||||
String derivativeKey = normalizeKey(irisBiome.getVanillaDerivativeKey());
|
||||
// Resolve from the registry, not only from the visible biome set: a sea or shore biome's structure
|
||||
// derivative is rewritten away from its vanilla derivative, so the derivative whose features we
|
||||
// want is not always a biome Iris can emit.
|
||||
Holder<Biome> derivative = byKey.get(derivativeKey);
|
||||
if (derivative == null) {
|
||||
derivative = resolveHolder(registry, derivativeKey);
|
||||
}
|
||||
if (derivative == null) {
|
||||
IrisLogging.warn("Iris importedFeatures: vanilla derivative " + derivativeKey + " of biome "
|
||||
+ irisBiome.getLoadKey()
|
||||
+ " is not registered; its custom biomes generate no imported features");
|
||||
continue;
|
||||
}
|
||||
for (IrisBiomeCustom customBiome : irisBiome.getCustomDerivitives()) {
|
||||
derivatives.put(namespace + ":" + customBiome.getId().toLowerCase(Locale.ROOT), derivative);
|
||||
}
|
||||
}
|
||||
return derivatives;
|
||||
}
|
||||
|
||||
private static Holder<Biome> resolveHolder(Registry<Biome> registry, String key) {
|
||||
if (registry == null || key == null || key.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
Identifier identifier = Identifier.tryParse(key);
|
||||
if (identifier == null) {
|
||||
return null;
|
||||
}
|
||||
return registry.get(identifier).<Holder<Biome>>map((Holder.Reference<Biome> reference) -> reference)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static BiomeGenerationSettings settingsFor(Holder<Biome> biome,
|
||||
Map<String, Holder<Biome>> derivatives) {
|
||||
Holder<Biome> mapped = derivatives.get(holderKey(biome));
|
||||
return mapped == null
|
||||
? biome.value().getGenerationSettings()
|
||||
: mapped.value().getGenerationSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the vanilla placed-feature pass for one chunk on the calling worldgen thread. A no-op while the
|
||||
* control is disabled or the table degraded.
|
||||
*/
|
||||
void run(WorldGenLevel level, ChunkAccess chunk, ChunkGenerator owner) {
|
||||
FeatureTable table = featureTable;
|
||||
if (table == null) {
|
||||
return;
|
||||
}
|
||||
ChunkPos centerPos = chunk.getPos();
|
||||
SectionPos sectionPos = SectionPos.of(centerPos, level.getMinSectionY());
|
||||
BlockPos origin = sectionPos.origin();
|
||||
Registry<PlacedFeature> featureRegistry = level.registryAccess().lookupOrThrow(Registries.PLACED_FEATURE);
|
||||
List<FeatureSorter.StepFeatureData> steps = table.steps();
|
||||
WorldgenRandom random = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||
long decorationSeed = random.setDecorationSeed(level.getSeed(), origin.getX(), origin.getZ());
|
||||
Set<Holder<Biome>> chunkBiomes = chunkBiomes(level, sectionPos, table);
|
||||
|
||||
try {
|
||||
for (int stepIndex = 0; stepIndex < steps.size(); stepIndex++) {
|
||||
if (!table.control().shouldGenerateStep(IrisDecorationStep.byOrdinal(stepIndex))) {
|
||||
continue;
|
||||
}
|
||||
placeStep(level, table, steps.get(stepIndex), featureRegistry, chunkBiomes, owner,
|
||||
random, decorationSeed, origin, stepIndex);
|
||||
}
|
||||
} catch (Throwable error) {
|
||||
throw new IllegalStateException("Iris imported feature placement failed for chunk "
|
||||
+ centerPos.x() + "," + centerPos.z(), error);
|
||||
} finally {
|
||||
level.setCurrentlyGenerating(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void placeStep(WorldGenLevel level, FeatureTable table, FeatureSorter.StepFeatureData stepData,
|
||||
Registry<PlacedFeature> featureRegistry, Set<Holder<Biome>> chunkBiomes,
|
||||
ChunkGenerator owner, WorldgenRandom random, long decorationSeed,
|
||||
BlockPos origin, int stepIndex) {
|
||||
IntSet stepFeatures = new IntArraySet();
|
||||
for (Holder<Biome> biome : chunkBiomes) {
|
||||
List<HolderSet<PlacedFeature>> biomeFeatures = settingsFor(biome, table.derivatives()).features();
|
||||
if (stepIndex >= biomeFeatures.size()) {
|
||||
continue;
|
||||
}
|
||||
for (Holder<PlacedFeature> feature : biomeFeatures.get(stepIndex)) {
|
||||
stepFeatures.add(stepData.indexMapping().applyAsInt(feature.value()));
|
||||
}
|
||||
}
|
||||
if (stepFeatures.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// Sorted global indices: identical ordering to vanilla, and each feature's seed comes from its own
|
||||
// global index, so denying one feature never shifts another.
|
||||
int[] featureIndices = stepFeatures.toIntArray();
|
||||
Arrays.sort(featureIndices);
|
||||
for (int globalIndex : featureIndices) {
|
||||
PlacedFeature feature = stepData.features().get(globalIndex);
|
||||
if (table.filtered()) {
|
||||
Identifier featureId = featureRegistry.getKey(feature);
|
||||
if (featureId != null && !table.control().shouldGenerate(featureId.toString())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
random.setFeatureSeed(decorationSeed, globalIndex, stepIndex);
|
||||
level.setCurrentlyGenerating(() -> describeFeature(featureRegistry, feature));
|
||||
feature.placeWithBiomeCheck(level, owner, random, origin);
|
||||
}
|
||||
}
|
||||
|
||||
private static String describeFeature(Registry<PlacedFeature> registry, PlacedFeature feature) {
|
||||
Identifier id = registry.getKey(feature);
|
||||
return id == null ? feature.toString() : id.toString();
|
||||
}
|
||||
|
||||
private Set<Holder<Biome>> chunkBiomes(WorldGenLevel level, SectionPos sectionPos, FeatureTable table) {
|
||||
List<Holder<Biome>> collected = new ArrayList<>();
|
||||
ChunkPos.rangeClosed(sectionPos.chunk(), 1).forEach((ChunkPos chunkPos) -> {
|
||||
ChunkAccess neighbour = level.getChunk(chunkPos.x(), chunkPos.z());
|
||||
for (LevelChunkSection section : neighbour.getSections()) {
|
||||
section.getBiomes().getAll(collected::add);
|
||||
}
|
||||
});
|
||||
Set<Holder<Biome>> present = new LinkedHashSet<>();
|
||||
for (Holder<Biome> biome : collected) {
|
||||
if (table.biomeSet().contains(biome)) {
|
||||
present.add(biome);
|
||||
continue;
|
||||
}
|
||||
String key = holderKey(biome);
|
||||
Holder<Biome> canonical = key == null ? null : table.byKey().get(key);
|
||||
if (canonical != null) {
|
||||
present.add(canonical);
|
||||
}
|
||||
}
|
||||
return present;
|
||||
}
|
||||
|
||||
private static void addKey(Set<String> keys, String key) {
|
||||
String normalized = normalizeKey(key);
|
||||
if (normalized != null) {
|
||||
keys.add(normalized);
|
||||
}
|
||||
}
|
||||
|
||||
private String dimensionKey() {
|
||||
IrisDimension dimension = engine.getDimension();
|
||||
return dimension == null ? "<unbound>" : dimension.getLoadKey();
|
||||
}
|
||||
|
||||
private static String holderKey(Holder<Biome> holder) {
|
||||
return holder.unwrapKey()
|
||||
.map(key -> key.identifier().toString().toLowerCase(Locale.ROOT))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static String normalizeKey(String key) {
|
||||
Identifier identifier = key == null ? null : Identifier.tryParse(key);
|
||||
return identifier == null ? null : identifier.toString().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
private record FeatureTable(IrisDimension dimension, IrisImportedFeatureControl control,
|
||||
List<Holder<Biome>> biomes, Set<Holder<Biome>> biomeSet,
|
||||
Map<String, Holder<Biome>> byKey,
|
||||
List<FeatureSorter.StepFeatureData> steps,
|
||||
Map<String, Holder<Biome>> derivatives, boolean filtered) {
|
||||
}
|
||||
}
|
||||
+22
@@ -50,6 +50,7 @@ import net.minecraft.world.level.NoiseColumn;
|
||||
import net.minecraft.world.level.StructureManager;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.BiomeGenerationSettings;
|
||||
import net.minecraft.world.level.biome.BiomeManager;
|
||||
import net.minecraft.world.level.biome.BiomeSource;
|
||||
import net.minecraft.world.level.biome.MobSpawnSettings;
|
||||
@@ -106,6 +107,7 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
private final int runtimeHeight;
|
||||
private final int runtimeSeaLevel;
|
||||
private final ConcurrentHashMap<SpawnTableKey, WeightedList<MobSpawnSettings.SpawnerData>> mergedSpawnTables = new ConcurrentHashMap<>();
|
||||
private final ImportedFeatureStage importedFeatures;
|
||||
private volatile ReachableStructureCache reachableStructureCache;
|
||||
private volatile StructureStepCache structureStepCache;
|
||||
|
||||
@@ -118,6 +120,7 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
this.delegate = delegate;
|
||||
this.engine = engine;
|
||||
this.customBiomeSource = customBiomeSource;
|
||||
this.importedFeatures = new ImportedFeatureStage(engine);
|
||||
ServerLevel level = ((CraftWorld) world).getHandle();
|
||||
this.runtimeMinY = level.getMinY();
|
||||
this.runtimeHeight = level.getHeight();
|
||||
@@ -425,14 +428,33 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
|
||||
@Override
|
||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
||||
// Bind-time equivalent for Bukkit: the table is built on the first decorated chunk, which is where a
|
||||
// feature-order cycle is reported once and degraded to features-off.
|
||||
importedFeatures.prepare(generatoraccessseed);
|
||||
try (GenerationSessionLease lease = requireGenerationLease("bukkit_nms_biome_decoration");
|
||||
IrisContext.Scope ignored = IrisContext.open(engine, lease.sessionId(), null)) {
|
||||
addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
||||
placeVanillaStructures(generatoraccessseed, ichunkaccess, structuremanager);
|
||||
// Vanilla's placed-feature pass, on THIS thread. The delegate is still called with
|
||||
// addVanillaDecorations=false below, so the vanilla half never runs twice. Inert unless the
|
||||
// dimension set importedFeatures.enabled.
|
||||
importedFeatures.run(generatoraccessseed, ichunkaccess, this);
|
||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iris custom biomes carry no features in their datapack JSON by design; when importedFeatures is on they
|
||||
* inherit the generation settings of the vanilla biome their Iris biome derives from. This is the gate
|
||||
* {@code BiomeFilter} consults, so it has to agree with the feature pass. With the control off this is
|
||||
* exactly the inherited behaviour.
|
||||
*/
|
||||
@Override
|
||||
public BiomeGenerationSettings getBiomeGenerationSettings(Holder<Biome> holder) {
|
||||
BiomeGenerationSettings imported = importedFeatures.generationSettings(holder);
|
||||
return imported == null ? super.getBiomeGenerationSettings(holder) : imported;
|
||||
}
|
||||
|
||||
private void placeVanillaStructures(WorldGenLevel world, ChunkAccess chunk, StructureManager structureManager) {
|
||||
if (!structureManager.shouldGenerateStructures()) {
|
||||
ChunkPos disabledChunk = chunk.getPos();
|
||||
|
||||
@@ -42,6 +42,15 @@ tasks.named('processResources').configure {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named('compileJava', JavaCompile).configure {
|
||||
// lombok.config decides how equals/hashCode/toString are generated (fields, never getters), so editing it
|
||||
// changes this module's bytecode. Gradle does not know that on its own and would serve a stale up-to-date
|
||||
// build until something else in the module changed.
|
||||
inputs.file(rootProject.file('lombok.config'))
|
||||
.withPropertyName('lombokConfig')
|
||||
.withPathSensitivity(PathSensitivity.NONE)
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar).configure {
|
||||
archiveBaseName.set('iris-bukkit-plugin')
|
||||
}
|
||||
|
||||
@@ -231,11 +231,12 @@ public class CommandSVC implements IrisService, CommandExecutor, TabCompleter, D
|
||||
return false;
|
||||
}
|
||||
|
||||
DirectorMiniMenu.deliver(sender, DirectorMiniMenu.render(
|
||||
DirectorMiniMenu.deliver(
|
||||
sender,
|
||||
request.get(),
|
||||
DirectorMiniMenu.Theme.irisGreen(),
|
||||
IrisLanguage.directorResolver()
|
||||
));
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -52,6 +52,7 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
||||
|
||||
private IrisSessionRegistry registry;
|
||||
private IrisProtocolServer protocolServer;
|
||||
private IrisVisionRequestService visionService;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
@@ -62,7 +63,8 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
||||
protocolServer = new IrisProtocolServer(registry, SERVER_CAPABILITIES, brand(), true);
|
||||
EngineResolver engineResolver = IrisProtocolService::resolveEngine;
|
||||
protocolServer.setEngineResolver(engineResolver);
|
||||
protocolServer.setVisionTileHandler(IrisVisionRequestService.create(engineResolver, registry));
|
||||
visionService = IrisVisionRequestService.create(engineResolver, registry);
|
||||
protocolServer.setVisionTileHandler(visionService);
|
||||
IrisServices.register(IrisProtocolServer.class, protocolServer);
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
registry.register(new IrisSession(player.getUniqueId().toString(), this));
|
||||
@@ -83,6 +85,7 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
||||
}
|
||||
registry = null;
|
||||
protocolServer = null;
|
||||
visionService = null;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -109,7 +112,12 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
||||
if (current == null) {
|
||||
return;
|
||||
}
|
||||
current.unregister(event.getPlayer().getUniqueId().toString());
|
||||
String sessionId = event.getPlayer().getUniqueId().toString();
|
||||
current.unregister(sessionId);
|
||||
IrisVisionRequestService vision = visionService;
|
||||
if (vision != null) {
|
||||
vision.clearSession(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user