mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-23 16:44:06 +00:00
[VERY VERY VERY BAD IDEA]
This commit is contained in:
1 parent
f0e7fea13b
commit
2fa0853e42
892 files changed
+13482
-53554
No files matched your search
+9
-5
@@ -1,5 +1,9 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeModdedChunkGenerator;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeContainerLoot;
|
||||
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.SharedConstants;
|
||||
@@ -66,13 +70,13 @@ public class IrisModdedBlockEntityParityTest {
|
||||
BlockPos position = new BlockPos(3, 70, 5);
|
||||
chunk.setBlockState(position, Blocks.CHEST.defaultBlockState(), 0);
|
||||
|
||||
IrisModdedChunkGenerator.createDefaultBlockEntity(chunk, position, Blocks.CHEST.defaultBlockState());
|
||||
NativeModdedChunkGenerator.createDefaultBlockEntity(chunk, position, Blocks.CHEST.defaultBlockState());
|
||||
|
||||
BlockEntity blockEntity = chunk.getBlockEntity(position);
|
||||
assertNotNull(blockEntity);
|
||||
assertTrue(blockEntity instanceof Container);
|
||||
Container container = (Container) blockEntity;
|
||||
ModdedLootApplier.fillContainer(container, List.of(new ItemStack(Items.DIAMOND)), new RNG(17L));
|
||||
NativeContainerLoot.fillContainer(container, List.of(new ItemStack(Items.DIAMOND)), new RNG(17L), message -> {});
|
||||
assertEquals(1, countItem(container, Items.DIAMOND));
|
||||
CompoundTag saved = blockEntity.saveWithoutMetadata(registries);
|
||||
ChestBlockEntity restored = new ChestBlockEntity(position, Blocks.CHEST.defaultBlockState());
|
||||
@@ -94,9 +98,9 @@ public class IrisModdedBlockEntityParityTest {
|
||||
chunk.setBlockState(signPosition, signState, 0);
|
||||
chunk.setBlockState(spawnerPosition, spawnerState, 0);
|
||||
chunk.setBlockState(bannerPosition, bannerState, 0);
|
||||
IrisModdedChunkGenerator.createDefaultBlockEntity(chunk, signPosition, signState);
|
||||
IrisModdedChunkGenerator.createDefaultBlockEntity(chunk, spawnerPosition, spawnerState);
|
||||
IrisModdedChunkGenerator.createDefaultBlockEntity(chunk, bannerPosition, bannerState);
|
||||
NativeModdedChunkGenerator.createDefaultBlockEntity(chunk, signPosition, signState);
|
||||
NativeModdedChunkGenerator.createDefaultBlockEntity(chunk, spawnerPosition, spawnerState);
|
||||
NativeModdedChunkGenerator.createDefaultBlockEntity(chunk, bannerPosition, bannerState);
|
||||
|
||||
assertTrue(chunk.getBlockEntity(signPosition) instanceof SignBlockEntity);
|
||||
assertTrue(chunk.getBlockEntity(spawnerPosition) instanceof SpawnerBlockEntity);
|
||||
|
||||
+2
@@ -1,5 +1,7 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeSpawnTableMerger;
|
||||
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.util.random.Weighted;
|
||||
|
||||
+2
@@ -1,5 +1,7 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedHeightmaps;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.SimpleBitStorage;
|
||||
import org.junit.Test;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.iris.nativegen.NativeStructureLocateResults;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.terrain.NativeStructureLocateResults;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
|
||||
+29
-29
@@ -9,7 +9,7 @@ import art.arcane.iris.generation.runtime.Engine;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.mantle.flag.MantleFlag;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeBlockPoint;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
@@ -40,31 +40,31 @@ public class IrisModdedStructureParityTest {
|
||||
|
||||
@Test
|
||||
public void surfaceBiomeFastPathBeginsAboveTheCaveSwitch() {
|
||||
assertFalse(IrisModdedBiomeSource.isGuaranteedSurfaceBiome(-2, -256));
|
||||
assertTrue(IrisModdedBiomeSource.isGuaranteedSurfaceBiome(-1, -256));
|
||||
assertFalse(IrisModdedBiomeSource.isGuaranteedSurfaceBiome(10, 0));
|
||||
assertTrue(IrisModdedBiomeSource.isGuaranteedSurfaceBiome(11, 0));
|
||||
assertFalse(ModdedBiomePolicy.isGuaranteedSurfaceBiome(-2, -256));
|
||||
assertTrue(ModdedBiomePolicy.isGuaranteedSurfaceBiome(-1, -256));
|
||||
assertFalse(ModdedBiomePolicy.isGuaranteedSurfaceBiome(10, 0));
|
||||
assertTrue(ModdedBiomePolicy.isGuaranteedSurfaceBiome(11, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void visibleCaveBiomeBeginsEightBlocksBelowTheSurface() {
|
||||
assertFalse(IrisModdedBiomeSource.isUnderground(93, 100));
|
||||
assertTrue(IrisModdedBiomeSource.isUnderground(92, 100));
|
||||
assertTrue(IrisModdedBiomeSource.isUnderground(-20, 100));
|
||||
assertFalse(ModdedBiomePolicy.isUnderground(93, 100));
|
||||
assertTrue(ModdedBiomePolicy.isUnderground(92, 100));
|
||||
assertTrue(ModdedBiomePolicy.isUnderground(-20, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void monumentBiomeCubeUsesSurfaceBiomesAtShiftedSeaLevel() {
|
||||
assertTrue(IrisModdedBiomeSource.isMonumentSurfaceBiomeQuery(50, 29, -256, 306));
|
||||
assertFalse(IrisModdedBiomeSource.isMonumentSurfaceBiomeQuery(51, 29, -256, 306));
|
||||
assertFalse(IrisModdedBiomeSource.isMonumentSurfaceBiomeQuery(50, 28, -256, 306));
|
||||
assertTrue(ModdedBiomePolicy.isMonumentSurfaceBiomeQuery(50, 29, -256, 306));
|
||||
assertFalse(ModdedBiomePolicy.isMonumentSurfaceBiomeQuery(51, 29, -256, 306));
|
||||
assertFalse(ModdedBiomePolicy.isMonumentSurfaceBiomeQuery(50, 28, -256, 306));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void strongholdRingSearchSamplesOneQuartColumnPerChunk() {
|
||||
assertEquals(4, IrisModdedBiomeSource.horizontalBiomeSearchQuartStep(0, 112));
|
||||
assertEquals(1, IrisModdedBiomeSource.horizontalBiomeSearchQuartStep(1, 112));
|
||||
assertEquals(1, IrisModdedBiomeSource.horizontalBiomeSearchQuartStep(0, 111));
|
||||
assertEquals(4, ModdedBiomePolicy.horizontalBiomeSearchQuartStep(0, 112));
|
||||
assertEquals(1, ModdedBiomePolicy.horizontalBiomeSearchQuartStep(1, 112));
|
||||
assertEquals(1, ModdedBiomePolicy.horizontalBiomeSearchQuartStep(0, 111));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -86,9 +86,9 @@ public class IrisModdedStructureParityTest {
|
||||
|
||||
@Test
|
||||
public void reconciledSpawnUsesOriginAndClampedSurfaceHeight() {
|
||||
assertEquals(new BlockPos(0, 73, 0), ModdedEngineBootstrap.reconciledSpawnPosition(73, -64, 384));
|
||||
assertEquals(new BlockPos(0, -63, 0), ModdedEngineBootstrap.reconciledSpawnPosition(-100, -64, 384));
|
||||
assertEquals(new BlockPos(0, 318, 0), ModdedEngineBootstrap.reconciledSpawnPosition(400, -64, 384));
|
||||
assertEquals(new NativeBlockPoint(0, 73, 0), ModdedEngineBootstrap.reconciledSpawnPosition(73, -64, 384));
|
||||
assertEquals(new NativeBlockPoint(0, -63, 0), ModdedEngineBootstrap.reconciledSpawnPosition(-100, -64, 384));
|
||||
assertEquals(new NativeBlockPoint(0, 318, 0), ModdedEngineBootstrap.reconciledSpawnPosition(400, -64, 384));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -102,7 +102,7 @@ public class IrisModdedStructureParityTest {
|
||||
^ ((long) blockY * 132897987541L)
|
||||
^ ((long) blockZ * 42317861L);
|
||||
|
||||
assertEquals(expected, IrisModdedBiomeSource.biomeResolutionSeed(worldSeed, blockX, blockY, blockZ));
|
||||
assertEquals(expected, ModdedBiomePolicy.biomeResolutionSeed(worldSeed, blockX, blockY, blockZ));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -114,19 +114,19 @@ public class IrisModdedStructureParityTest {
|
||||
|
||||
assertEquals(
|
||||
ModdedWorldgenIds.biomeRef("pack", "Upper", "Aurora"),
|
||||
IrisModdedBiomeSource.customBiomeRef("pack", upper, "Aurora")
|
||||
ModdedBiomePolicy.customBiomeRef("pack", upper, "Aurora")
|
||||
);
|
||||
assertFalse(IrisModdedBiomeSource.customBiomeRef("pack", host, "Aurora")
|
||||
.equals(IrisModdedBiomeSource.customBiomeRef("pack", upper, "Aurora")));
|
||||
assertFalse(ModdedBiomePolicy.customBiomeRef("pack", host, "Aurora")
|
||||
.equals(ModdedBiomePolicy.customBiomeRef("pack", upper, "Aurora")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void temporaryNaturalBiomeAnswersAreNotMemoized() {
|
||||
Engine engine = mock(Engine.class);
|
||||
when(engine.answersFromNaturalTerrain(12, -8)).thenReturn(true);
|
||||
assertFalse(IrisModdedBiomeSource.isBiomeCacheable(engine, 12, -8));
|
||||
assertFalse(ModdedBiomePolicy.isBiomeCacheable(engine, 12, -8));
|
||||
when(engine.answersFromNaturalTerrain(12, -8)).thenReturn(false);
|
||||
assertTrue(IrisModdedBiomeSource.isBiomeCacheable(engine, 12, -8));
|
||||
assertTrue(ModdedBiomePolicy.isBiomeCacheable(engine, 12, -8));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -162,16 +162,16 @@ public class IrisModdedStructureParityTest {
|
||||
public void structureStateRejectsBiomesOutsideThePackContract() {
|
||||
Set<String> generated = Set.of("minecraft:deep_ocean", "minecraft:dark_forest");
|
||||
|
||||
assertTrue(IrisModdedBiomeSource.isGeneratedBiomeKey("minecraft:deep_ocean", generated));
|
||||
assertTrue(IrisModdedBiomeSource.isGeneratedBiomeKey("MINECRAFT:DARK_FOREST", generated));
|
||||
assertFalse(IrisModdedBiomeSource.isGeneratedBiomeKey("minecraft:desert", generated));
|
||||
assertFalse(IrisModdedBiomeSource.isGeneratedBiomeKey(null, generated));
|
||||
assertTrue(ModdedBiomePolicy.isGeneratedBiomeKey("minecraft:deep_ocean", generated));
|
||||
assertTrue(ModdedBiomePolicy.isGeneratedBiomeKey("MINECRAFT:DARK_FOREST", generated));
|
||||
assertFalse(ModdedBiomePolicy.isGeneratedBiomeKey("minecraft:desert", generated));
|
||||
assertFalse(ModdedBiomePolicy.isGeneratedBiomeKey(null, generated));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureBiomeContractRejectsAnEmptyConfiguredSet() {
|
||||
IllegalStateException error = assertThrows(IllegalStateException.class,
|
||||
() -> IrisModdedBiomeSource.requireConfiguredStructureBiomeKeys(Set.of()));
|
||||
() -> ModdedBiomePolicy.requireConfiguredStructureBiomeKeys(Set.of()));
|
||||
|
||||
assertEquals("Iris has no configured structure biomes", error.getMessage());
|
||||
}
|
||||
@@ -180,7 +180,7 @@ public class IrisModdedStructureParityTest {
|
||||
public void structureBiomeContractPreservesConfiguredKeysDuringBootstrap() {
|
||||
Set<String> configured = Set.of("minecraft:deep_ocean", "minecraft:dark_forest");
|
||||
|
||||
assertSame(configured, IrisModdedBiomeSource.requireConfiguredStructureBiomeKeys(configured));
|
||||
assertSame(configured, ModdedBiomePolicy.requireConfiguredStructureBiomeKeys(configured));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class MainWorldServiceInstanceRootTest {
|
||||
@Test
|
||||
public void universeOptionIsReadInBothArgumentForms() {
|
||||
assertEquals("worlds", MainWorldService.commandLineOption(
|
||||
List.of("nogui", "--universe", "worlds"), "universe"));
|
||||
assertEquals("worlds", MainWorldService.commandLineOption(
|
||||
List.of("--universe=worlds", "nogui"), "universe"));
|
||||
assertEquals("survival", MainWorldService.commandLineOption(
|
||||
List.of("--universe", "worlds", "--world", "survival"), "world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingOrValuelessOptionsResolveToNull() {
|
||||
assertNull(MainWorldService.commandLineOption(List.of("nogui"), "universe"));
|
||||
assertNull(MainWorldService.commandLineOption(List.of(), "world"));
|
||||
assertNull(MainWorldService.commandLineOption(List.of("nogui", "--world"), "world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void universeRootDefaultsToTheInstanceRootAndHonorsTheOption() throws IOException {
|
||||
Path instanceRoot = Files.createTempDirectory("iris-instance");
|
||||
Path elsewhere = Files.createTempDirectory("iris-elsewhere");
|
||||
|
||||
assertEquals(instanceRoot, MainWorldService.universeRoot(instanceRoot, null));
|
||||
assertEquals(instanceRoot, MainWorldService.universeRoot(instanceRoot, ""));
|
||||
assertEquals(instanceRoot.resolve("worlds"), MainWorldService.universeRoot(instanceRoot, "worlds"));
|
||||
assertEquals(elsewhere, MainWorldService.universeRoot(instanceRoot, elsewhere.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void worldRootResolvesInsideTheUniverse() throws IOException {
|
||||
Path universe = Files.createTempDirectory("iris-universe");
|
||||
Path world = Files.createDirectory(universe.resolve("survival"));
|
||||
|
||||
assertEquals(world.toAbsolutePath().normalize(),
|
||||
MainWorldService.resolveWorldRoot(universe, "survival"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void worldRootRefusesToEscapeTheUniverse() throws IOException {
|
||||
Path universe = Files.createTempDirectory("iris-universe");
|
||||
Files.createDirectory(universe.resolve("survival"));
|
||||
|
||||
IOException escaped = assertThrows(IOException.class,
|
||||
() -> MainWorldService.resolveWorldRoot(universe, "../survival"));
|
||||
IOException empty = assertThrows(IOException.class,
|
||||
() -> MainWorldService.resolveWorldRoot(universe, "."));
|
||||
|
||||
assertTrue(escaped.getMessage().contains("Unsafe world name"));
|
||||
assertTrue(empty.getMessage().contains("Unsafe world name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void worldRootReportsMissingDirectoriesAsTheRecoverableCase() throws IOException {
|
||||
Path universe = Files.createTempDirectory("iris-universe");
|
||||
|
||||
MainWorldService.MissingWorldRootException missingWorld = assertThrows(
|
||||
MainWorldService.MissingWorldRootException.class,
|
||||
() -> MainWorldService.resolveWorldRoot(universe, "survival"));
|
||||
MainWorldService.MissingWorldRootException missingUniverse = assertThrows(
|
||||
MainWorldService.MissingWorldRootException.class,
|
||||
() -> MainWorldService.resolveWorldRoot(universe.resolve("absent"), "survival"));
|
||||
|
||||
assertTrue(missingWorld.getMessage().contains("world directory does not exist"));
|
||||
assertEquals(universe.resolve("survival").toAbsolutePath().normalize(), missingWorld.path());
|
||||
assertTrue(missingUniverse.getMessage().contains("universe directory does not exist"));
|
||||
assertEquals(universe.resolve("absent"), missingUniverse.path());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unsafeWorldNameIsNotTreatedAsAMissingWorldRoot() throws IOException {
|
||||
Path universe = Files.createTempDirectory("iris-universe");
|
||||
|
||||
IOException escaped = assertThrows(IOException.class,
|
||||
() -> MainWorldService.resolveWorldRoot(universe, "../survival"));
|
||||
|
||||
assertFalse(escaped instanceof MainWorldService.MissingWorldRootException);
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeBiomeSourceAccess;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedBiomePolicyTest {
|
||||
@Test
|
||||
public void registryOrderAndHolderIdentitySurviveThePolicyBoundaryAndRefreshOnRepoint() {
|
||||
BiomeToken ocean = new BiomeToken("minecraft:ocean");
|
||||
BiomeToken forest = new BiomeToken("minecraft:forest");
|
||||
List<BiomeToken> entries = new ArrayList<>(List.of(forest, ocean));
|
||||
AtomicReference<Set<String>> configured = new AtomicReference<>(Set.of(ocean.key(), forest.key()));
|
||||
ModdedBiomePolicy<BiomeToken, Object> policy = policy(entries, configured);
|
||||
|
||||
List<BiomeToken> first = policy.orderedPossibleBiomes();
|
||||
assertSame(forest, first.getFirst());
|
||||
assertSame(ocean, first.getLast());
|
||||
assertEquals(first, new ArrayList<>(policy.possibleBiomes()));
|
||||
|
||||
BiomeToken desert = new BiomeToken("minecraft:desert");
|
||||
entries.clear();
|
||||
entries.add(desert);
|
||||
configured.set(Set.of(desert.key()));
|
||||
assertSame(first, policy.orderedPossibleBiomes());
|
||||
|
||||
policy.clearCaches();
|
||||
|
||||
assertEquals(1L, policy.packGeneration());
|
||||
assertEquals(1, policy.orderedPossibleBiomes().size());
|
||||
assertSame(desert, policy.orderedPossibleBiomes().getFirst());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingRequiredStructureBiomesFailBeforePublishingAPartialSet() {
|
||||
AtomicReference<Set<String>> configured = new AtomicReference<>(Set.of("example:missing"));
|
||||
ModdedBiomePolicy<BiomeToken, Object> policy = policy(
|
||||
new ArrayList<>(List.of(new BiomeToken("minecraft:plains"))), configured);
|
||||
|
||||
IllegalStateException failure = assertThrows(IllegalStateException.class, policy::possibleBiomes);
|
||||
|
||||
assertTrue(failure.getMessage().contains("example:missing"));
|
||||
}
|
||||
|
||||
private static ModdedBiomePolicy<BiomeToken, Object> policy(List<BiomeToken> entries,
|
||||
AtomicReference<Set<String>> configured) {
|
||||
ModdedBiomePolicy<BiomeToken, Object> policy = new ModdedBiomePolicy<>(new Access(entries));
|
||||
policy.bind(new ModdedBiomePolicy.RuntimeCallbacks(() -> null, () -> null, engine -> false,
|
||||
configured::get, engine -> Set.of(), () -> 0L));
|
||||
return policy;
|
||||
}
|
||||
|
||||
private record BiomeToken(String key) {
|
||||
}
|
||||
|
||||
private record Access(List<BiomeToken> entries) implements NativeBiomeSourceAccess<BiomeToken, Object>,
|
||||
NativeBiomeSourceAccess.RegistryView<BiomeToken> {
|
||||
@Override
|
||||
public RegistryView<BiomeToken> registry() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<BiomeToken> serializedBiomes() {
|
||||
throw new AssertionError("A loaded registry must not use serialized biomes");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeToken serializedNoise(int x, int y, int z, Object sampler) {
|
||||
throw new AssertionError("Listing biome holders must not sample terrain");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String holderKey(BiomeToken holder) {
|
||||
return holder.key();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super BiomeToken> consumer) {
|
||||
entries.forEach(consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeToken lookup(String key) {
|
||||
for (BiomeToken biome : entries) {
|
||||
if (biome.key().equals(key)) {
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -1,6 +1,7 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.iris.spi.PlatformBiome;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeBiomeRegistry;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeBiome;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
@@ -12,7 +13,7 @@ import static org.junit.Assert.assertTrue;
|
||||
public class ModdedBiomeWriterCacheTest {
|
||||
@Test
|
||||
public void unavailableServerFallsBackToBiomeIdZero() {
|
||||
ModdedBiomeWriter writer = new ModdedBiomeWriter(() -> null);
|
||||
ModdedBiomeWriter writer = new ModdedBiomeWriter(new NativeBiomeRegistry(() -> null, "minecraft:plains"));
|
||||
|
||||
assertEquals(0, writer.biomeIdFor("minecraft:plains"));
|
||||
assertEquals(0, writer.biomeIdFor("minecraft:plains"));
|
||||
@@ -20,10 +21,10 @@ public class ModdedBiomeWriterCacheTest {
|
||||
|
||||
@Test
|
||||
public void unavailableServerYieldsAnEmptyMutableBiomeList() {
|
||||
ModdedBiomeWriter writer = new ModdedBiomeWriter(() -> null);
|
||||
ModdedBiomeWriter writer = new ModdedBiomeWriter(new NativeBiomeRegistry(() -> null, "minecraft:plains"));
|
||||
|
||||
List<PlatformBiome> first = writer.allBiomes();
|
||||
List<PlatformBiome> second = writer.allBiomes();
|
||||
List<NativeBiome> first = writer.allBiomes();
|
||||
List<NativeBiome> second = writer.allBiomes();
|
||||
|
||||
assertTrue(first.isEmpty());
|
||||
assertNotSame("callers must never share the writer cache instance", first, second);
|
||||
|
||||
+13
-3
@@ -19,23 +19,33 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedBlockState;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.StairBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.junit.Test;
|
||||
import org.junit.BeforeClass;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedBlockBreakHandlerTest {
|
||||
@BeforeClass
|
||||
public static void bootstrapMinecraftRegistries() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exactMatchingIncludesPropertiesWhileTypeMatchingDoesNot() {
|
||||
BlockState north = Blocks.OAK_STAIRS.defaultBlockState().setValue(StairBlock.FACING, Direction.NORTH);
|
||||
BlockState east = Blocks.OAK_STAIRS.defaultBlockState().setValue(StairBlock.FACING, Direction.EAST);
|
||||
ModdedBlockState north = ModdedBlockState.of(Blocks.OAK_STAIRS.defaultBlockState().setValue(StairBlock.FACING, Direction.NORTH), null);
|
||||
ModdedBlockState east = ModdedBlockState.of(Blocks.OAK_STAIRS.defaultBlockState().setValue(StairBlock.FACING, Direction.EAST), null);
|
||||
|
||||
assertTrue(ModdedBlockBreakHandler.matchesState(north, north, true));
|
||||
assertFalse(ModdedBlockBreakHandler.matchesState(north, east, true));
|
||||
assertTrue(ModdedBlockBreakHandler.matchesState(north, east, false));
|
||||
assertFalse(ModdedBlockBreakHandler.matchesState(north, Blocks.COBBLESTONE.defaultBlockState(), false));
|
||||
assertFalse(ModdedBlockBreakHandler.matchesState(north, ModdedBlockState.of(Blocks.COBBLESTONE.defaultBlockState(), null), false));
|
||||
}
|
||||
}
|
||||
+21
-19
@@ -1,8 +1,10 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeBlockProperties;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedBlockState;
|
||||
import art.arcane.iris.generation.decoration.DecoratorPlatformHooks;
|
||||
import art.arcane.iris.generation.decoration.IrisSpeleothems;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
|
||||
import art.arcane.volmlib.util.hunk.Hunk;
|
||||
|
||||
import net.minecraft.SharedConstants;
|
||||
@@ -35,38 +37,38 @@ public class ModdedBlockResolutionContractTest {
|
||||
|
||||
@Test
|
||||
public void getOrNullReturnsNullForUnknownKey() {
|
||||
assertNull(ModdedBlockResolution.getOrNull(UNKNOWN));
|
||||
assertNull(ModdedBlockResolution.getOrNull(UNKNOWN, true));
|
||||
assertNull(ModdedBlockResolution.BLOCKS.getOrNull(UNKNOWN));
|
||||
assertNull(ModdedBlockResolution.BLOCKS.getOrNull(UNKNOWN, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFallsBackToAirForUnknownKey() {
|
||||
ModdedBlockState state = ModdedBlockResolution.get(UNKNOWN);
|
||||
ModdedBlockState state = ModdedBlockResolution.BLOCKS.get(UNKNOWN);
|
||||
assertNotNull(state);
|
||||
assertEquals(Blocks.AIR, state.handle().getBlock());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOrNullResolvesKnownKeyWithProperties() {
|
||||
ModdedBlockState state = ModdedBlockResolution.getOrNull("minecraft:oak_log[axis=x]", true);
|
||||
ModdedBlockState state = ModdedBlockResolution.BLOCKS.getOrNull("minecraft:oak_log[axis=x]", true);
|
||||
assertNotNull(state);
|
||||
assertEquals(Blocks.OAK_LOG, state.handle().getBlock());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unknownPropertyFallsBackToDefaultState() {
|
||||
ModdedBlockState state = ModdedBlockResolution.getOrNull("minecraft:oak_log[not_a_property=x]", true);
|
||||
ModdedBlockState state = ModdedBlockResolution.BLOCKS.getOrNull("minecraft:oak_log[not_a_property=x]", true);
|
||||
assertNotNull(state);
|
||||
assertEquals(Blocks.OAK_LOG, state.handle().getBlock());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cactusPlacementRequiresNativeCactusSupport() {
|
||||
assertTrue(ModdedBlockResolution.canPlaceOnto(Blocks.CACTUS, Blocks.CACTUS));
|
||||
assertTrue(ModdedBlockResolution.canPlaceOnto(Blocks.CACTUS, Blocks.SAND));
|
||||
assertTrue(ModdedBlockResolution.canPlaceOnto(Blocks.CACTUS, Blocks.RED_SAND));
|
||||
assertFalse(ModdedBlockResolution.canPlaceOnto(Blocks.CACTUS, Blocks.STONE));
|
||||
assertTrue(ModdedBlockResolution.isDecorant(Blocks.CACTUS.defaultBlockState()));
|
||||
assertTrue(NativeBlockProperties.canPlaceOnto(Blocks.CACTUS, Blocks.CACTUS));
|
||||
assertTrue(NativeBlockProperties.canPlaceOnto(Blocks.CACTUS, Blocks.SAND));
|
||||
assertTrue(NativeBlockProperties.canPlaceOnto(Blocks.CACTUS, Blocks.RED_SAND));
|
||||
assertFalse(NativeBlockProperties.canPlaceOnto(Blocks.CACTUS, Blocks.STONE));
|
||||
assertTrue(NativeBlockProperties.isDecorant(Blocks.CACTUS.defaultBlockState()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -74,11 +76,11 @@ public class ModdedBlockResolutionContractTest {
|
||||
for (Block block : new Block[]{Blocks.SUGAR_CANE, Blocks.GRASS_BLOCK, Blocks.DIRT, Blocks.COARSE_DIRT,
|
||||
Blocks.PODZOL, Blocks.MYCELIUM, Blocks.ROOTED_DIRT, Blocks.MOSS_BLOCK, Blocks.PALE_MOSS_BLOCK,
|
||||
Blocks.MUD, Blocks.MUDDY_MANGROVE_ROOTS, Blocks.SAND, Blocks.RED_SAND, Blocks.SUSPICIOUS_SAND}) {
|
||||
assertTrue(block.toString(), ModdedBlockResolution.canPlaceOnto(Blocks.SUGAR_CANE, block));
|
||||
assertTrue(block.toString(), NativeBlockProperties.canPlaceOnto(Blocks.SUGAR_CANE, block));
|
||||
}
|
||||
for (Block block : new Block[]{Blocks.STONE, Blocks.GRAVEL, Blocks.CLAY, Blocks.DIRT_PATH,
|
||||
Blocks.FARMLAND, Blocks.AIR, Blocks.WATER}) {
|
||||
assertFalse(block.toString(), ModdedBlockResolution.canPlaceOnto(Blocks.SUGAR_CANE, block));
|
||||
assertFalse(block.toString(), NativeBlockProperties.canPlaceOnto(Blocks.SUGAR_CANE, block));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,11 +89,11 @@ public class ModdedBlockResolutionContractTest {
|
||||
for (Block block : new Block[]{Blocks.SULFUR_SPIKE, Blocks.POINTED_DRIPSTONE}) {
|
||||
for (SpeleothemThickness thickness : SpeleothemThickness.values()) {
|
||||
assertEquals(thickness == SpeleothemThickness.TIP,
|
||||
ModdedBlockResolution.isUpdatable(block.defaultBlockState()
|
||||
NativeBlockProperties.isUpdatable(block.defaultBlockState()
|
||||
.setValue(SpeleothemBlock.THICKNESS, thickness)));
|
||||
}
|
||||
}
|
||||
assertFalse(ModdedBlockResolution.isUpdatable(Blocks.STONE.defaultBlockState()));
|
||||
assertFalse(NativeBlockProperties.isUpdatable(Blocks.STONE.defaultBlockState()));
|
||||
}
|
||||
@Test
|
||||
public void nativeSpikesUseModdedSupportFaces() {
|
||||
@@ -100,14 +102,14 @@ public class ModdedBlockResolutionContractTest {
|
||||
try {
|
||||
for (String material : new String[]{"minecraft:sulfur_spike", "minecraft:pointed_dripstone"}) {
|
||||
for (boolean upward : new boolean[]{true, false}) {
|
||||
Hunk<PlatformBlockState> output = Hunk.newArrayHunk(1, 3, 1);
|
||||
PlatformBlockState spike = ModdedBlockResolution.get(material
|
||||
Hunk<NativeBlockState> output = Hunk.newArrayHunk(1, 3, 1);
|
||||
NativeBlockState spike = ModdedBlockResolution.BLOCKS.get(material
|
||||
+ "[vertical_direction=" + (upward ? "up" : "down") + ",thickness=tip]");
|
||||
int supportY = upward ? 0 : 2;
|
||||
output.set(0, 1, 0, spike);
|
||||
output.set(0, supportY, 0, ModdedBlockResolution.get("minecraft:stone_slab[type=top]"));
|
||||
output.set(0, supportY, 0, ModdedBlockResolution.BLOCKS.get("minecraft:stone_slab[type=top]"));
|
||||
assertEquals(upward, IrisSpeleothems.isSupported(spike, output, 0, 0, 1));
|
||||
output.set(0, supportY, 0, ModdedBlockResolution.get("minecraft:stone_slab[type=bottom]"));
|
||||
output.set(0, supportY, 0, ModdedBlockResolution.BLOCKS.get("minecraft:stone_slab[type=bottom]"));
|
||||
assertEquals(!upward, IrisSpeleothems.isSupported(spike, output, 0, 0, 1));
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -32,6 +32,7 @@ import static org.junit.Assert.assertTrue;
|
||||
*/
|
||||
public class ModdedClientPackageIsolationTest {
|
||||
private static final String CLIENT_MINECRAFT = "net/minecraft/client/";
|
||||
private static final String CLIENT_NATIVE = "art/arcane/volmlib/nativelib/minecraft26_2/client/";
|
||||
private static final String CLIENT_IRIS = "art/arcane/iris/client/";
|
||||
private static final List<String> GUARDED_PACKAGES = List.of(
|
||||
"art/arcane/iris/modded",
|
||||
@@ -56,6 +57,9 @@ public class ModdedClientPackageIsolationTest {
|
||||
if (bytecode.contains(CLIENT_MINECRAFT)) {
|
||||
violations.add(name + " -> " + CLIENT_MINECRAFT);
|
||||
}
|
||||
if (bytecode.contains(CLIENT_NATIVE)) {
|
||||
violations.add(name + " -> " + CLIENT_NATIVE);
|
||||
}
|
||||
if (bytecode.contains(CLIENT_IRIS)) {
|
||||
violations.add(name + " -> " + CLIENT_IRIS);
|
||||
}
|
||||
@@ -74,8 +78,8 @@ public class ModdedClientPackageIsolationTest {
|
||||
*/
|
||||
@Test
|
||||
public void scanDetectsClientReferencesInAKnownClientClass() throws IOException, URISyntaxException {
|
||||
Path visionScreen = classesRoot().resolve("art/arcane/iris/client/IrisVisionScreen.class");
|
||||
assertTrue("IrisVisionScreen.class missing from " + visionScreen, Files.isRegularFile(visionScreen));
|
||||
Path visionScreen = classesRoot().resolve("art/arcane/volmlib/nativelib/minecraft26_2/client/NativeClientScreen.class");
|
||||
assertTrue("NativeClientScreen.class missing from " + visionScreen, Files.isRegularFile(visionScreen));
|
||||
assertTrue("scan needle no longer matches a known client class",
|
||||
readAsLatin1(visionScreen).contains(CLIENT_MINECRAFT));
|
||||
}
|
||||
@@ -89,7 +93,7 @@ public class ModdedClientPackageIsolationTest {
|
||||
}
|
||||
|
||||
private static Path classesRoot() throws URISyntaxException {
|
||||
String anchor = "/art/arcane/iris/modded/ModdedMixinFlags.class";
|
||||
String anchor = "/art/arcane/iris/modded/ModdedMixinAudit.class";
|
||||
URL located = ModdedClientPackageIsolationTest.class.getResource(anchor);
|
||||
assertNotNull("compiled main classes are not on the test classpath as files", located);
|
||||
assertEquals("expected a directory classpath entry, got " + located, "file", located.getProtocol());
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeEntityLoot;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeWorld;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class ModdedDeathLootTest {
|
||||
@Test
|
||||
public void unboundEntityRetainsItsNativeBaseLoot() {
|
||||
NativeEntityLoot entity = mock(NativeEntityLoot.class);
|
||||
when(entity.world()).thenReturn(mock(NativeWorld.class));
|
||||
when(entity.tags()).thenReturn(Set.of("unrelated"));
|
||||
assertFalse(ModdedDeathLoot.replaceBaseLoot(entity));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedBindingStillSuppressesNativeBaseLoot() {
|
||||
NativeEntityLoot entity = mock(NativeEntityLoot.class);
|
||||
when(entity.world()).thenReturn(mock(NativeWorld.class));
|
||||
when(entity.tags()).thenReturn(Set.of("iris_loot|invalid"));
|
||||
assertTrue(ModdedDeathLoot.replaceBaseLoot(entity));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entityOutsideServerWorldRetainsNativeBaseLoot() {
|
||||
NativeEntityLoot entity = mock(NativeEntityLoot.class);
|
||||
assertFalse(ModdedDeathLoot.replaceBaseLoot(entity));
|
||||
assertFalse(ModdedDeathLoot.replaceBaseLoot(null));
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -1,12 +1,12 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedBlockState;
|
||||
import art.arcane.iris.modded.api.ModdedBlockData;
|
||||
import art.arcane.iris.modded.api.ModdedCustomContentRegistry;
|
||||
import art.arcane.iris.modded.api.ModdedDataProvider;
|
||||
import art.arcane.iris.modded.api.ModdedDataType;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.StairBlock;
|
||||
@@ -23,7 +23,7 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedDeferredBlockParityTest {
|
||||
private static final Identifier BLOCK_ID = Identifier.parse("iris_deferred_test:oak_stairs");
|
||||
private static final String BLOCK_ID = "iris_deferred_test:oak_stairs";
|
||||
|
||||
@BeforeClass
|
||||
public static void bootstrapMinecraftRegistries() {
|
||||
@@ -34,7 +34,7 @@ public class ModdedDeferredBlockParityTest {
|
||||
|
||||
@Test
|
||||
public void deferredProviderStateCarriesPlacementMetadataThroughMutation() {
|
||||
ModdedBlockState resolved = ModdedBlockResolution.getOrNull(
|
||||
ModdedBlockState resolved = ModdedBlockResolution.BLOCKS.getOrNull(
|
||||
"iris_deferred_test:oak_stairs[facing=north,half=bottom]");
|
||||
|
||||
assertNotNull(resolved);
|
||||
@@ -42,12 +42,12 @@ public class ModdedDeferredBlockParityTest {
|
||||
assertEquals("iris_deferred_test:oak_stairs[facing=north,half=bottom]", resolved.deferredPlacementKey());
|
||||
assertEquals(Blocks.OAK_STAIRS, resolved.handle().getBlock());
|
||||
|
||||
PlatformBlockState mutated = resolved.withProperty("facing", "west");
|
||||
NativeBlockState mutated = resolved.withProperty("facing", "west");
|
||||
assertTrue(mutated.isCustom());
|
||||
assertEquals(resolved.deferredPlacementKey(), mutated.deferredPlacementKey());
|
||||
assertEquals("west", ((ModdedBlockState) mutated).handle().getValue(StairBlock.FACING).getName());
|
||||
|
||||
PlatformBlockState base = mutated.placementBaseState();
|
||||
NativeBlockState base = mutated.placementBaseState();
|
||||
assertFalse(base.isCustom());
|
||||
assertEquals(Blocks.OAK_STAIRS, ((ModdedBlockState) base).handle().getBlock());
|
||||
}
|
||||
@@ -59,18 +59,18 @@ public class ModdedDeferredBlockParityTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Identifier> getTypes(ModdedDataType type) {
|
||||
public Collection<String> getTypes(ModdedDataType type) {
|
||||
return type == ModdedDataType.BLOCK ? List.of(BLOCK_ID) : List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidProvider(Identifier id, ModdedDataType type) {
|
||||
public boolean isValidProvider(String id, ModdedDataType type) {
|
||||
return type == ModdedDataType.BLOCK && BLOCK_ID.equals(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModdedBlockData getBlockData(Identifier blockId, Map<String, String> state) {
|
||||
return ModdedBlockData.deferred(Blocks.OAK_STAIRS.defaultBlockState());
|
||||
public ModdedBlockData getBlockData(String blockId, Map<String, String> state) {
|
||||
return ModdedBlockData.deferred(ModdedBlockState.of(Blocks.OAK_STAIRS.defaultBlockState(), null));
|
||||
}
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class ModdedDimensionManagerTeleportTest {
|
||||
@Test
|
||||
public void blockCoordinatesUseFloorAcrossZeroAndChunkBoundaries() {
|
||||
assertEquals(0, ModdedTeleportBounds.blockCoordinate(0.99D));
|
||||
assertEquals(-1, ModdedTeleportBounds.blockCoordinate(-0.01D));
|
||||
assertEquals(-17, ModdedTeleportBounds.blockCoordinate(-16.01D));
|
||||
assertEquals(16, ModdedTeleportBounds.blockCoordinate(16D));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void teleportYReservesSupportFeetAndHeadSpace() {
|
||||
assertEquals(-63, ModdedTeleportBounds.clampY(-64, 320, -100));
|
||||
assertEquals(318, ModdedTeleportBounds.clampY(-64, 320, 400));
|
||||
assertEquals(72, ModdedTeleportBounds.clampY(-64, 320, 72));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void teleportYRejectsWorldsWithoutThreeVerticalBlocks() {
|
||||
ModdedTeleportBounds.clampY(0, 2, 1);
|
||||
}
|
||||
}
|
||||
+6
-4
@@ -18,8 +18,10 @@
|
||||
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.iris.platform.bukkit.nms.datapack.DataVersion;
|
||||
import art.arcane.iris.platform.bukkit.nms.datapack.IDataFixer;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeWorldInspection.Dimension;
|
||||
|
||||
import art.arcane.iris.pack.datapack.DataVersion;
|
||||
import art.arcane.iris.pack.datapack.IDataFixer;
|
||||
import art.arcane.iris.generation.terrain.IrisDimension;
|
||||
import art.arcane.iris.generation.terrain.IrisDimensionRuntimeContract;
|
||||
import art.arcane.iris.generation.terrain.IrisDimensionTypeOptions;
|
||||
@@ -152,8 +154,8 @@ public class ModdedDimensionTypeParityTest {
|
||||
.ceiling(TRUE);
|
||||
IrisDimension dimension = dimension("runtime_contract", IrisEnvironment.CUSTOM,
|
||||
-128, 384, 384, options);
|
||||
WorldCheckDimensionContract.DimensionContract expected = WorldCheckDimensionContract.expectedDimensionContract(dimension);
|
||||
WorldCheckDimensionContract.DimensionContract fallback = new WorldCheckDimensionContract.DimensionContract(
|
||||
Dimension expected = WorldCheckDimensionContract.expectedDimensionContract(dimension);
|
||||
Dimension fallback = new Dimension(
|
||||
-256, 768, 512, 1D, 0F, true, false, false, 0);
|
||||
|
||||
assertTrue(WorldCheckDimensionContract.matchesDimensionContract(-128, 512, expected, expected));
|
||||
|
||||
+15
-6
@@ -1,6 +1,10 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeEntityBehavior;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.Before;
|
||||
import art.arcane.volmlib.nativelib.modded.EntityBehaviorTags;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -9,27 +13,32 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedEntityAwarenessTest {
|
||||
@Before
|
||||
public void configureEntityTags() {
|
||||
NativeEntityBehavior.bind(new EntityBehaviorTags("iris_non_persistent", "iris_unaware"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unawareConfigurationAddsThePartialAiTag() {
|
||||
Set<String> tags = new HashSet<>();
|
||||
|
||||
ModdedEntityAwareness.configureTags(tags, false);
|
||||
NativeEntityBehavior.configureAwarenessTags(tags, false);
|
||||
|
||||
assertFalse(ModdedEntityAwareness.isAware(tags));
|
||||
assertFalse(NativeEntityBehavior.isAware(tags));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void awareConfigurationRemovesThePartialAiTag() {
|
||||
Set<String> tags = new HashSet<>();
|
||||
ModdedEntityAwareness.configureTags(tags, false);
|
||||
NativeEntityBehavior.configureAwarenessTags(tags, false);
|
||||
|
||||
ModdedEntityAwareness.configureTags(tags, true);
|
||||
NativeEntityBehavior.configureAwarenessTags(tags, true);
|
||||
|
||||
assertTrue(ModdedEntityAwareness.isAware(tags));
|
||||
assertTrue(NativeEntityBehavior.isAware(tags));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mobsAreAwareWithoutAnIrisTag() {
|
||||
assertTrue(ModdedEntityAwareness.isAware(Set.of()));
|
||||
assertTrue(NativeEntityBehavior.isAware(Set.of()));
|
||||
}
|
||||
}
|
||||
+16
-7
@@ -1,6 +1,10 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeEntityBehavior;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.Before;
|
||||
import art.arcane.volmlib.nativelib.modded.EntityBehaviorTags;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -9,31 +13,36 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedEntityPersistenceTest {
|
||||
@Before
|
||||
public void configureEntityTags() {
|
||||
NativeEntityBehavior.bind(new EntityBehaviorTags("iris_non_persistent", "iris_unaware"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generatedNonPersistentEntityIsExcludedFromVanillaSaves() {
|
||||
Set<String> tags = new HashSet<>();
|
||||
|
||||
ModdedEntityPersistence.configureTags(tags, false);
|
||||
NativeEntityBehavior.configurePersistenceTags(tags, false);
|
||||
|
||||
assertFalse(ModdedEntityPersistence.shouldSave(tags, true));
|
||||
assertFalse(NativeEntityBehavior.shouldSave(tags, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void positivePersistenceRemovesTheSaveExclusion() {
|
||||
Set<String> tags = new HashSet<>();
|
||||
ModdedEntityPersistence.configureTags(tags, false);
|
||||
NativeEntityBehavior.configurePersistenceTags(tags, false);
|
||||
|
||||
ModdedEntityPersistence.configureTags(tags, true);
|
||||
NativeEntityBehavior.configurePersistenceTags(tags, true);
|
||||
|
||||
assertTrue(ModdedEntityPersistence.shouldSave(tags, true));
|
||||
assertTrue(NativeEntityBehavior.shouldSave(tags, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void interceptionNeverOverridesVanillaSaveRejection() {
|
||||
Set<String> tags = new HashSet<>();
|
||||
|
||||
ModdedEntityPersistence.configureTags(tags, true);
|
||||
NativeEntityBehavior.configurePersistenceTags(tags, true);
|
||||
|
||||
assertFalse(ModdedEntityPersistence.shouldSave(tags, false));
|
||||
assertFalse(NativeEntityBehavior.shouldSave(tags, false));
|
||||
}
|
||||
}
|
||||
+13
-6
@@ -1,5 +1,12 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeEntityRuntime;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedPlatformWorld;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeModdedLoader;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeEntitySpawns;
|
||||
|
||||
import art.arcane.iris.generation.runtime.Engine;
|
||||
import art.arcane.iris.world.entity.IrisEntity;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
@@ -46,7 +53,7 @@ public class ModdedEntitySpawnDifficultyTest {
|
||||
public void sharedPlatformSpawnReturnsFalseForPeacefulHostiles() {
|
||||
ServerLevel level = mock(ServerLevel.class);
|
||||
when(level.getDifficulty()).thenReturn(Difficulty.PEACEFUL);
|
||||
ModdedPlatform platform = new ModdedPlatform(mock(ModdedLoader.class));
|
||||
ModdedPlatform platform = new ModdedPlatform(mock(NativeModdedLoader.class));
|
||||
|
||||
assertFalse(platform.spawnEntity(new ModdedPlatformWorld(level), "minecraft:zombie", 0.5, 80, 0.5));
|
||||
|
||||
@@ -63,7 +70,7 @@ public class ModdedEntitySpawnDifficultyTest {
|
||||
when(chunks.getChunkNow(anyInt(), anyInt())).thenReturn(mock(LevelChunk.class));
|
||||
IrisEntity configured = new IrisEntity().setType("zombie").setSpawnEffectRiseOutOfGround(false);
|
||||
|
||||
assertNull(ModdedEntitySpawner.spawn(mock(Engine.class), configured, level, 0, 80, 0, new RNG(1L)));
|
||||
assertNull(ModdedEntitySpawner.spawn(mock(Engine.class), configured, new NativeEntityRuntime(level), 0, 80, 0, new RNG(1L)));
|
||||
|
||||
verify(level, never()).addFreshEntity(any(Entity.class));
|
||||
verify(level, never()).enabledFeatures();
|
||||
@@ -80,7 +87,7 @@ public class ModdedEntitySpawnDifficultyTest {
|
||||
continue;
|
||||
}
|
||||
EntityType<?> type = spy(registered);
|
||||
assertNull(ModdedEntitySpawner.spawnNative(type, level, BlockPos.ZERO, EntitySpawnReason.NATURAL));
|
||||
assertNull(NativeEntitySpawns.spawn(type, level, BlockPos.ZERO, EntitySpawnReason.NATURAL));
|
||||
verify(type, never()).spawn(level, BlockPos.ZERO, EntitySpawnReason.NATURAL);
|
||||
rejected++;
|
||||
}
|
||||
@@ -98,7 +105,7 @@ public class ModdedEntitySpawnDifficultyTest {
|
||||
EntityType<?> type = spy(BuiltInRegistries.ENTITY_TYPE.getValue(Identifier.parse("minecraft:" + key)));
|
||||
doReturn(created).when(type).spawn(level, BlockPos.ZERO, EntitySpawnReason.NATURAL);
|
||||
|
||||
assertSame(key, created, ModdedEntitySpawner.spawnNative(type, level, BlockPos.ZERO, EntitySpawnReason.NATURAL));
|
||||
assertSame(key, created, NativeEntitySpawns.spawn(type, level, BlockPos.ZERO, EntitySpawnReason.NATURAL));
|
||||
verify(type).spawn(level, BlockPos.ZERO, EntitySpawnReason.NATURAL);
|
||||
}
|
||||
}
|
||||
@@ -113,7 +120,7 @@ public class ModdedEntitySpawnDifficultyTest {
|
||||
when(level.getDifficulty()).thenReturn(difficulty);
|
||||
doReturn(created).when(type).spawn(level, BlockPos.ZERO, EntitySpawnReason.NATURAL);
|
||||
|
||||
assertSame(created, ModdedEntitySpawner.spawnNative(type, level, BlockPos.ZERO, EntitySpawnReason.NATURAL));
|
||||
assertSame(created, NativeEntitySpawns.spawn(type, level, BlockPos.ZERO, EntitySpawnReason.NATURAL));
|
||||
verify(type).spawn(level, BlockPos.ZERO, EntitySpawnReason.NATURAL);
|
||||
}
|
||||
}
|
||||
@@ -127,6 +134,6 @@ public class ModdedEntitySpawnDifficultyTest {
|
||||
doThrow(failure).when(type).spawn(level, BlockPos.ZERO, EntitySpawnReason.NATURAL);
|
||||
|
||||
assertSame(failure, assertThrows(IllegalStateException.class,
|
||||
() -> ModdedEntitySpawner.spawnNative(type, level, BlockPos.ZERO, EntitySpawnReason.NATURAL)));
|
||||
() -> NativeEntitySpawns.spawn(type, level, BlockPos.ZERO, EntitySpawnReason.NATURAL)));
|
||||
}
|
||||
}
|
||||
+18
-16
@@ -1,5 +1,7 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeEntityRuntime;
|
||||
|
||||
import art.arcane.iris.world.entity.IrisEffect;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
@@ -22,9 +24,9 @@ public class ModdedEntitySpawnerParityTest {
|
||||
public void collisionCheckUsesPaperInclusiveIntegerDimensions() {
|
||||
Set<BlockPos> checked = new HashSet<>();
|
||||
|
||||
boolean clear = ModdedEntitySpawner.isAreaClearForSpawn(
|
||||
10, 64, 20, 0.6F, 1.95F, position -> {
|
||||
checked.add(position);
|
||||
boolean clear = NativeEntityRuntime.isAreaClearForSpawn(
|
||||
10, 64, 20, 0.6F, 1.95F, (x, y, z) -> {
|
||||
checked.add(new BlockPos(x, y, z));
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -35,8 +37,8 @@ public class ModdedEntitySpawnerParityTest {
|
||||
@Test
|
||||
public void collisionCheckCoversWideEntityVolumeAndRejectsOneBlockedCell() {
|
||||
AtomicInteger checked = new AtomicInteger();
|
||||
boolean fullyClear = ModdedEntitySpawner.isAreaClearForSpawn(
|
||||
0, 10, 0, 4F, 3.2F, position -> {
|
||||
boolean fullyClear = NativeEntityRuntime.isAreaClearForSpawn(
|
||||
0, 10, 0, 4F, 3.2F, (x, y, z) -> {
|
||||
checked.incrementAndGet();
|
||||
return true;
|
||||
});
|
||||
@@ -46,8 +48,8 @@ public class ModdedEntitySpawnerParityTest {
|
||||
|
||||
BlockPos obstruction = new BlockPos(2, 12, -2);
|
||||
|
||||
boolean clear = ModdedEntitySpawner.isAreaClearForSpawn(
|
||||
0, 10, 0, 4F, 3.2F, position -> !position.equals(obstruction));
|
||||
boolean clear = NativeEntityRuntime.isAreaClearForSpawn(
|
||||
0, 10, 0, 4F, 3.2F, (x, y, z) -> !new BlockPos(x, y, z).equals(obstruction));
|
||||
|
||||
assertFalse(clear);
|
||||
}
|
||||
@@ -61,19 +63,19 @@ public class ModdedEntitySpawnerParityTest {
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(ModdedEntitySpawner.allNeighborChunksLoaded(5, -2,
|
||||
assertTrue(NativeEntityRuntime.allNeighborChunksLoaded(5, -2,
|
||||
(x, z) -> loaded.contains(pack(x, z))));
|
||||
|
||||
loaded.remove(pack(4, -3));
|
||||
|
||||
assertFalse(ModdedEntitySpawner.allNeighborChunksLoaded(5, -2,
|
||||
assertFalse(NativeEntityRuntime.allNeighborChunksLoaded(5, -2,
|
||||
(x, z) -> loaded.contains(pack(x, z))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onlyAiFalseUsesVanillaNoAi() {
|
||||
assertFalse(ModdedEntitySpawner.shouldDisableAi(true));
|
||||
assertTrue(ModdedEntitySpawner.shouldDisableAi(false));
|
||||
assertFalse(NativeEntityRuntime.shouldDisableAi(true));
|
||||
assertTrue(NativeEntityRuntime.shouldDisableAi(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -137,16 +139,16 @@ public class ModdedEntitySpawnerParityTest {
|
||||
|
||||
assertEquals(47, expected.size());
|
||||
for (Map.Entry<String, EntitySpawnReason> entry : expected.entrySet()) {
|
||||
assertEquals(entry.getKey(), entry.getValue(), ModdedEntitySpawner.reasonFor(entry.getKey()));
|
||||
assertEquals(entry.getKey(), entry.getValue(), ModdedEntitySpawner.reasonFor(entry.getKey().toLowerCase()));
|
||||
assertEquals(entry.getKey(), entry.getValue(), NativeEntityRuntime.reasonFor(entry.getKey()));
|
||||
assertEquals(entry.getKey(), entry.getValue(), NativeEntityRuntime.reasonFor(entry.getKey().toLowerCase()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidConfiguredSpawnReasonIntentionallyDefaultsToNatural() {
|
||||
assertEquals(EntitySpawnReason.NATURAL, ModdedEntitySpawner.reasonFor(null));
|
||||
assertEquals(EntitySpawnReason.NATURAL, ModdedEntitySpawner.reasonFor(""));
|
||||
assertEquals(EntitySpawnReason.NATURAL, ModdedEntitySpawner.reasonFor("not_a_spawn_reason"));
|
||||
assertEquals(EntitySpawnReason.NATURAL, NativeEntityRuntime.reasonFor(null));
|
||||
assertEquals(EntitySpawnReason.NATURAL, NativeEntityRuntime.reasonFor(""));
|
||||
assertEquals(EntitySpawnReason.NATURAL, NativeEntityRuntime.reasonFor("not_a_spawn_reason"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.util.collection.KSet;
|
||||
import art.arcane.volmlib.util.json.JSONObject;
|
||||
import art.arcane.iris.platform.bukkit.nms.datapack.v1217.DataFixerV1217;
|
||||
import art.arcane.iris.pack.datapack.v1217.DataFixerV1217;
|
||||
import art.arcane.iris.world.history.GenerationEpochContractFactory;
|
||||
import art.arcane.iris.world.history.GenerationRegistryContract;
|
||||
import art.arcane.iris.world.history.GenerationRegistryContractFactory;
|
||||
|
||||
+63
-29
@@ -1,11 +1,17 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeModdedServer;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeModdedChunkGenerator;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeWorld;
|
||||
import java.lang.reflect.Field;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import org.junit.Test;
|
||||
import org.junit.BeforeClass;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -20,67 +26,95 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class ModdedGenerationBootstrapBindingTest {
|
||||
@BeforeClass
|
||||
public static void bootstrap() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishedLevelRequiresCurrentGeneratorIdentity() {
|
||||
IrisModdedChunkGenerator generator = mock(IrisModdedChunkGenerator.class, CALLS_REAL_METHODS);
|
||||
MinecraftServer server = mock(MinecraftServer.class);
|
||||
ServerLevel level = mock(ServerLevel.class);
|
||||
IrisModdedChunkGenerator generator = generator();
|
||||
NativeModdedServer server = mock(NativeModdedServer.class);
|
||||
NativeWorld level = world();
|
||||
ServerChunkCache chunkSource = mock(ServerChunkCache.class);
|
||||
when(server.getLevel(Level.OVERWORLD)).thenReturn(level);
|
||||
when(level.dimension()).thenReturn(Level.OVERWORLD);
|
||||
when(level.getChunkSource()).thenReturn(chunkSource);
|
||||
when(chunkSource.getGenerator()).thenReturn(generator);
|
||||
when(server.world("minecraft:overworld")).thenReturn(level);
|
||||
when(level.name()).thenReturn("minecraft:overworld");
|
||||
when(((ServerLevel) level.nativeHandle()).getChunkSource()).thenReturn(chunkSource);
|
||||
ChunkGenerator nativeGenerator = (ChunkGenerator) generator.nativeGenerator();
|
||||
when(chunkSource.getGenerator()).thenReturn(nativeGenerator);
|
||||
|
||||
assertSame(level, generator.requirePublishedLevel(server, Level.OVERWORLD));
|
||||
assertSame(level, generator.requirePublishedLevel(server, "minecraft:overworld"));
|
||||
|
||||
ChunkGenerator otherGenerator = mock(ChunkGenerator.class);
|
||||
when(chunkSource.getGenerator()).thenReturn(otherGenerator);
|
||||
IllegalStateException mismatch = assertThrows(IllegalStateException.class,
|
||||
() -> generator.requirePublishedLevel(server, Level.OVERWORLD));
|
||||
() -> generator.requirePublishedLevel(server, "minecraft:overworld"));
|
||||
assertTrue(mismatch.getMessage().contains("does not use Iris generator"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishedLevelRejectsMissingServerAndWorld() {
|
||||
IrisModdedChunkGenerator generator = mock(IrisModdedChunkGenerator.class, CALLS_REAL_METHODS);
|
||||
IrisModdedChunkGenerator generator = generator();
|
||||
IllegalStateException missingServer = assertThrows(IllegalStateException.class,
|
||||
() -> generator.requirePublishedLevel(null, Level.OVERWORLD));
|
||||
() -> generator.requirePublishedLevel(null, "minecraft:overworld"));
|
||||
assertTrue(missingServer.getMessage().contains("server is unavailable"));
|
||||
|
||||
MinecraftServer server = mock(MinecraftServer.class);
|
||||
NativeModdedServer server = mock(NativeModdedServer.class);
|
||||
IllegalStateException missingWorld = assertThrows(IllegalStateException.class,
|
||||
() -> generator.requirePublishedLevel(server, Level.OVERWORLD));
|
||||
assertTrue(missingWorld.getMessage().contains("no published ServerLevel"));
|
||||
() -> generator.requirePublishedLevel(server, "minecraft:overworld"));
|
||||
assertTrue(missingWorld.getMessage().contains("no published NativeWorld"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void staleSnapshotResolvesOnlyCanonicalOverworldOwnedByGenerator() {
|
||||
IrisModdedChunkGenerator generator = mock(IrisModdedChunkGenerator.class, CALLS_REAL_METHODS);
|
||||
MinecraftServer server = mock(MinecraftServer.class);
|
||||
ServerLevel overworld = mock(ServerLevel.class);
|
||||
IrisModdedChunkGenerator generator = generator();
|
||||
NativeModdedServer server = mock(NativeModdedServer.class);
|
||||
NativeWorld overworld = world();
|
||||
ServerChunkCache chunkSource = mock(ServerChunkCache.class);
|
||||
when(server.getLevel(Level.OVERWORLD)).thenReturn(overworld);
|
||||
when(overworld.getChunkSource()).thenReturn(chunkSource);
|
||||
when(chunkSource.getGenerator()).thenReturn(generator);
|
||||
when(server.overworld()).thenReturn(overworld);
|
||||
when(((ServerLevel) overworld.nativeHandle()).getChunkSource()).thenReturn(chunkSource);
|
||||
ChunkGenerator nativeGenerator = (ChunkGenerator) generator.nativeGenerator();
|
||||
when(chunkSource.getGenerator()).thenReturn(nativeGenerator);
|
||||
|
||||
assertSame(overworld, generator.resolveBoundLevel(server, List.of()));
|
||||
|
||||
ChunkGenerator otherGenerator = mock(ChunkGenerator.class);
|
||||
when(chunkSource.getGenerator()).thenReturn(otherGenerator);
|
||||
assertNull(generator.resolveBoundLevel(server, List.of()));
|
||||
verify(server, never()).getLevel(Level.NETHER);
|
||||
verify(server, never()).world("minecraft:the_nether");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dynamicLevelStillResolvesFromSnapshotWithoutCanonicalLookup() {
|
||||
IrisModdedChunkGenerator generator = mock(IrisModdedChunkGenerator.class, CALLS_REAL_METHODS);
|
||||
MinecraftServer server = mock(MinecraftServer.class);
|
||||
ServerLevel dynamicLevel = mock(ServerLevel.class);
|
||||
IrisModdedChunkGenerator generator = generator();
|
||||
NativeModdedServer server = mock(NativeModdedServer.class);
|
||||
NativeWorld dynamicLevel = world();
|
||||
ServerChunkCache chunkSource = mock(ServerChunkCache.class);
|
||||
when(dynamicLevel.getChunkSource()).thenReturn(chunkSource);
|
||||
when(chunkSource.getGenerator()).thenReturn(generator);
|
||||
when(((ServerLevel) dynamicLevel.nativeHandle()).getChunkSource()).thenReturn(chunkSource);
|
||||
ChunkGenerator nativeGenerator = (ChunkGenerator) generator.nativeGenerator();
|
||||
when(chunkSource.getGenerator()).thenReturn(nativeGenerator);
|
||||
|
||||
assertSame(dynamicLevel, generator.resolveBoundLevel(server, List.of(dynamicLevel)));
|
||||
verify(server, never()).getLevel(Level.OVERWORLD);
|
||||
verify(server, never()).overworld();
|
||||
}
|
||||
|
||||
private static NativeWorld world() {
|
||||
NativeWorld world = mock(NativeWorld.class);
|
||||
when(world.nativeHandle()).thenReturn(mock(ServerLevel.class));
|
||||
return world;
|
||||
}
|
||||
|
||||
private static IrisModdedChunkGenerator generator() {
|
||||
IrisModdedChunkGenerator generator = mock(IrisModdedChunkGenerator.class, CALLS_REAL_METHODS);
|
||||
NativeModdedChunkGenerator<?, ?, ?> nativeGenerator = mock(NativeModdedChunkGenerator.class, CALLS_REAL_METHODS);
|
||||
try {
|
||||
Field field = IrisModdedChunkGenerator.class.getDeclaredField("nativeGenerator");
|
||||
field.setAccessible(true);
|
||||
field.set(generator, nativeGenerator);
|
||||
return generator;
|
||||
} catch (ReflectiveOperationException failure) {
|
||||
throw new AssertionError(failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeFeatureBiomeSource;
|
||||
|
||||
import art.arcane.iris.generation.runtime.Engine;
|
||||
import art.arcane.iris.generation.terrain.IrisDimension;
|
||||
import art.arcane.iris.structure.nativegen.IrisImportedFeatureControl;
|
||||
import org.junit.Test;
|
||||
import org.junit.BeforeClass;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class ModdedImportedFeatureStageTest {
|
||||
@BeforeClass
|
||||
public static void bootstrapMinecraftRegistries() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disabledFeaturesRecheckAfterPackRepointAndRuntimeEviction() {
|
||||
NativeFeatureBiomeSource source = mock(NativeFeatureBiomeSource.class);
|
||||
when(source.packGeneration()).thenReturn(1L);
|
||||
IrisImportedFeatureControl control = spy(new IrisImportedFeatureControl());
|
||||
IrisDimension dimension = new IrisDimension().setImportedFeatures(control);
|
||||
Engine engine = mock(Engine.class);
|
||||
when(engine.getDimension()).thenReturn(dimension);
|
||||
when(engine.getCacheID()).thenReturn(7);
|
||||
ModdedImportedFeatureStage stage = new ModdedImportedFeatureStage(source);
|
||||
|
||||
stage.prepare(engine);
|
||||
stage.prepare(engine);
|
||||
verify(control, times(1)).shouldGenerateFeatures();
|
||||
|
||||
when(source.packGeneration()).thenReturn(2L);
|
||||
stage.prepare(engine);
|
||||
verify(control, times(2)).shouldGenerateFeatures();
|
||||
|
||||
stage.evictRuntime(7);
|
||||
stage.prepare(engine);
|
||||
verify(control, times(3)).shouldGenerateFeatures();
|
||||
|
||||
stage.invalidate();
|
||||
stage.prepare(engine);
|
||||
verify(control, times(4)).shouldGenerateFeatures();
|
||||
verify(source, never()).orderedPossibleBiomes();
|
||||
assertFalse(stage.active());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void closingRuntimeDoesNotBuildFeatureTables() {
|
||||
NativeFeatureBiomeSource source = mock(NativeFeatureBiomeSource.class);
|
||||
Engine engine = mock(Engine.class);
|
||||
when(engine.isClosing()).thenReturn(true);
|
||||
ModdedImportedFeatureStage stage = new ModdedImportedFeatureStage(source);
|
||||
|
||||
stage.prepare(engine);
|
||||
stage.prepareWithoutWaiting(engine);
|
||||
|
||||
verify(source, never()).packGeneration();
|
||||
verify(engine, never()).getDimension();
|
||||
assertFalse(stage.active());
|
||||
}
|
||||
}
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedLevelDataAttachmentTest {
|
||||
@Test
|
||||
public void detectsAndInvokesHostLevelDataAttachment() {
|
||||
ModdedServerLevels.HostLevelDataAttachment attachment =
|
||||
ModdedServerLevels.HostLevelDataAttachment.detect(
|
||||
AttachedLevelData.class, RootData.class, DimensionKey.class);
|
||||
AttachedLevelData levelData = new AttachedLevelData();
|
||||
RootData rootData = new RootData();
|
||||
DimensionKey dimensionKey = new DimensionKey();
|
||||
|
||||
assertTrue(attachment.supported());
|
||||
attachment.attach(levelData, rootData, dimensionKey);
|
||||
assertSame(rootData, levelData.rootData);
|
||||
assertSame(dimensionKey, levelData.dimensionKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoresLevelDataWithoutAttachmentCapability() {
|
||||
ModdedServerLevels.HostLevelDataAttachment attachment =
|
||||
ModdedServerLevels.HostLevelDataAttachment.detect(
|
||||
StandardLevelData.class, RootData.class, DimensionKey.class);
|
||||
|
||||
assertFalse(attachment.supported());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propagatesHostAttachmentFailureWithoutReflectionWrapper() {
|
||||
ModdedServerLevels.HostLevelDataAttachment attachment =
|
||||
ModdedServerLevels.HostLevelDataAttachment.detect(
|
||||
FailingLevelData.class, RootData.class, DimensionKey.class);
|
||||
IllegalStateException failure = assertThrows(IllegalStateException.class,
|
||||
() -> attachment.attach(new FailingLevelData(), new RootData(), new DimensionKey()));
|
||||
|
||||
assertNull(failure.getCause());
|
||||
}
|
||||
|
||||
public static final class AttachedLevelData {
|
||||
private RootData rootData;
|
||||
private DimensionKey dimensionKey;
|
||||
|
||||
public void attach(RootData rootData, DimensionKey dimensionKey) {
|
||||
this.rootData = rootData;
|
||||
this.dimensionKey = dimensionKey;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class FailingLevelData {
|
||||
public void attach(RootData rootData, DimensionKey dimensionKey) {
|
||||
throw new IllegalStateException("attachment failed");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class StandardLevelData {
|
||||
}
|
||||
|
||||
public static final class RootData {
|
||||
}
|
||||
|
||||
public static final class DimensionKey {
|
||||
}
|
||||
}
|
||||
+10
-8
@@ -1,5 +1,7 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeContainerLoot;
|
||||
|
||||
import art.arcane.iris.structure.placement.LootResolver;
|
||||
import art.arcane.iris.world.loot.IrisLootMode;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
@@ -112,7 +114,7 @@ public class ModdedLootApplierTest {
|
||||
|
||||
@Test
|
||||
public void nativeKeyIsReturnedWhenTheLiveRegistryContainsIt() {
|
||||
ResourceKey<LootTable> key = ModdedLootApplier.resolveNativeKey("minecraft:chests/simple_dungeon", candidate -> true);
|
||||
ResourceKey<LootTable> key = NativeContainerLoot.resolveNativeKey("minecraft:chests/simple_dungeon", candidate -> true);
|
||||
|
||||
assertNotNull(key);
|
||||
assertEquals(Identifier.parse("minecraft:chests/simple_dungeon"), key.identifier());
|
||||
@@ -120,7 +122,7 @@ public class ModdedLootApplierTest {
|
||||
|
||||
@Test
|
||||
public void nativeKeyIsRejectedWhenTheLiveRegistryDoesNotContainIt() {
|
||||
ResourceKey<LootTable> key = ModdedLootApplier.resolveNativeKey("minecraft:chests/missing", candidate -> false);
|
||||
ResourceKey<LootTable> key = NativeContainerLoot.resolveNativeKey("minecraft:chests/missing", candidate -> false);
|
||||
|
||||
assertNull(key);
|
||||
}
|
||||
@@ -129,7 +131,7 @@ public class ModdedLootApplierTest {
|
||||
public void malformedNativeKeyIsRejectedBeforeRegistryLookup() {
|
||||
AtomicBoolean registryConsulted = new AtomicBoolean(false);
|
||||
|
||||
ResourceKey<LootTable> key = ModdedLootApplier.resolveNativeKey("not a valid identifier", candidate -> {
|
||||
ResourceKey<LootTable> key = NativeContainerLoot.resolveNativeKey("not a valid identifier", candidate -> {
|
||||
registryConsulted.set(true);
|
||||
return true;
|
||||
});
|
||||
@@ -142,7 +144,7 @@ public class ModdedLootApplierTest {
|
||||
public void nativeOnlyFillMarksTheContainerChanged() {
|
||||
TrackingContainer container = new TrackingContainer();
|
||||
|
||||
ModdedLootApplier.fillContainer(container, List.<ItemStack>of(), new RNG(17L));
|
||||
NativeContainerLoot.fillContainer(container, List.<ItemStack>of(), new RNG(17L), message -> {});
|
||||
|
||||
assertTrue(container.changed);
|
||||
}
|
||||
@@ -152,8 +154,8 @@ public class ModdedLootApplierTest {
|
||||
BlockPos leftPos = new BlockPos(0, 64, 0);
|
||||
BlockPos rightPos = new BlockPos(1, 64, 0);
|
||||
|
||||
assertTrue(ModdedLootApplier.isCanonicalPair(leftPos, rightPos));
|
||||
assertFalse(ModdedLootApplier.isCanonicalPair(rightPos, leftPos));
|
||||
assertTrue(NativeContainerLoot.isCanonicalPair(leftPos, rightPos));
|
||||
assertFalse(NativeContainerLoot.isCanonicalPair(rightPos, leftPos));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -165,8 +167,8 @@ public class ModdedLootApplierTest {
|
||||
RandomizableContainer empty = containerWithLootTable(null);
|
||||
RandomizableContainer nativeLoot = containerWithLootTable(key);
|
||||
|
||||
assertFalse(ModdedLootApplier.hasNativeLootTable(empty));
|
||||
assertTrue(ModdedLootApplier.hasNativeLootTable(nativeLoot));
|
||||
assertFalse(NativeContainerLoot.hasNativeLootTable(empty));
|
||||
assertTrue(NativeContainerLoot.hasNativeLootTable(nativeLoot));
|
||||
}
|
||||
|
||||
private RandomizableContainer containerWithLootTable(ResourceKey<LootTable> key) {
|
||||
|
||||
+4
-2
@@ -1,5 +1,7 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeModdedStructureStage;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@@ -58,7 +60,7 @@ public class ModdedNativeStructurePoiRegistrationTest {
|
||||
chunk.setBlockState(ordinaryPosition, Blocks.STONE.defaultBlockState(), 0);
|
||||
Map<BlockPos, BlockState> visited = new LinkedHashMap<>();
|
||||
|
||||
ModdedNativeStructureStage.visitExistingPois(
|
||||
NativeModdedStructureStage.visitExistingPois(
|
||||
chunk, (position, state) -> visited.put(position.immutable(), state));
|
||||
|
||||
assertEquals(poiState, visited.get(poiPosition));
|
||||
@@ -92,7 +94,7 @@ public class ModdedNativeStructurePoiRegistrationTest {
|
||||
Deque<Runnable> serverQueue = new ArrayDeque<>();
|
||||
AtomicInteger missingRemovals = new AtomicInteger();
|
||||
|
||||
ModdedNativeStructureStage.visitExistingPois(chunk,
|
||||
NativeModdedStructureStage.visitExistingPois(chunk,
|
||||
(poiPosition, state) -> queuePoiTransition(
|
||||
serverQueue, section, poiPosition,
|
||||
Blocks.AIR.defaultBlockState(), state, missingRemovals));
|
||||
|
||||
+6
-4
@@ -1,9 +1,11 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedNativeStructureWorldgenAccess;
|
||||
|
||||
import art.arcane.iris.structure.placement.IrisStructureTerrain;
|
||||
import art.arcane.iris.structure.placement.IrisStructureTerrainMode;
|
||||
import art.arcane.iris.nativegen.NativeStructurePostProcessor;
|
||||
import art.arcane.iris.nativegen.NativeStructureTerrainIntegrator;
|
||||
import art.arcane.volmlib.util.structure.StructureTerrainMode;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.terrain.NativeStructurePostProcessor;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.terrain.NativeStructureTerrainIntegrator;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@@ -84,7 +86,7 @@ public class ModdedNativeStructureWorldgenAccessTest {
|
||||
StructureStart start = new StructureStart(structure, generationCenter(), 0, new PiecesContainer(List.of(piece)));
|
||||
List<NativeStructureTerrainIntegrator.TerrainTarget> targets = List.of(
|
||||
new NativeStructureTerrainIntegrator.TerrainTarget("minecraft:village_plains", start,
|
||||
new IrisStructureTerrain().setMode(IrisStructureTerrainMode.FLATTEN)));
|
||||
new IrisStructureTerrain().setMode(StructureTerrainMode.FLATTEN)));
|
||||
BoundingBox area = new BoundingBox(generationCenter().getMinBlockX(), -64, generationCenter().getMinBlockZ(),
|
||||
generationCenter().getMaxBlockX(), 319, generationCenter().getMaxBlockZ());
|
||||
RecordingDelegate unbounded = new RecordingDelegate();
|
||||
|
||||
+14
-8
@@ -1,7 +1,12 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeModdedLoader;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeWorld;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeModdedServer;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedServerAccess;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedServerLevels;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
@@ -20,7 +25,7 @@ public class ModdedPlatformPathsTest {
|
||||
|
||||
private ModdedPlatform platform() {
|
||||
Path configDir = temporaryFolder.getRoot().toPath();
|
||||
return new ModdedPlatform(new ModdedLoader() {
|
||||
return new ModdedPlatform(new NativeModdedLoader() {
|
||||
@Override
|
||||
public String platformName() {
|
||||
return "test";
|
||||
@@ -37,20 +42,21 @@ public class ModdedPlatformPathsTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftServer currentServer() {
|
||||
public NativeModdedServer currentServer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateLevelCache(MinecraftServer server) {
|
||||
public ModdedServerAccess serverAccess() {
|
||||
return new ModdedServerLevels(server -> {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireDynamicLevelLoad(MinecraftServer server, ServerLevel level) {
|
||||
public void fireDynamicLevelLoad(NativeWorld level) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireDynamicLevelUnload(MinecraftServer server, ServerLevel level) {
|
||||
public void fireDynamicLevelUnload(NativeWorld level) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,12 +75,12 @@ public class ModdedPlatformPathsTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTreeFellerPermission(ServerPlayer player) {
|
||||
public boolean hasBlockBreakPermission(ServerPlayer player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTreeFellerBreak(ServerLevel level, ServerPlayer player, BlockPos position, BlockState state) {
|
||||
public boolean canBreakBlock(ServerLevel level, ServerPlayer player, BlockPos position, BlockState state) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
+16
-10
@@ -1,5 +1,11 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedPlatformWorld;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeProtocolPlayer;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeWorld;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeEntityRuntime;
|
||||
|
||||
import art.arcane.iris.configuration.IrisSettings;
|
||||
import art.arcane.iris.pack.loading.IrisData;
|
||||
import art.arcane.iris.generation.runtime.BiomeEnvironment;
|
||||
@@ -19,7 +25,7 @@ import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.junit.Test;
|
||||
import org.junit.BeforeClass;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
|
||||
import art.arcane.iris.generation.block.B;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
@@ -45,7 +51,7 @@ public class ModdedSavedBiomeConsumersTest {
|
||||
public static void initializeRuntimeTypes() throws Exception {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
PlatformBlockState air = mock(PlatformBlockState.class);
|
||||
NativeBlockState air = mock(NativeBlockState.class);
|
||||
try (MockedStatic<B> blocks = mockStatic(B.class)) {
|
||||
blocks.when(() -> B.getState("AIR")).thenReturn(air);
|
||||
Class.forName(EngineMantle.class.getName());
|
||||
@@ -78,10 +84,10 @@ public class ModdedSavedBiomeConsumersTest {
|
||||
try (MockedStatic<IrisSettings> configured = mockStatic(IrisSettings.class);
|
||||
MockedStatic<ModdedEntitySpawner> spawns = mockStatic(ModdedEntitySpawner.class)) {
|
||||
configured.when(IrisSettings::get).thenReturn(settings);
|
||||
spawns.when(() -> ModdedEntitySpawner.chunksSafe(level, 2, -1)).thenReturn(true);
|
||||
assertThrows(SavedBiomeUnavailableException.class, () -> manager.initialSpawnChunk(level, 2, -1));
|
||||
spawns.when(() -> ModdedEntitySpawner.chunksSafe(any(NativeEntityRuntime.class), eq(2), eq(-1))).thenReturn(true);
|
||||
assertThrows(SavedBiomeUnavailableException.class, () -> manager.initialSpawnChunk(new ModdedPlatformWorld(level), 2, -1));
|
||||
verify(chunk, never()).raiseFlagUnchecked(eq(ModdedWorldManager.INITIAL_SPAWN_COMPLETION_FLAG), any());
|
||||
assertTrue(manager.initialSpawnChunk(level, 2, -1));
|
||||
assertTrue(manager.initialSpawnChunk(new ModdedPlatformWorld(level), 2, -1));
|
||||
verify(chunk).raiseFlagUnchecked(eq(ModdedWorldManager.INITIAL_SPAWN_COMPLETION_FLAG), any());
|
||||
} finally {
|
||||
manager.close();
|
||||
@@ -105,10 +111,10 @@ public class ModdedSavedBiomeConsumersTest {
|
||||
IrisSettings settings = new IrisSettings();
|
||||
settings.getWorld().setEffectSystem(false);
|
||||
Class<?> stateType = Class.forName(ModdedEngineEffects.class.getName() + "$PlayerState");
|
||||
Constructor<?> constructor = stateType.getDeclaredConstructor(ServerPlayer.class);
|
||||
Constructor<?> constructor = stateType.getDeclaredConstructor(NativeProtocolPlayer.class);
|
||||
constructor.setAccessible(true);
|
||||
Object state = constructor.newInstance(player);
|
||||
Method tick = ModdedEngineEffects.class.getDeclaredMethod("tickPlayer", ServerLevel.class, stateType);
|
||||
Object state = constructor.newInstance(NativeProtocolPlayer.fromHandle(player));
|
||||
Method tick = ModdedEngineEffects.class.getDeclaredMethod("tickPlayer", NativeWorld.class, stateType);
|
||||
tick.setAccessible(true);
|
||||
Field selected = stateType.getDeclaredField("environment");
|
||||
selected.setAccessible(true);
|
||||
@@ -116,9 +122,9 @@ public class ModdedSavedBiomeConsumersTest {
|
||||
try (MockedStatic<IrisSettings> configured = mockStatic(IrisSettings.class)) {
|
||||
configured.when(IrisSettings::get).thenReturn(settings);
|
||||
ModdedEngineEffects effects = new ModdedEngineEffects(engine);
|
||||
tick.invoke(effects, level, state);
|
||||
tick.invoke(effects, new ModdedPlatformWorld(level), state);
|
||||
assertNull(selected.get(state));
|
||||
tick.invoke(effects, level, state);
|
||||
tick.invoke(effects, new ModdedPlatformWorld(level), state);
|
||||
assertSame(environment, selected.get(state));
|
||||
verify(engine, times(2)).getBiomeEnvironment(0, 64, 0);
|
||||
}
|
||||
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedServerLevelsTest {
|
||||
@Test
|
||||
public void detectsAndInvokesHostLevelPublicationPair() {
|
||||
ModdedServerLevels.HostLevelPublication publication =
|
||||
ModdedServerLevels.HostLevelPublication.detect(PublishingServer.class, PublishedLevel.class);
|
||||
PublishingServer server = new PublishingServer();
|
||||
PublishedLevel level = new PublishedLevel();
|
||||
|
||||
assertTrue(publication.supported());
|
||||
publication.add(server, level);
|
||||
assertSame(level, server.added);
|
||||
publication.remove(server, level);
|
||||
assertSame(level, server.removed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectsPartialHostLevelPublicationCapability() {
|
||||
ModdedServerLevels.HostLevelPublication publication =
|
||||
ModdedServerLevels.HostLevelPublication.detect(AddOnlyServer.class, PublishedLevel.class);
|
||||
|
||||
assertFalse(publication.supported());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propagatesHostPublicationFailureWithoutReflectionWrapper() {
|
||||
ModdedServerLevels.HostLevelPublication publication =
|
||||
ModdedServerLevels.HostLevelPublication.detect(FailingServer.class, PublishedLevel.class);
|
||||
IllegalStateException failure = assertThrows(IllegalStateException.class,
|
||||
() -> publication.add(new FailingServer(), new PublishedLevel()));
|
||||
|
||||
assertNull(failure.getCause());
|
||||
}
|
||||
|
||||
public static final class PublishingServer {
|
||||
private PublishedLevel added;
|
||||
private PublishedLevel removed;
|
||||
|
||||
public void addLevel(PublishedLevel level) {
|
||||
added = level;
|
||||
}
|
||||
|
||||
public void removeLevel(PublishedLevel level) {
|
||||
removed = level;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class AddOnlyServer {
|
||||
public void addLevel(PublishedLevel level) {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class FailingServer {
|
||||
public void addLevel(PublishedLevel level) {
|
||||
throw new IllegalStateException("publication failed");
|
||||
}
|
||||
|
||||
public void removeLevel(PublishedLevel level) {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class PublishedLevel {
|
||||
}
|
||||
}
|
||||
-128
@@ -1,128 +0,0 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedStructureHooksTest {
|
||||
@BeforeClass
|
||||
public static void bootstrapMinecraftRegistries() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void objectFeaturesMatchPaperGroups() {
|
||||
assertEquals("trees", ModdedStructureHooks.classifyFeature(Feature.TREE));
|
||||
assertEquals("fallen_trees", ModdedStructureHooks.classifyFeature(Feature.FALLEN_TREE));
|
||||
assertEquals("mushrooms", ModdedStructureHooks.classifyFeature(Feature.HUGE_BROWN_MUSHROOM));
|
||||
assertEquals("mushrooms", ModdedStructureHooks.classifyFeature(Feature.HUGE_RED_MUSHROOM));
|
||||
assertNull(ModdedStructureHooks.classifyFeature(Feature.ORE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureSpanGuardUsesInclusiveBoundingBoxDimensions() {
|
||||
BoundingBox box = new BoundingBox(-16, -64, 32, 15, 63, 47);
|
||||
|
||||
assertTrue(ModdedStructureHooks.isWithinSpan(box, 128));
|
||||
assertFalse(ModdedStructureHooks.isWithinSpan(box, 127));
|
||||
assertTrue(ModdedStructureHooks.isWithinSpan(box, 0));
|
||||
assertTrue(ModdedStructureHooks.isWithinSpan(box, -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chunkGridSizeCountsEveryChunkPlacementWouldLoad() {
|
||||
assertEquals(1, ModdedStructureHooks.chunkGridSize(new BoundingBox(0, 0, 0, 15, 15, 15)));
|
||||
assertEquals(4, ModdedStructureHooks.chunkGridSize(new BoundingBox(0, 0, 0, 16, 15, 16)));
|
||||
assertEquals(9, ModdedStructureHooks.chunkGridSize(new BoundingBox(-16, 0, -16, 16, 15, 16)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chunkGridSizeSaturatesInsteadOfOverflowing() {
|
||||
BoundingBox box = new BoundingBox(
|
||||
Integer.MIN_VALUE / 2, 0, Integer.MIN_VALUE / 2,
|
||||
Integer.MAX_VALUE / 2, 15, Integer.MAX_VALUE / 2);
|
||||
|
||||
assertEquals(Integer.MAX_VALUE, ModdedStructureHooks.chunkGridSize(box));
|
||||
assertTrue(ModdedStructureHooks.chunkGridSize(box) > ModdedStructureHooks.MAX_PLACEMENT_CHUNKS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structurePlacementReturnsPaperOrderedBounds() {
|
||||
BoundingBox box = new BoundingBox(-16, -64, 32, 15, 63, 47);
|
||||
|
||||
assertArrayEquals(new int[]{-16, -64, 32, 15, 63, 47}, ModdedStructureHooks.bounds(box));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void platformWorldMaximumHeightIsExclusive() {
|
||||
assertEquals(320, ModdedPlatformWorld.exclusiveMaxHeight(-64, 384));
|
||||
assertEquals(384, ModdedPlatformWorld.exclusiveMaxHeight(0, 384));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureRegistryHooksRejectUnavailableServer() {
|
||||
ModdedStructureHooks hooks = new ModdedStructureHooks(() -> null);
|
||||
|
||||
IllegalStateException structureKeys = assertThrows(
|
||||
IllegalStateException.class, hooks::structureKeys);
|
||||
IllegalStateException jigsawStructureKeys = assertThrows(
|
||||
IllegalStateException.class, hooks::jigsawStructureKeys);
|
||||
IllegalStateException templatePoolKeys = assertThrows(
|
||||
IllegalStateException.class, hooks::templatePoolKeys);
|
||||
IllegalStateException jigsawMetadata = assertThrows(
|
||||
IllegalStateException.class, () -> hooks.jigsawSourceMetadata("minecraft:village"));
|
||||
IllegalStateException templatePoolSpan = assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> hooks.templatePoolHorizontalSpan("minecraft:village/plains/town_centers"));
|
||||
IllegalStateException structureSetKeys = assertThrows(
|
||||
IllegalStateException.class, hooks::structureSetKeys);
|
||||
IllegalStateException structureBiomeKeys = assertThrows(
|
||||
IllegalStateException.class, () -> hooks.structureBiomeKeys("minecraft:village"));
|
||||
|
||||
assertTrue(structureKeys.getMessage().contains("before the Minecraft server is available"));
|
||||
assertTrue(jigsawStructureKeys.getMessage().contains("before the Minecraft server is available"));
|
||||
assertTrue(templatePoolKeys.getMessage().contains("before the Minecraft server is available"));
|
||||
assertTrue(jigsawMetadata.getMessage().contains("before the Minecraft server is available"));
|
||||
assertTrue(templatePoolSpan.getMessage().contains("before the Minecraft server is available"));
|
||||
assertTrue(structureSetKeys.getMessage().contains("before the Minecraft server is available"));
|
||||
assertTrue(structureBiomeKeys.getMessage().contains("before the Minecraft server is available"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureReachabilityHooksRejectUnavailableLevel() {
|
||||
ModdedStructureHooks hooks = new ModdedStructureHooks(() -> null);
|
||||
|
||||
IllegalStateException reachable = assertThrows(
|
||||
IllegalStateException.class, () -> hooks.reachableStructureKeys(null));
|
||||
IllegalStateException possibleBiomes = assertThrows(
|
||||
IllegalStateException.class, () -> hooks.possibleBiomeKeys(null));
|
||||
|
||||
assertTrue(reachable.getMessage().contains("without a bound modded ServerLevel"));
|
||||
assertTrue(possibleBiomes.getMessage().contains("without a bound modded ServerLevel"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureRegistryHooksPreserveServerSupplierFailure() {
|
||||
IllegalStateException cause = new IllegalStateException("server supplier failed");
|
||||
ModdedStructureHooks hooks = new ModdedStructureHooks(() -> {
|
||||
throw cause;
|
||||
});
|
||||
|
||||
IllegalStateException failure = assertThrows(
|
||||
IllegalStateException.class, hooks::structureKeys);
|
||||
|
||||
assertTrue(failure.getMessage().contains("access the Minecraft server"));
|
||||
assertEquals(cause, failure.getCause());
|
||||
}
|
||||
}
|
||||
+7
-5
@@ -1,5 +1,7 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeStructureSetFrequencyOverrides;
|
||||
|
||||
import art.arcane.iris.structure.nativegen.IrisImportedStructureControl;
|
||||
import art.arcane.iris.structure.placement.IrisStructureSetFrequencyOverride;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
@@ -55,7 +57,7 @@ public class ModdedStructureSetFrequencyOverridesTest {
|
||||
.setFrequencyOverrides(overrides);
|
||||
|
||||
ChunkGeneratorStructureState returned =
|
||||
ModdedStructureSetFrequencyOverrides.apply(state, control);
|
||||
NativeStructureSetFrequencyOverrides.apply(state, control);
|
||||
|
||||
assertSame(state, returned);
|
||||
List<Holder<StructureSet>> scaledSets = state.possibleStructureSets();
|
||||
@@ -80,7 +82,7 @@ public class ModdedStructureSetFrequencyOverridesTest {
|
||||
.setFrequencyOverrides(overrides);
|
||||
|
||||
List<Holder<StructureSet>> scaled =
|
||||
ModdedStructureSetFrequencyOverrides.scaleSets(List.of(custom), control);
|
||||
NativeStructureSetFrequencyOverrides.scaleSets(List.of(custom), control);
|
||||
|
||||
assertSame(custom, scaled.getFirst());
|
||||
}
|
||||
@@ -98,7 +100,7 @@ public class ModdedStructureSetFrequencyOverridesTest {
|
||||
IrisImportedStructureControl control = new IrisImportedStructureControl()
|
||||
.setFrequencyOverrides(overrides);
|
||||
|
||||
List<Holder<StructureSet>> scaled = ModdedStructureSetFrequencyOverrides.scaleSets(
|
||||
List<Holder<StructureSet>> scaled = NativeStructureSetFrequencyOverrides.scaleSets(
|
||||
List.of(first, second), control);
|
||||
|
||||
assertSame(first, scaled.get(0));
|
||||
@@ -118,7 +120,7 @@ public class ModdedStructureSetFrequencyOverridesTest {
|
||||
IrisImportedStructureControl control = new IrisImportedStructureControl()
|
||||
.setFrequencyOverrides(overrides);
|
||||
|
||||
List<Holder<StructureSet>> scaled = ModdedStructureSetFrequencyOverrides.scaleSets(
|
||||
List<Holder<StructureSet>> scaled = NativeStructureSetFrequencyOverrides.scaleSets(
|
||||
List.of(first, second), control);
|
||||
|
||||
assertEquals(31, ((RandomSpreadStructurePlacement)
|
||||
@@ -140,7 +142,7 @@ public class ModdedStructureSetFrequencyOverridesTest {
|
||||
.setFrequencyOverrides(overrides);
|
||||
|
||||
assertThrows(IllegalStateException.class, () ->
|
||||
ModdedStructureSetFrequencyOverrides.scaleSets(List.of(custom), control));
|
||||
NativeStructureSetFrequencyOverrides.scaleSets(List.of(custom), control));
|
||||
}
|
||||
|
||||
private static Holder<StructureSet> structureSet(
|
||||
|
||||
+2
-2
@@ -55,7 +55,7 @@ public class ModdedStructureTemplateCacheTest {
|
||||
@Test
|
||||
public void requiredCommonMixinConfigRegistersPaletteConcurrencyFix() throws Exception {
|
||||
InputStream resource = ModdedStructureTemplateCacheTest.class.getClassLoader()
|
||||
.getResourceAsStream("irisworldgen.entity.mixins.json");
|
||||
.getResourceAsStream("volmlib.entity.mixins.json");
|
||||
assertNotNull(resource);
|
||||
String config;
|
||||
try (InputStream input = resource) {
|
||||
@@ -63,7 +63,7 @@ public class ModdedStructureTemplateCacheTest {
|
||||
}
|
||||
assertTrue(config.contains("\"StructureTemplatePaletteConcurrencyMixin\""));
|
||||
assertNotNull(Class.forName(
|
||||
"art.arcane.iris.modded.mixin.StructureTemplatePaletteConcurrencyMixin",
|
||||
"art.arcane.volmlib.nativelib.minecraft26_2.modded.mixin.StructureTemplatePaletteConcurrencyMixin",
|
||||
false,
|
||||
ModdedStructureTemplateCacheTest.class.getClassLoader()));
|
||||
}
|
||||
|
||||
+6
-5
@@ -1,5 +1,6 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeTileData;
|
||||
import art.arcane.iris.generation.block.TileData;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import com.google.gson.Gson;
|
||||
@@ -53,15 +54,15 @@ public class ModdedTileDataIdentityTest {
|
||||
|
||||
ModdedTileData captured = ModdedTileData.capture("minecraft:player_head", snbt);
|
||||
|
||||
assertEquals(snbt, captured.snbt());
|
||||
assertEquals(snbt, captured.getProperties().get(ModdedTileData.NBT_PROPERTY));
|
||||
assertEquals(snbt, captured.nativeData().snbt());
|
||||
assertEquals(snbt, captured.getProperties().get(NativeTileData.NBT_PROPERTY));
|
||||
|
||||
// The Bukkit-readable map form is still written, and is still array-lossy - which is why the SNBT has to stay.
|
||||
assertTrue(captured.getProperties().get("profile") instanceof KMap);
|
||||
KMap<?, ?> profile = (KMap<?, ?>) captured.getProperties().get("profile");
|
||||
assertTrue(profile.get("id") instanceof List);
|
||||
|
||||
CompoundTag payload = captured.payload();
|
||||
CompoundTag payload = captured.nativeData().payload();
|
||||
assertNotNull(payload);
|
||||
Tag profileTag = payload.get("profile");
|
||||
assertTrue(profileTag instanceof CompoundTag);
|
||||
@@ -101,7 +102,7 @@ public class ModdedTileDataIdentityTest {
|
||||
|
||||
@Test
|
||||
public void legacyRecordHasNoBlockKey() {
|
||||
ModdedTileData legacy = new ModdedTileData(new byte[]{0, 1}, new KMap<>(), null, 0);
|
||||
ModdedTileData legacy = ModdedTileData.wrap(new NativeTileData(new byte[]{0, 1}, new KMap<>(), null, 0));
|
||||
assertNull(legacy.getMaterialKey());
|
||||
}
|
||||
|
||||
@@ -131,7 +132,7 @@ public class ModdedTileDataIdentityTest {
|
||||
out.writeUTF(blockKey);
|
||||
out.writeUTF(GSON.toJson(properties));
|
||||
}
|
||||
return new ModdedTileData(bytes.toByteArray(), properties, blockKey, -1);
|
||||
return ModdedTileData.wrap(new NativeTileData(bytes.toByteArray(), properties, blockKey, -1));
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
+21
-18
@@ -1,5 +1,7 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeTileReader;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedBlockState;
|
||||
import art.arcane.iris.generation.block.TileData;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import net.minecraft.SharedConstants;
|
||||
@@ -39,7 +41,8 @@ public class ModdedTileParityTest {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
registries = RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY);
|
||||
TileData.bindPlatformReader(new ModdedTileReader(() -> null));
|
||||
NativeTileReader nativeTileReader = new NativeTileReader(() -> null);
|
||||
TileData.bindPlatformReader(in -> ModdedTileData.wrap(nativeTileReader.read(in)));
|
||||
TileData.bindPlatformFactory(ModdedTileData::fromProperties);
|
||||
}
|
||||
|
||||
@@ -55,7 +58,7 @@ public class ModdedTileParityTest {
|
||||
});
|
||||
SignBlockEntity sign = new SignBlockEntity(BlockPos.ZERO, Blocks.OAK_SIGN.defaultBlockState());
|
||||
|
||||
sign.loadWithComponents(TagValueInput.create(ProblemReporter.DISCARDING, registries, tile.payload()));
|
||||
sign.loadWithComponents(TagValueInput.create(ProblemReporter.DISCARDING, registries, tile.nativeData().payload()));
|
||||
|
||||
assertEquals("Iris", sign.getFrontText().getMessage(0, false).getString());
|
||||
assertEquals("parity", sign.getBackText().getMessage(3, false).getString());
|
||||
@@ -70,7 +73,7 @@ public class ModdedTileParityTest {
|
||||
});
|
||||
SpawnerBlockEntity spawner = new SpawnerBlockEntity(BlockPos.ZERO, Blocks.SPAWNER.defaultBlockState());
|
||||
|
||||
spawner.loadWithComponents(TagValueInput.create(ProblemReporter.DISCARDING, registries, tile.payload()));
|
||||
spawner.loadWithComponents(TagValueInput.create(ProblemReporter.DISCARDING, registries, tile.nativeData().payload()));
|
||||
CompoundTag saved = spawner.saveWithoutMetadata(registries);
|
||||
|
||||
assertTrue(saved.toString().contains("minecraft:zombie"));
|
||||
@@ -84,7 +87,7 @@ public class ModdedTileParityTest {
|
||||
});
|
||||
SpawnerBlockEntity spawner = new SpawnerBlockEntity(BlockPos.ZERO, Blocks.SPAWNER.defaultBlockState());
|
||||
|
||||
spawner.loadWithComponents(TagValueInput.create(ProblemReporter.DISCARDING, registries, tile.payload()));
|
||||
spawner.loadWithComponents(TagValueInput.create(ProblemReporter.DISCARDING, registries, tile.nativeData().payload()));
|
||||
CompoundTag saved = spawner.saveWithoutMetadata(registries);
|
||||
|
||||
assertTrue(saved.toString().contains("minecraft:command_block_minecart"));
|
||||
@@ -98,7 +101,7 @@ public class ModdedTileParityTest {
|
||||
});
|
||||
SpawnerBlockEntity spawner = new SpawnerBlockEntity(BlockPos.ZERO, Blocks.SPAWNER.defaultBlockState());
|
||||
|
||||
spawner.loadWithComponents(TagValueInput.create(ProblemReporter.DISCARDING, registries, tile.payload()));
|
||||
spawner.loadWithComponents(TagValueInput.create(ProblemReporter.DISCARDING, registries, tile.nativeData().payload()));
|
||||
CompoundTag saved = spawner.saveWithoutMetadata(registries);
|
||||
|
||||
assertTrue(saved.toString().contains("minecraft:pig"));
|
||||
@@ -114,7 +117,7 @@ public class ModdedTileParityTest {
|
||||
});
|
||||
ChestBlockEntity chest = new ChestBlockEntity(BlockPos.ZERO, Blocks.CHEST.defaultBlockState());
|
||||
|
||||
chest.loadWithComponents(TagValueInput.create(ProblemReporter.DISCARDING, registries, tile.payload()));
|
||||
chest.loadWithComponents(TagValueInput.create(ProblemReporter.DISCARDING, registries, tile.nativeData().payload()));
|
||||
RandomizableContainer lootable = chest;
|
||||
|
||||
assertNotNull(lootable.getLootTable());
|
||||
@@ -132,35 +135,35 @@ public class ModdedTileParityTest {
|
||||
|
||||
assertEquals(
|
||||
BuiltInRegistries.BLOCK.getValue(Identifier.parse("minecraft:red_banner")),
|
||||
tile.adjustBlockState(BuiltInRegistries.BLOCK.getValue(Identifier.parse("minecraft:white_banner")).defaultBlockState()).getBlock());
|
||||
assertEquals(Blocks.BARREL, tile.adjustBlockState(Blocks.BARREL.defaultBlockState()).getBlock());
|
||||
tile.nativeData().adjustBlockState(BuiltInRegistries.BLOCK.getValue(Identifier.parse("minecraft:white_banner")).defaultBlockState()).getBlock());
|
||||
assertEquals(Blocks.BARREL, tile.nativeData().adjustBlockState(Blocks.BARREL.defaultBlockState()).getBlock());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paper26_2LegacyBannerFirstOrdinalIsSmallStripes() {
|
||||
assertEquals(
|
||||
Identifier.parse("minecraft:small_stripes"),
|
||||
ModdedTileReader.legacyBannerPatternKey(0));
|
||||
NativeTileReader.legacyBannerPatternKey(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paper26_2LegacyBannerMiddleOrdinalIsStripeLeft() {
|
||||
assertEquals(
|
||||
Identifier.parse("minecraft:stripe_left"),
|
||||
ModdedTileReader.legacyBannerPatternKey(21));
|
||||
NativeTileReader.legacyBannerPatternKey(21));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paper26_2LegacyBannerLastOrdinalIsHalfVerticalRight() {
|
||||
assertEquals(
|
||||
Identifier.parse("minecraft:half_vertical_right"),
|
||||
ModdedTileReader.legacyBannerPatternKey(42));
|
||||
NativeTileReader.legacyBannerPatternKey(42));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidLegacyBannerOrdinalFallsBackToBase() {
|
||||
assertEquals(Identifier.parse("minecraft:base"), ModdedTileReader.legacyBannerPatternKey(-1));
|
||||
assertEquals(Identifier.parse("minecraft:base"), ModdedTileReader.legacyBannerPatternKey(43));
|
||||
assertEquals(Identifier.parse("minecraft:base"), NativeTileReader.legacyBannerPatternKey(-1));
|
||||
assertEquals(Identifier.parse("minecraft:base"), NativeTileReader.legacyBannerPatternKey(43));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -173,13 +176,13 @@ public class ModdedTileParityTest {
|
||||
assertTrue(tile instanceof ModdedTileData);
|
||||
ChestBlockEntity chest = new ChestBlockEntity(BlockPos.ZERO, Blocks.CHEST.defaultBlockState());
|
||||
chest.loadWithComponents(TagValueInput.create(
|
||||
ProblemReporter.DISCARDING, registries, ((ModdedTileData) tile).payload()));
|
||||
ProblemReporter.DISCARDING, registries, ((ModdedTileData) tile).nativeData().payload()));
|
||||
|
||||
assertNotNull(chest.getLootTable());
|
||||
assertEquals("minecraft:chests/abandoned_mineshaft", chest.getLootTable().identifier().toString());
|
||||
assertEquals(9124L, chest.getLootTableSeed());
|
||||
assertTrue(((ModdedTileData) tile).isApplicable(Blocks.CHEST.defaultBlockState(), chest));
|
||||
assertFalse(((ModdedTileData) tile).isApplicable(
|
||||
assertTrue(((ModdedTileData) tile).nativeData().isApplicable(Blocks.CHEST.defaultBlockState(), chest));
|
||||
assertFalse(((ModdedTileData) tile).nativeData().isApplicable(
|
||||
Blocks.BARREL.defaultBlockState(),
|
||||
new BarrelBlockEntity(BlockPos.ZERO, Blocks.BARREL.defaultBlockState())));
|
||||
}
|
||||
@@ -197,8 +200,8 @@ public class ModdedTileParityTest {
|
||||
SignBlockEntity sign = new SignBlockEntity(BlockPos.ZERO, Blocks.OAK_SIGN.defaultBlockState());
|
||||
ChestBlockEntity chest = new ChestBlockEntity(BlockPos.ZERO, Blocks.CHEST.defaultBlockState());
|
||||
|
||||
assertTrue(tile.isApplicable(Blocks.OAK_SIGN.defaultBlockState(), sign));
|
||||
assertFalse(tile.isApplicable(Blocks.CHEST.defaultBlockState(), chest));
|
||||
assertTrue(tile.nativeData().isApplicable(Blocks.OAK_SIGN.defaultBlockState(), sign));
|
||||
assertFalse(tile.nativeData().isApplicable(Blocks.CHEST.defaultBlockState(), chest));
|
||||
}
|
||||
|
||||
private static ModdedTileData legacyTile(TileWriter writer) throws Exception {
|
||||
|
||||
+18
-14
@@ -1,5 +1,9 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedBlockState;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeEntityRuntime;
|
||||
|
||||
import art.arcane.iris.world.entity.IrisEntity;
|
||||
import art.arcane.iris.world.entity.IrisEntitySpawn;
|
||||
import art.arcane.iris.world.entity.IrisSpawnGroup;
|
||||
@@ -37,13 +41,13 @@ public class ModdedWaterEntitySpawnTest {
|
||||
ServerLevel level = mock(ServerLevel.class);
|
||||
IrisEntity entity = new IrisEntity().setType("tadpole").setSurface(IrisSurface.WATER);
|
||||
when(level.getBlockState(any(BlockPos.class))).thenReturn(Blocks.WATER.defaultBlockState());
|
||||
assertTrue(ModdedEntitySpawner.isAreaClearForSpawn(level, entity, 0, 78, 0));
|
||||
assertTrue(ModdedEntitySpawner.isAreaClearForSpawn(new NativeEntityRuntime(level), entity, 0, 78, 0));
|
||||
when(level.getBlockState(any(BlockPos.class))).thenReturn(Blocks.SEAGRASS.defaultBlockState());
|
||||
assertTrue(ModdedEntitySpawner.isAreaClearForSpawn(level, entity, 0, 78, 0));
|
||||
assertTrue(ModdedEntitySpawner.isAreaClearForSpawn(new NativeEntityRuntime(level), entity, 0, 78, 0));
|
||||
when(level.getBlockState(any(BlockPos.class))).thenReturn(Blocks.AIR.defaultBlockState());
|
||||
assertFalse(ModdedEntitySpawner.isAreaClearForSpawn(level, entity, 0, 79, 0));
|
||||
assertFalse(ModdedEntitySpawner.isAreaClearForSpawn(new NativeEntityRuntime(level), entity, 0, 79, 0));
|
||||
when(level.getBlockState(any(BlockPos.class))).thenReturn(Blocks.LAVA.defaultBlockState());
|
||||
assertFalse(ModdedEntitySpawner.isAreaClearForSpawn(level, entity, 0, 78, 0));
|
||||
assertFalse(ModdedEntitySpawner.isAreaClearForSpawn(new NativeEntityRuntime(level), entity, 0, 78, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -51,38 +55,38 @@ public class ModdedWaterEntitySpawnTest {
|
||||
ServerLevel level = mock(ServerLevel.class);
|
||||
IrisEntity entity = new IrisEntity().setType("tadpole").setSurface(IrisSurface.LAVA);
|
||||
when(level.getBlockState(any(BlockPos.class))).thenReturn(Blocks.LAVA.defaultBlockState());
|
||||
assertTrue(ModdedEntitySpawner.isAreaClearForSpawn(level, entity, 0, 78, 0));
|
||||
assertTrue(ModdedEntitySpawner.isAreaClearForSpawn(new NativeEntityRuntime(level), entity, 0, 78, 0));
|
||||
when(level.getBlockState(any(BlockPos.class))).thenReturn(Blocks.WATER.defaultBlockState());
|
||||
assertFalse(ModdedEntitySpawner.isAreaClearForSpawn(level, entity, 0, 78, 0));
|
||||
assertFalse(ModdedEntitySpawner.isAreaClearForSpawn(new NativeEntityRuntime(level), entity, 0, 78, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void waterloggedSolidBlocksStillObstructWaterSpawns() {
|
||||
assertTrue(ModdedWorldManager.matchesSurface(IrisSurface.WATER,
|
||||
Blocks.SEA_PICKLE.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, true)));
|
||||
ModdedBlockState.of(Blocks.SEA_PICKLE.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, true), null)));
|
||||
assertFalse(ModdedWorldManager.matchesSurface(IrisSurface.WATER,
|
||||
Blocks.OAK_FENCE.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, true)));
|
||||
ModdedBlockState.of(Blocks.OAK_FENCE.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, true), null)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fractionalFluidVolumeIncludesHorizontalEdgesAndCenteredHeight() {
|
||||
Set<BlockPos> checked = new HashSet<>();
|
||||
assertTrue(ModdedEntitySpawner.isFluidAreaClearForSpawn(-1, 78, -1, 1.3F, 0.8F, position -> {
|
||||
checked.add(position);
|
||||
assertTrue(NativeEntityRuntime.isFluidAreaClearForSpawn(-1, 78, -1, 1.3F, 0.8F, (x, y, z) -> {
|
||||
checked.add(new BlockPos(x, y, z));
|
||||
return true;
|
||||
}));
|
||||
assertEquals(18, checked.size());
|
||||
assertTrue(checked.contains(new BlockPos(-2, 79, -2)));
|
||||
assertTrue(checked.contains(new BlockPos(0, 78, 0)));
|
||||
assertFalse(ModdedEntitySpawner.isFluidAreaClearForSpawn(-1, 78, -1, 1.3F, 0.8F,
|
||||
position -> !position.equals(new BlockPos(-2, 79, -2))));
|
||||
assertFalse(NativeEntityRuntime.isFluidAreaClearForSpawn(-1, 78, -1, 1.3F, 0.8F,
|
||||
(x, y, z) -> !new BlockPos(x, y, z).equals(new BlockPos(-2, 79, -2))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exactUpperBoundaryDoesNotRequireWaterOutsideTheBody() {
|
||||
Set<BlockPos> checked = new HashSet<>();
|
||||
assertTrue(ModdedEntitySpawner.isFluidAreaClearForSpawn(0, 78, 0, 1F, 0.5F, position -> {
|
||||
checked.add(position);
|
||||
assertTrue(NativeEntityRuntime.isFluidAreaClearForSpawn(0, 78, 0, 1F, 0.5F, (x, y, z) -> {
|
||||
checked.add(new BlockPos(x, y, z));
|
||||
return true;
|
||||
}));
|
||||
assertEquals(Set.of(new BlockPos(0, 78, 0)), checked);
|
||||
|
||||
+5
-3
@@ -1,5 +1,7 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeStructureInspection;
|
||||
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||
@@ -126,7 +128,7 @@ public class ModdedWorldCheckTest {
|
||||
public void smallStructureFootprintIncludesEveryChunk() {
|
||||
BoundingBox bounds = new BoundingBox(-16, -20, -16, 31, 120, 31);
|
||||
|
||||
List<ChunkPos> chunks = WorldCheckStructureAudit.boundedFootprintChunks(bounds, ChunkPos.ZERO, 96);
|
||||
List<ChunkPos> chunks = NativeStructureInspection.boundedFootprintChunks(bounds, ChunkPos.ZERO, 96);
|
||||
|
||||
assertEquals(9, chunks.size());
|
||||
assertTrue(chunks.contains(new ChunkPos(-1, -1)));
|
||||
@@ -137,7 +139,7 @@ public class ModdedWorldCheckTest {
|
||||
public void largeStructureFootprintIsBoundedAndSamplesEdges() {
|
||||
BoundingBox bounds = new BoundingBox(-512, -64, -512, 511, 300, 511);
|
||||
|
||||
List<ChunkPos> chunks = WorldCheckStructureAudit.boundedFootprintChunks(bounds, ChunkPos.ZERO, 20);
|
||||
List<ChunkPos> chunks = NativeStructureInspection.boundedFootprintChunks(bounds, ChunkPos.ZERO, 20);
|
||||
|
||||
assertTrue(chunks.size() <= 20);
|
||||
assertTrue(chunks.size() >= 16);
|
||||
@@ -267,6 +269,6 @@ public class ModdedWorldCheckTest {
|
||||
|
||||
private static boolean characteristic(String structureLabel, String structureKey, String blockKey) {
|
||||
return WorldCheckMaterials.isCharacteristicMaterial(structureLabel,
|
||||
Identifier.parse(structureKey), Identifier.parse(blockKey));
|
||||
structureKey, blockKey);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeCommandExecutor;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeModdedServer;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class NativeCommandExecutorTest {
|
||||
@BeforeClass
|
||||
public static void bootstrapMinecraftRegistries() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dispatchesConsoleSourceWithLeadingSlashRemoved() {
|
||||
MinecraftServer server = mock(MinecraftServer.class);
|
||||
Commands commands = mock(Commands.class);
|
||||
CommandSourceStack source = mock(CommandSourceStack.class);
|
||||
when(server.getCommands()).thenReturn(commands);
|
||||
when(server.createCommandSourceStack()).thenReturn(source);
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
|
||||
assertTrue(NativeCommandExecutor.dispatch(NativeModdedServer.fromHandle(server), "/say terrain", errors::add));
|
||||
|
||||
verify(commands).performPrefixedCommand(source, "say terrain");
|
||||
assertTrue(errors.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failedDispatchPreservesFailureForTheCaller() {
|
||||
MinecraftServer server = mock(MinecraftServer.class);
|
||||
Commands commands = mock(Commands.class);
|
||||
CommandSourceStack source = mock(CommandSourceStack.class);
|
||||
when(server.getCommands()).thenReturn(commands);
|
||||
when(server.createCommandSourceStack()).thenReturn(source);
|
||||
IllegalStateException failure = new IllegalStateException("dispatch failed");
|
||||
doThrow(failure).when(commands).performPrefixedCommand(source, "say terrain");
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
|
||||
assertFalse(NativeCommandExecutor.dispatch(NativeModdedServer.fromHandle(server), "say terrain", errors::add));
|
||||
|
||||
assertEquals(List.of(failure), errors);
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.iris.world.loot.IrisLoot;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeItemContext;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeItemStack;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeItemTranslator;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.component.DataComponentMap;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class NativeItemTranslatorTest {
|
||||
@BeforeClass
|
||||
public static void bootstrapMinecraftRegistries() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
if (!Items.LEATHER_HELMET.builtInRegistryHolder().areComponentsBound()) {
|
||||
Items.LEATHER_HELMET.builtInRegistryHolder().bindComponents(DataComponentMap.builder()
|
||||
.set(DataComponents.MAX_STACK_SIZE, 1)
|
||||
.set(DataComponents.MAX_DAMAGE, 55)
|
||||
.set(DataComponents.DAMAGE, 0)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void componentsPreserveAuthoredValuesAndDurability() {
|
||||
IrisLoot loot = new IrisLoot().setType("leather_helmet").setMinAmount(2).setMaxAmount(2)
|
||||
.setMinDurability(0.5).setMaxDurability(0.5).setUnbreakable(true)
|
||||
.setCustomModel(73).setLeatherColor("0x12ab34").setDisplayName("&aExplorer")
|
||||
.setLore(new KList<>("&bFirst line", "Second line"))
|
||||
.setCustomNbt(new KMap<String, Object>().qput("marker", "terrain"));
|
||||
List<String> warnings = new ArrayList<>();
|
||||
NativeItemContext context = new NativeItemContext(null,
|
||||
new NativeItemContext.Options("example", (key, message) -> warnings.add(message)));
|
||||
|
||||
NativeItemStack result = NativeItemTranslator.stack(new IrisItemRecipe(loot, new RNG(41)), context);
|
||||
|
||||
assertNotNull(result);
|
||||
ItemStack stack = result.stack();
|
||||
assertTrue(stack.is(Items.LEATHER_HELMET));
|
||||
assertEquals(2, stack.getCount());
|
||||
assertEquals((int) Math.round(stack.getMaxDamage() * 0.5), stack.getDamageValue());
|
||||
assertNotNull(stack.get(DataComponents.UNBREAKABLE));
|
||||
assertEquals(73F, stack.get(DataComponents.CUSTOM_MODEL_DATA).floats().getFirst(), 0F);
|
||||
assertEquals(0x12ab34, stack.get(DataComponents.DYED_COLOR).rgb());
|
||||
assertEquals("§aExplorer", stack.get(DataComponents.CUSTOM_NAME).getString());
|
||||
assertEquals("§bFirst line", stack.get(DataComponents.LORE).lines().getFirst().getString());
|
||||
assertEquals("terrain", stack.get(DataComponents.CUSTOM_DATA).copyTag().getString("marker").orElseThrow());
|
||||
assertTrue(warnings.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unknownItemDoesNotConsumeLootRandomness() {
|
||||
RNG random = new RNG(83);
|
||||
RNG expected = new RNG(83);
|
||||
List<String> warnings = new ArrayList<>();
|
||||
NativeItemContext context = new NativeItemContext(null,
|
||||
new NativeItemContext.Options("example", (key, message) -> warnings.add(key)));
|
||||
|
||||
NativeItemStack result = NativeItemTranslator.stack(new IrisItemRecipe(
|
||||
new IrisLoot().setType("example:unknown_item").setMinAmount(1).setMaxAmount(64), random), context);
|
||||
|
||||
assertNull(result);
|
||||
assertEquals(expected.nextLong(), random.nextLong());
|
||||
assertEquals(List.of("item:example:unknown_item"), warnings);
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativePayloadProtocol;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
public class NativePayloadProtocolTest {
|
||||
@Test
|
||||
public void frameRoundTripKeepsItsChannelAndBytes() {
|
||||
NativePayloadProtocol protocol = new NativePayloadProtocol("terrain:frame", 32);
|
||||
byte[] frame = new byte[]{1, 4, 9, 16};
|
||||
RegistryFriendlyByteBuf buffer = new RegistryFriendlyByteBuf(Unpooled.buffer(), RegistryAccess.EMPTY);
|
||||
try {
|
||||
protocol.codec().encode(buffer, protocol.payload(frame));
|
||||
NativePayloadProtocol.Payload decoded = protocol.codec().decode(buffer);
|
||||
|
||||
assertSame(protocol, decoded.protocol());
|
||||
assertArrayEquals(frame, decoded.data());
|
||||
assertEquals("terrain:frame", decoded.type().id().toString());
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decoderEnforcesTheConfiguredFrameLimit() {
|
||||
NativePayloadProtocol protocol = new NativePayloadProtocol("terrain:frame", 3);
|
||||
RegistryFriendlyByteBuf buffer = new RegistryFriendlyByteBuf(Unpooled.buffer(), RegistryAccess.EMPTY);
|
||||
try {
|
||||
buffer.writeByteArray(new byte[]{1, 2, 3, 4});
|
||||
assertThrows(DecoderException.class, () -> protocol.codec().decode(buffer));
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeRegistryAccess;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeBlockProperty;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class NativeRegistryAccessTest {
|
||||
@BeforeClass
|
||||
public static void bootstrapMinecraftRegistries() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void statePropertiesPreserveTypesDefaultsAndSharedGroups() {
|
||||
NativeRegistryAccess access = new NativeRegistryAccess(() -> null, message -> {});
|
||||
Map<String, List<NativeBlockProperty>> properties = access.blockStateProperties();
|
||||
|
||||
assertSame(properties.get("minecraft:stone"), properties.get("minecraft:dirt"));
|
||||
NativeBlockProperty power = properties.get("minecraft:redstone_wire").stream()
|
||||
.filter(property -> property.name().equals("power")).findFirst().orElseThrow();
|
||||
assertEquals("integer", power.jsonType());
|
||||
assertEquals(0, power.defaultValue());
|
||||
assertEquals(16, power.allowedValues().size());
|
||||
assertTrue(power.allowedValues().contains(15));
|
||||
assertNull(power.numericRange());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void staticRegistriesResolveWithoutAnActiveServerAndDynamicReadsStayEmpty() {
|
||||
List<String> warnings = new ArrayList<>();
|
||||
NativeRegistryAccess access = new NativeRegistryAccess(() -> null, warnings::add);
|
||||
|
||||
assertEquals("minecraft:diamond_sword", access.item("DIAMOND SWORD").key());
|
||||
assertEquals("creature", access.entity("minecraft:cow").spawnCategory());
|
||||
assertNull(access.item("example:unknown"));
|
||||
assertTrue(access.biomeKeys().isEmpty());
|
||||
assertTrue(access.structureKeys().isEmpty());
|
||||
assertTrue(access.enchantmentKeys().isEmpty());
|
||||
assertEquals(List.of("biome", "structure", "enchantment"), warnings);
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedBlockState;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeBlockResolver;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeStateMerger;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeStateRotator;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.world.level.block.StairBlock;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class NativeStateOperationsTest {
|
||||
@BeforeClass
|
||||
public static void bootstrapMinecraftRegistries() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rotationPreservesDeferredPlacementMetadata() {
|
||||
ModdedBlockState parsed = NativeBlockResolver.strictParse("minecraft:oak_stairs[facing=north]");
|
||||
ModdedBlockState deferred = ModdedBlockState.deferred(parsed.handle(), parsed.parsedProperties(), "custom:stairs");
|
||||
|
||||
NativeBlockState result = NativeStateRotator.rotate(deferred,
|
||||
(x, y, z) -> new NativeStateRotator.Vector(-z, y, x), failure -> {
|
||||
throw new AssertionError(failure);
|
||||
});
|
||||
|
||||
assertEquals(Direction.EAST, ((ModdedBlockState) result).handle().getValue(StairBlock.FACING));
|
||||
assertEquals("custom:stairs", result.deferredPlacementKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeAppliesOnlySpecifiedPropertiesAndRetainsDeferredPlacement() {
|
||||
ModdedBlockState parsed = NativeBlockResolver.strictParse("minecraft:oak_stairs[facing=west]");
|
||||
ModdedBlockState deferred = ModdedBlockState.deferred(parsed.handle(), parsed.parsedProperties(), "custom:stairs");
|
||||
ModdedBlockState update = NativeBlockResolver.strictParse("minecraft:oak_stairs[waterlogged=true]");
|
||||
|
||||
NativeBlockState result = new NativeStateMerger(ModdedBlockResolution.BLOCKS).merge(deferred, update);
|
||||
|
||||
assertEquals(Direction.WEST, ((ModdedBlockState) result).handle().getValue(StairBlock.FACING));
|
||||
assertTrue(((ModdedBlockState) result).handle().getValue(StairBlock.WATERLOGGED));
|
||||
assertEquals("custom:stairs", result.deferredPlacementKey());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.iris.nativegen.NativeStructureGenerationException;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.terrain.NativeStructureGenerationException;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
+44
-3
@@ -1,6 +1,10 @@
|
||||
package art.arcane.iris.modded.api;
|
||||
|
||||
import net.minecraft.resources.Identifier;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeEntityRuntime;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeSpawnedEntity;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -11,8 +15,45 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class ModdedCustomContentRegistryTest {
|
||||
@BeforeClass
|
||||
public static void bootstrapRegistries() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entityProviderReceivesCanonicalKeyAndOriginalWorldAndPosition() {
|
||||
ModdedDataProvider provider = mock(ModdedDataProvider.class);
|
||||
NativeEntityRuntime runtime = mock(NativeEntityRuntime.class);
|
||||
NativeSpawnedEntity entity = mock(NativeSpawnedEntity.class);
|
||||
NativeEntityRuntime.Position position = new NativeEntityRuntime.Position(2.5, 63.5, -4.5);
|
||||
NativeEntityRuntime.CustomSpawn canonical = new NativeEntityRuntime.CustomSpawn(runtime, position, "provider_test:mob");
|
||||
when(provider.modId()).thenReturn("provider_entity_test");
|
||||
when(provider.isReady()).thenReturn(true);
|
||||
when(provider.isValidProvider("provider_test:mob", ModdedDataType.ENTITY)).thenReturn(true);
|
||||
when(provider.spawnMob(canonical)).thenReturn(entity);
|
||||
ModdedCustomContentRegistry.Discovery discovery = ModdedCustomContentRegistry.discover(List.of(provider));
|
||||
try {
|
||||
assertSame(entity, ModdedCustomContentRegistry.spawnMob(
|
||||
new NativeEntityRuntime.CustomSpawn(runtime, position, " provider_test:mob[variant=a] ")));
|
||||
verify(provider).spawnMob(canonical);
|
||||
} finally {
|
||||
discovery.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unclaimedDeferredBlockDoesNotReadTheWorld() {
|
||||
ModdedCustomContentRegistry.processBlockPlacement(null, "provider_test:unclaimed", () -> {
|
||||
throw new AssertionError("unclaimed placement read the world");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishesProvidersOnlyAfterCompleteDiscoveryAndCanRollBack() {
|
||||
String modId = "iris_discovery_success";
|
||||
@@ -65,12 +106,12 @@ public class ModdedCustomContentRegistryTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Identifier> getTypes(ModdedDataType type) {
|
||||
public Collection<String> getTypes(ModdedDataType type) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidProvider(Identifier id, ModdedDataType type) {
|
||||
public boolean isValidProvider(String id, ModdedDataType type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -6,6 +6,7 @@ import art.arcane.iris.world.lifecycle.LifecycleOperationCoordinator;
|
||||
import art.arcane.iris.pack.PackDownloader;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.tree.CommandNode;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeCommandRegistration;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
@@ -27,7 +28,7 @@ public class IrisModdedCommandParityTest {
|
||||
Bootstrap.bootStrap();
|
||||
CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();
|
||||
|
||||
IrisModdedCommands.register(dispatcher);
|
||||
IrisModdedCommands.register(new NativeCommandRegistration(dispatcher));
|
||||
|
||||
CommandNode<CommandSourceStack> iris = child(dispatcher.getRoot(), "iris");
|
||||
CommandNode<CommandSourceStack> language = child(iris, "language");
|
||||
@@ -183,7 +184,7 @@ public class IrisModdedCommandParityTest {
|
||||
Bootstrap.bootStrap();
|
||||
CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();
|
||||
|
||||
IrisModdedCommands.register(dispatcher);
|
||||
IrisModdedCommands.register(new NativeCommandRegistration(dispatcher));
|
||||
|
||||
CommandNode<CommandSourceStack> iris = child(dispatcher.getRoot(), "iris");
|
||||
assertNotNull("iris", iris.getCommand());
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.structure.nativegen.IrisNativeStructureDecision;
|
||||
import art.arcane.iris.structure.nativegen.NativeStructureGenerationStatus;
|
||||
import art.arcane.iris.nativegen.NativeStructureLocateResults;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.terrain.NativeStructureLocateResults;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import org.junit.Test;
|
||||
|
||||
+11
-11
@@ -1,6 +1,6 @@
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeBlockPoint;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
@@ -25,29 +25,29 @@ public class ModdedDustRevealerTest {
|
||||
|
||||
@Test
|
||||
public void revealTraversalUsesDiagonalAdjacencyButNotDisconnectedBlocks() {
|
||||
Set<BlockPos> object = Set.of(
|
||||
new BlockPos(0, 0, 0),
|
||||
new BlockPos(1, 1, 1),
|
||||
new BlockPos(3, 3, 3));
|
||||
List<BlockPos> hits = ModdedDustRevealer.collect(
|
||||
new BlockPos(0, 0, 0),
|
||||
Set<NativeBlockPoint> object = Set.of(
|
||||
new NativeBlockPoint(0, 0, 0),
|
||||
new NativeBlockPoint(1, 1, 1),
|
||||
new NativeBlockPoint(3, 3, 3));
|
||||
List<NativeBlockPoint> hits = ModdedDustRevealer.collect(
|
||||
new NativeBlockPoint(0, 0, 0),
|
||||
"object",
|
||||
-64,
|
||||
-64,
|
||||
320,
|
||||
new AtomicBoolean(),
|
||||
(int x, int relativeY, int z) ->
|
||||
object.contains(new BlockPos(x, relativeY - 64, z))
|
||||
object.contains(new NativeBlockPoint(x, relativeY - 64, z))
|
||||
? "object"
|
||||
: null);
|
||||
|
||||
assertEquals(List.of(new BlockPos(0, 0, 0), new BlockPos(1, 1, 1)), hits);
|
||||
assertEquals(List.of(new NativeBlockPoint(0, 0, 0), new NativeBlockPoint(1, 1, 1)), hits);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelledRevealDoesNoTraversal() {
|
||||
List<BlockPos> hits = ModdedDustRevealer.collect(
|
||||
new BlockPos(0, 0, 0),
|
||||
List<NativeBlockPoint> hits = ModdedDustRevealer.collect(
|
||||
new NativeBlockPoint(0, 0, 0),
|
||||
"object",
|
||||
-64,
|
||||
-64,
|
||||
|
||||
+5
-5
@@ -6,7 +6,7 @@ import art.arcane.volmlib.util.localization.PluginLanguageService;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeCommandRegistration;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
@@ -67,13 +67,13 @@ public class ModdedLanguageCommandsTest {
|
||||
language.when(IrisLanguage::availableLocales).thenReturn(Set.of("de_DE"));
|
||||
language.when(() -> IrisLanguage.plain(DirectorHelpMessages.BACK)).thenReturn("Back");
|
||||
CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();
|
||||
dispatcher.register(Commands.literal("iris").then(ModdedLanguageCommands.tree()));
|
||||
new NativeCommandRegistration(dispatcher).register(NativeCommandRegistration.literal("iris").then(ModdedLanguageCommands.tree()));
|
||||
|
||||
assertEquals(1, dispatcher.execute("iris language", source));
|
||||
}
|
||||
|
||||
assertEquals(6, rendered.size());
|
||||
assertEquals(ModdedCommandFeedback.banner("/iris language"), rendered.getFirst());
|
||||
assertEquals(ModdedCommandFeedback.banner("/iris language").getString(), rendered.getFirst().getString());
|
||||
assertEquals(new ClickEvent.RunCommand("/iris"), rendered.get(1).getStyle().getClickEvent());
|
||||
assertEquals("Iris language: en_US", rendered.get(2).getString());
|
||||
Component locale = rendered.get(3);
|
||||
@@ -82,7 +82,7 @@ public class ModdedLanguageCommandsTest {
|
||||
assertEquals(new ClickEvent.RunCommand("/iris language self de_DE"),
|
||||
locale.getSiblings().getFirst().getStyle().getClickEvent());
|
||||
assertEquals(new ClickEvent.RunCommand("/iris language self reset"), rendered.get(4).getStyle().getClickEvent());
|
||||
assertEquals(ModdedCommandFeedback.footer(), rendered.getLast());
|
||||
assertEquals(ModdedCommandFeedback.footer().getString(), rendered.getLast().getString());
|
||||
}
|
||||
|
||||
private void assertPersonalCompletion(String requested, String selected, String expected) throws Exception {
|
||||
@@ -114,7 +114,7 @@ public class ModdedLanguageCommandsTest {
|
||||
try (MockedStatic<IrisLanguage> language = mockStatic(IrisLanguage.class)) {
|
||||
language.when(IrisLanguage::selections).thenReturn(service);
|
||||
CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();
|
||||
dispatcher.register(Commands.literal("iris").then(ModdedLanguageCommands.tree()));
|
||||
new NativeCommandRegistration(dispatcher).register(NativeCommandRegistration.literal("iris").then(ModdedLanguageCommands.tree()));
|
||||
assertEquals(1, dispatcher.execute("iris language self " + requested, source));
|
||||
assertTrue(rendered.isEmpty());
|
||||
selection.complete(null);
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.configuration.IrisSettings;
|
||||
import art.arcane.iris.generation.runtime.Engine;
|
||||
import art.arcane.iris.modded.ModdedGenPool;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativePregenRuntime;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class ModdedPregenMethodLifecycleTest {
|
||||
private MockedStatic<IrisSettings> settings;
|
||||
private NativePregenRuntime runtime;
|
||||
private ModdedPregenMethod method;
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
settings = mockStatic(IrisSettings.class);
|
||||
IrisSettings configured = new IrisSettings();
|
||||
settings.when(IrisSettings::get).thenReturn(configured);
|
||||
runtime = mock(NativePregenRuntime.class);
|
||||
when(runtime.worldIdentity()).thenReturn("example:terrain");
|
||||
Engine engine = mock(Engine.class);
|
||||
when(engine.getHeight()).thenReturn(384);
|
||||
method = new ModdedPregenMethod(new ModdedPregenMethod.Configuration(runtime, engine, true));
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
settings.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void periodicSaveRunsOnlyAfterTheServerExecutesIt() {
|
||||
method.save();
|
||||
verify(runtime, never()).save();
|
||||
ArgumentCaptor<Runnable> queued = ArgumentCaptor.forClass(Runnable.class);
|
||||
verify(runtime).execute(queued.capture());
|
||||
when(runtime.isServerThread()).thenReturn(true);
|
||||
queued.getValue().run();
|
||||
verify(runtime).save();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shutdownCanClaimTheFinalSaveWithoutQueuingWorkToItsOwnThread() {
|
||||
when(runtime.isServerThread()).thenReturn(true);
|
||||
assertTrue(method.deferFinalSaveToServerThread());
|
||||
method.close();
|
||||
assertTrue(method.hasPendingFinalSave());
|
||||
verify(runtime, never()).save();
|
||||
method.completeDeferredFinalSave();
|
||||
method.completeDeferredFinalSave();
|
||||
assertFalse(method.hasPendingFinalSave());
|
||||
verify(runtime, times(1)).save();
|
||||
verify(runtime, never()).execute(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asynchronousCallerCannotClaimTheShutdownSave() {
|
||||
assertFalse(method.deferFinalSaveToServerThread());
|
||||
assertThrows(IllegalStateException.class, method::completeDeferredFinalSave);
|
||||
verify(runtime, never()).save();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failedFinalSaveStillRestoresTheEmptyServerPauseSetting() {
|
||||
AtomicInteger pause = new AtomicInteger(60);
|
||||
when(runtime.supportsPauseWhenEmpty()).thenReturn(true);
|
||||
when(runtime.pauseWhenEmptySeconds()).thenAnswer(call -> pause.get());
|
||||
doAnswer(call -> {
|
||||
pause.set(call.getArgument(0, Integer.class));
|
||||
return null;
|
||||
}).when(runtime).pauseWhenEmptySeconds(anyInt());
|
||||
when(runtime.isServerThread()).thenReturn(true);
|
||||
IllegalStateException failure = new IllegalStateException("save failed");
|
||||
doThrow(failure).when(runtime).save();
|
||||
try (MockedStatic<ModdedGenPool> pool = mockStatic(ModdedGenPool.class)) {
|
||||
method.init();
|
||||
assertEquals(0, pause.get());
|
||||
assertSame(failure, assertThrows(IllegalStateException.class, method::close));
|
||||
}
|
||||
assertEquals(60, pause.get());
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedBlockState;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeBlockPoint;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedPlatformWorld;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeEditWorld;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class NativeEditWorldTest {
|
||||
@BeforeClass
|
||||
public static void bootstrapRegistries() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void repeatedWritesKeepTheOriginalUndoState() {
|
||||
ServerLevel level = mock(ServerLevel.class);
|
||||
BlockPos point = new BlockPos(2, 64, 3);
|
||||
when(level.getBlockState(point)).thenReturn(Blocks.STONE.defaultBlockState(), Blocks.DIRT.defaultBlockState());
|
||||
NativeEditWorld.EditSession session = new NativeEditWorld(new ModdedPlatformWorld(level))
|
||||
.editSession(new NativeEditWorld.EditOptions(1, 256, true));
|
||||
|
||||
assertEquals(NativeEditWorld.WriteResult.BLOCK, session.set(2, 64, 3, ModdedBlockState.of(Blocks.DIRT.defaultBlockState(), null)));
|
||||
assertEquals(NativeEditWorld.WriteResult.AIR, session.set(2, 64, 3, ModdedBlockState.of(Blocks.AIR.defaultBlockState(), null)));
|
||||
assertEquals(1, session.restore(failure -> { throw new AssertionError(failure.error()); }));
|
||||
verify(level).setBlock(point, Blocks.STONE.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void protectedBedrockAndOutOfRangeWritesNeverEnterUndo() {
|
||||
ServerLevel level = mock(ServerLevel.class);
|
||||
when(level.getBlockState(any())).thenReturn(Blocks.BEDROCK.defaultBlockState());
|
||||
NativeEditWorld.EditSession session = new NativeEditWorld(new ModdedPlatformWorld(level))
|
||||
.editSession(new NativeEditWorld.EditOptions(1, 256, true));
|
||||
ModdedBlockState stone = ModdedBlockState.of(Blocks.STONE.defaultBlockState(), null);
|
||||
|
||||
assertEquals(NativeEditWorld.WriteResult.SKIPPED, session.set(0, 0, 0, stone));
|
||||
assertEquals(NativeEditWorld.WriteResult.SKIPPED, session.set(0, 256, 0, stone));
|
||||
assertEquals(NativeEditWorld.WriteResult.SKIPPED, session.set(0, 64, 0, stone));
|
||||
assertTrue(session.empty());
|
||||
verify(level, never()).setBlock(any(), any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void captureOmitsOnlyRegularAirAndPreservesCaveAir() {
|
||||
ServerLevel level = mock(ServerLevel.class);
|
||||
when(level.getBlockState(any())).thenAnswer(invocation -> {
|
||||
BlockPos pos = invocation.getArgument(0);
|
||||
return pos.getX() == 0 ? Blocks.AIR.defaultBlockState() : Blocks.CAVE_AIR.defaultBlockState();
|
||||
});
|
||||
NativeEditWorld.CaptureTarget target = mock(NativeEditWorld.CaptureTarget.class);
|
||||
new NativeEditWorld(new ModdedPlatformWorld(level)).capture(
|
||||
new NativeEditWorld.Bounds(new NativeBlockPoint(0, 0, 0), new NativeBlockPoint(1, 0, 0)), target);
|
||||
|
||||
verify(target).block(1, 0, 0, ModdedBlockState.of(Blocks.CAVE_AIR.defaultBlockState(), null));
|
||||
verify(target, never()).block(eq(0), anyInt(), anyInt(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reopenedDimensionDoesNotAcceptTheOldWorldIdentity() {
|
||||
MinecraftServer server = mock(MinecraftServer.class);
|
||||
ServerLevel original = mock(ServerLevel.class);
|
||||
ServerLevel replacement = mock(ServerLevel.class);
|
||||
when(original.getServer()).thenReturn(server);
|
||||
when(original.dimension()).thenReturn(Level.OVERWORLD);
|
||||
when(server.getLevel(Level.OVERWORLD)).thenReturn(original, replacement);
|
||||
NativeEditWorld world = new NativeEditWorld(new ModdedPlatformWorld(original));
|
||||
|
||||
assertTrue(world.current());
|
||||
assertFalse(world.current());
|
||||
assertTrue(world.represents(new ModdedPlatformWorld(original)));
|
||||
assertFalse(world.represents(new ModdedPlatformWorld(replacement)));
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeCommandText;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeItemStack;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeTaggedItems;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.component.DataComponentMap;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class NativeTaggedItemsTest {
|
||||
@BeforeClass
|
||||
public static void bootstrapRegistries() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
if (!Items.BLAZE_ROD.builtInRegistryHolder().areComponentsBound()) {
|
||||
Items.BLAZE_ROD.builtInRegistryHolder().bindComponents(DataComponentMap.builder()
|
||||
.set(DataComponents.MAX_STACK_SIZE, 64).build());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toolRetainsNameLoreFlagsAndHiddenUnbreakableMarker() {
|
||||
NativeItemStack item = NativeTaggedItems.create(new NativeTaggedItems.Options("minecraft:blaze_rod",
|
||||
NativeCommandText.literal("Selection"), List.of(NativeCommandText.literal("First corner")),
|
||||
"selection_tool", true, true));
|
||||
|
||||
assertSame(Items.BLAZE_ROD, item.stack().getItem());
|
||||
assertEquals("Selection", item.stack().get(DataComponents.CUSTOM_NAME).getString());
|
||||
assertEquals("First corner", item.stack().get(DataComponents.LORE).lines().getFirst().getString());
|
||||
assertTrue(item.stack().get(DataComponents.CUSTOM_DATA).copyTag().getBooleanOr("selection_tool", false));
|
||||
assertTrue(item.stack().get(DataComponents.ENCHANTMENT_GLINT_OVERRIDE));
|
||||
assertTrue(item.stack().has(DataComponents.UNBREAKABLE));
|
||||
assertTrue(item.stack().get(DataComponents.TOOLTIP_DISPLAY).hiddenComponents().contains(DataComponents.UNBREAKABLE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void editingSoundKeysResolveToTheOriginalEvents() {
|
||||
assertSame(SoundEvents.END_PORTAL_FRAME_FILL, BuiltInRegistries.SOUND_EVENT.getValue(Identifier.parse("minecraft:block.end_portal_frame.fill")));
|
||||
assertSame(SoundEvents.LODESTONE_COMPASS_LOCK, BuiltInRegistries.SOUND_EVENT.getValue(Identifier.parse("minecraft:item.lodestone_compass.lock")));
|
||||
assertSame(SoundEvents.AMETHYST_BLOCK_CHIME, BuiltInRegistries.SOUND_EVENT.getValue(Identifier.parse("minecraft:block.amethyst_block.chime")));
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -1,5 +1,7 @@
|
||||
package art.arcane.iris.modded.service;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedPlatformWorld;
|
||||
|
||||
import art.arcane.iris.generation.runtime.Engine;
|
||||
import art.arcane.iris.generation.runtime.EngineMetrics;
|
||||
import art.arcane.iris.world.IrisWorld;
|
||||
@@ -49,13 +51,14 @@ public class ModdedChunkUpdateServiceTest {
|
||||
when(engine.getMetrics()).thenReturn(new EngineMetrics(8));
|
||||
ServerLevel level = mock(ServerLevel.class);
|
||||
when(level.getMinY()).thenReturn(-64);
|
||||
when(level.getMaxY()).thenReturn(320);
|
||||
when(level.getMaxY()).thenReturn(319);
|
||||
when(level.getHeight()).thenReturn(384);
|
||||
BlockPos position = new BlockPos(15, -59, 14);
|
||||
BlockState falling = Blocks.WATER.defaultBlockState().setValue(LiquidBlock.LEVEL, 8);
|
||||
when(level.getBlockState(position)).thenReturn(falling);
|
||||
UpdateRecordingMantleChunk chunk = new UpdateRecordingMantleChunk();
|
||||
|
||||
new ModdedChunkUpdateService().runUpdatePass(engine, level, 0, 0, chunk);
|
||||
new ModdedChunkUpdateService().runUpdatePass(engine, new ModdedPlatformWorld(level), 0, 0, chunk);
|
||||
|
||||
assertEquals(8, falling.getValue(LiquidBlock.LEVEL).intValue());
|
||||
if (falling.getFluidState().hasProperty(FlowingFluid.FALLING)) {
|
||||
|
||||
+8
-7
@@ -5,6 +5,7 @@ import net.minecraft.core.component.DataComponentMap;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
@@ -40,15 +41,15 @@ public class ModdedTreeFellerPresentationTest {
|
||||
|
||||
@Test
|
||||
public void compatibleDropsConsolidateWithoutExceedingStackLimits() {
|
||||
List<ItemStack> drops = ModdedTreeFellerPresentation.consolidateDrops(List.of(
|
||||
new ItemStack(Items.OAK_LOG, 48),
|
||||
new ItemStack(Items.OAK_LOG, 48),
|
||||
new ItemStack(Items.BIRCH_LOG, 3)
|
||||
List<NativeItemStack> drops = ModdedTreeFellerPresentation.consolidateDrops(List.of(
|
||||
NativeItemStack.of(new ItemStack(Items.OAK_LOG, 48)),
|
||||
NativeItemStack.of(new ItemStack(Items.OAK_LOG, 48)),
|
||||
NativeItemStack.of(new ItemStack(Items.BIRCH_LOG, 3))
|
||||
));
|
||||
|
||||
assertEquals(3, drops.size());
|
||||
assertEquals(64, drops.get(0).getCount());
|
||||
assertEquals(32, drops.get(1).getCount());
|
||||
assertEquals(3, drops.get(2).getCount());
|
||||
assertEquals(64, drops.get(0).count());
|
||||
assertEquals(32, drops.get(1).count());
|
||||
assertEquals(3, drops.get(2).count());
|
||||
}
|
||||
}
|
||||
+11
-2
@@ -3,6 +3,10 @@ package art.arcane.iris.modded.service;
|
||||
import art.arcane.iris.world.IrisWorldBoundary;
|
||||
import art.arcane.iris.world.IrisWorldBoundaryCenter;
|
||||
import net.minecraft.world.level.border.WorldBorder;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedPlatformWorld;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -17,7 +21,7 @@ public class ModdedWorldBoundaryTest {
|
||||
worldBorder.setSafeZone(2.5D);
|
||||
worldBorder.setDamagePerBlock(0.75D);
|
||||
|
||||
ModdedStudioHotloadService.applyWorldBoundary(worldBorder, null);
|
||||
ModdedStudioHotloadService.applyWorldBoundary(world(worldBorder), null);
|
||||
|
||||
assertEquals(3.5D, worldBorder.getCenterX(), 0D);
|
||||
assertEquals(-4.5D, worldBorder.getCenterZ(), 0D);
|
||||
@@ -37,7 +41,7 @@ public class ModdedWorldBoundaryTest {
|
||||
.setDamageBuffer(6.5D)
|
||||
.setDamageAmount(0.4D);
|
||||
|
||||
ModdedStudioHotloadService.applyWorldBoundary(worldBorder, boundary);
|
||||
ModdedStudioHotloadService.applyWorldBoundary(world(worldBorder), boundary);
|
||||
|
||||
assertEquals(12.5D, worldBorder.getCenterX(), 0D);
|
||||
assertEquals(-7.25D, worldBorder.getCenterZ(), 0D);
|
||||
@@ -46,4 +50,9 @@ public class ModdedWorldBoundaryTest {
|
||||
assertEquals(6.5D, worldBorder.getSafeZone(), 0D);
|
||||
assertEquals(0.4D, worldBorder.getDamagePerBlock(), 0D);
|
||||
}
|
||||
private static ModdedPlatformWorld world(WorldBorder border) {
|
||||
ServerLevel level = mock(ServerLevel.class);
|
||||
when(level.getWorldBorder()).thenReturn(border);
|
||||
return new ModdedPlatformWorld(level);
|
||||
}
|
||||
}
|
||||
+25
-17
@@ -1,5 +1,17 @@
|
||||
package art.arcane.iris.nativegen;
|
||||
|
||||
import art.arcane.iris.structure.nativegen.IrisStructurePolicy;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.terrain.NativeStructureReferenceRepair;
|
||||
|
||||
import art.arcane.volmlib.nativelib.terrain.structure.StructureOwnershipRecordView;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.terrain.NativeStructureOwnershipFingerprint;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.terrain.NativeStructureVerticalPlacer;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.terrain.NativeStructureReferenceEnvelope;
|
||||
|
||||
import art.arcane.iris.pack.loading.IrisData;
|
||||
import art.arcane.iris.generation.runtime.IrisEngine;
|
||||
import art.arcane.iris.generation.runtime.Engine;
|
||||
@@ -14,7 +26,7 @@ import art.arcane.iris.structure.nativegen.IrisNativeStructure;
|
||||
import art.arcane.iris.structure.nativegen.IrisNativeStructureDecision;
|
||||
import art.arcane.iris.structure.placement.IrisStructurePlacement;
|
||||
import art.arcane.iris.structure.placement.IrisStructureTerrain;
|
||||
import art.arcane.iris.structure.placement.IrisStructureTerrainMode;
|
||||
import art.arcane.volmlib.util.structure.StructureTerrainMode;
|
||||
import art.arcane.iris.structure.nativegen.NativeStructureGenerationStatus;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
@@ -75,18 +87,16 @@ public class NativeStructureReferenceRepairTest {
|
||||
NativeStructureVerticalPlacer.alignOceanMonumentToSeaLevel(
|
||||
generated, 0, 80, -64, 320);
|
||||
IrisStructureTerrain terrain = new IrisStructureTerrain()
|
||||
.setMode(IrisStructureTerrainMode.FORCE_CARVE)
|
||||
.setMode(StructureTerrainMode.FORCE_CARVE)
|
||||
.setHorizontalPadding(24);
|
||||
StructureStart wrapped = NativeStructureReferenceEnvelope.wrap(
|
||||
generated,
|
||||
structure,
|
||||
0,
|
||||
terrain);
|
||||
NativeStructureOwnershipRecord ownership = NativeStructureOwnershipFingerprint.capture(
|
||||
"minecraft:monument",
|
||||
wrapped,
|
||||
plan(origin, NativeStructureReferenceEnvelope.contentBounds(wrapped).minY()),
|
||||
NativeStructureReferenceEnvelope.referenceBounds(wrapped, structure, terrain));
|
||||
NativeStructureOwnershipRecord ownership = NativeStructureOwnershipRecord.capture(
|
||||
NativeStructureOwnershipFingerprint.capture(
|
||||
"minecraft:monument", wrapped, NativeStructureReferenceEnvelope.referenceBounds(wrapped, structure, terrain)), plan(origin, NativeStructureReferenceEnvelope.contentBounds(wrapped).minY()));
|
||||
PiecesContainer regeneratedPieces = OceanMonumentStructure.regeneratePiecesAfterLoad(
|
||||
origin, seed, new PiecesContainer(wrapped.getPieces()));
|
||||
StructureStart reloaded = new StructureStart(structure, origin, 0, regeneratedPieces);
|
||||
@@ -128,15 +138,13 @@ public class NativeStructureReferenceRepairTest {
|
||||
NativeStructureVerticalPlacer.alignOceanMonumentToSeaLevel(
|
||||
generated, 0, 80, -64, 320);
|
||||
IrisStructureTerrain terrain = new IrisStructureTerrain()
|
||||
.setMode(IrisStructureTerrainMode.FORCE_CARVE)
|
||||
.setMode(StructureTerrainMode.FORCE_CARVE)
|
||||
.setHorizontalPadding(24);
|
||||
StructureStart start = NativeStructureReferenceEnvelope.wrap(
|
||||
generated, structure, 0, terrain);
|
||||
NativeStructureOwnershipRecord ownership = NativeStructureOwnershipFingerprint.capture(
|
||||
structureKey,
|
||||
start,
|
||||
plan(origin, NativeStructureReferenceEnvelope.contentBounds(start).minY()),
|
||||
NativeStructureReferenceEnvelope.referenceBounds(start, structure, terrain));
|
||||
NativeStructureOwnershipRecord ownership = NativeStructureOwnershipRecord.capture(
|
||||
NativeStructureOwnershipFingerprint.capture(
|
||||
structureKey, start, NativeStructureReferenceEnvelope.referenceBounds(start, structure, terrain)), plan(origin, NativeStructureReferenceEnvelope.contentBounds(start).minY()));
|
||||
IrisDimension dimension = new IrisDimension();
|
||||
dimension.getImportedStructures().getDisabled().add(structureKey);
|
||||
IrisData data = allocateWithoutConstructor(IrisData.class);
|
||||
@@ -165,7 +173,7 @@ public class NativeStructureReferenceRepairTest {
|
||||
registry, serverLevel, originChunk, emptyScannedChunk);
|
||||
ProtoChunk coveredChunk = emptyChunk(coveredTarget);
|
||||
NativeStructureReferenceRepair.createReferences(
|
||||
engine, level, structureManager, coveredChunk);
|
||||
new IrisStructurePolicy(engine), level, structureManager, coveredChunk);
|
||||
|
||||
assertSame(start, originChunk.getStartForStructure(structure));
|
||||
assertTrue(originChunk.getStartForStructure(structure).isValid());
|
||||
@@ -173,7 +181,7 @@ public class NativeStructureReferenceRepairTest {
|
||||
|
||||
ProtoChunk uncoveredChunk = emptyChunk(uncoveredTarget);
|
||||
NativeStructureReferenceRepair.createReferences(
|
||||
engine, level, structureManager, uncoveredChunk);
|
||||
new IrisStructurePolicy(engine), level, structureManager, uncoveredChunk);
|
||||
|
||||
assertSame(start, originChunk.getStartForStructure(structure));
|
||||
assertTrue(originChunk.getStartForStructure(structure).isValid());
|
||||
@@ -248,9 +256,9 @@ public class NativeStructureReferenceRepairTest {
|
||||
for (ChunkPos candidate : candidates) {
|
||||
if (!ownership.covers(candidate.x(), candidate.z())
|
||||
&& Math.abs(candidate.x() - originX)
|
||||
<= NativeStructureOwnershipRecord.MAX_REFERENCE_DISTANCE_CHUNKS
|
||||
<= StructureOwnershipRecordView.MAX_REFERENCE_DISTANCE_CHUNKS
|
||||
&& Math.abs(candidate.z() - originZ)
|
||||
<= NativeStructureOwnershipRecord.MAX_REFERENCE_DISTANCE_CHUNKS) {
|
||||
<= StructureOwnershipRecordView.MAX_REFERENCE_DISTANCE_CHUNKS) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -1,7 +1,11 @@
|
||||
package art.arcane.iris.nativegen;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.terrain.NativeStructureTerrainIntegrator;
|
||||
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.terrain.NativeStructureSurfaceFitter;
|
||||
|
||||
import art.arcane.iris.structure.placement.IrisStructureTerrain;
|
||||
import art.arcane.iris.structure.placement.IrisStructureTerrainMode;
|
||||
import art.arcane.volmlib.util.structure.StructureTerrainMode;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
@@ -42,7 +46,7 @@ public class NativeStructureVacuumParityTest {
|
||||
NativeStructureTerrainIntegrator.TerrainTarget target =
|
||||
new NativeStructureTerrainIntegrator.TerrainTarget(
|
||||
"test:vacuum", start,
|
||||
new IrisStructureTerrain().setMode(IrisStructureTerrainMode.VACUUM));
|
||||
new IrisStructureTerrain().setMode(StructureTerrainMode.VACUUM));
|
||||
|
||||
assertTrue(NativeStructureSurfaceFitter.requiresSurfaceTerrain(target));
|
||||
assertFalse(NativeStructureTerrainIntegrator.clearsLegacyTemplateAir(
|
||||
|
||||
Reference in new issue
Block a user