From dc3fe7d3184c214d11379bcc72db833ecfd20cd0 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Wed, 28 Oct 2026 19:50:46 +0000 Subject: [PATCH] Add exact ore host variants on 1.10.2 --- .github/workflows/ci.yml | 6 +- CHANGELOG.txt | 6 ++ README.md | 2 +- docs/API.md | 14 +++ docs/VERSIONS.md | 2 +- gradle.properties | 2 +- gradle/release/artifacts.gradle | 6 +- .../orespawn/compat/LegacyOs3Bridge.java | 2 +- src/main/java/cyano/orespawn/OreSpawn.java | 2 +- .../zone/moddev/mc/orespawn/OreSpawn.java | 2 +- .../mc/orespawn/api/WorldgenProvider.java | 39 +++++++- .../LegacyMineralogyProfileMigration.java | 2 +- .../worldgen/LegacyOs3ProfileMigration.java | 2 +- .../orespawn/api/ExactHostStateApiTest.java | 92 +++++++++++++++++++ .../worldgen/ExactHostStateBakeTest.java | 56 +++++++++++ 15 files changed, 219 insertions(+), 16 deletions(-) create mode 100644 src/test/java/zone/moddev/mc/orespawn/api/ExactHostStateApiTest.java create mode 100644 src/test/java/zone/moddev/mc/orespawn/worldgen/ExactHostStateBakeTest.java diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 41af3ba2..df76b628 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,9 +126,9 @@ jobs: if-no-files-found: error retention-days: 30 path: | - build/libs/OreSpawn-4.1.3.110021.jar - build/libs/OreSpawn-4.1.3.110021-sources.jar - build/libs/OreSpawn-4.1.3.110021-javadoc.jar + build/libs/OreSpawn-4.1.4.110021.jar + build/libs/OreSpawn-4.1.4.110021-sources.jar + build/libs/OreSpawn-4.1.4.110021-javadoc.jar build/release/SHA256SUMS CHANGELOG.txt diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 0990b261..057a2c6f 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,9 @@ +Version 4.1.4.110021 + +* Let Java providers select an exact legacy host variant, such as plain stone + without granite. Keep existing block selectors and placement behaviour. +* Reject invalid exact-host weights without leaving a partly configured host. + Version 4.1.3.110021 * Apply hybrid and replacement background limits to imported built-in ore diff --git a/README.md b/README.md index 4066a3b5..f3b71f3b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ It gives mods and modpacks one place to configure ores, deposit shapes, optional rock strata and geomes, provider-owned underground fluid deposits, biome palettes and world materials, flat bedrock, and bounded ore retrogen. -This branch builds target-qualified version `4.1.3.110021`: the OreSpawn 4.1.3 +This branch builds target-qualified version `4.1.4.110021`: the OreSpawn 4.1.4 feature set for Minecraft 1.10.2 and Forge. It adds stable generation identity, non-loading geology sampling, per-resource background control, existing-world provider merge policy, an Ore Sources arbiter for equivalent provider ores and diff --git a/docs/API.md b/docs/API.md index c45a3a0e..a0aac0aa 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1,5 +1,19 @@ # Java API +## Exact legacy host states + +Since 4.1.4.110021, Java providers can use `hostState(blockId, metadata)` on the +ore dimension builder. For example, `hostState(new ResourceLocation("minecraft", +"stone"), 0)` accepts plain stone without also accepting granite, diorite or +andesite. A third argument supplies a replacement weight between zero and one. + +`hostBlock` still selects the whole block, as before. Families and other hosts +are alternatives, so do not add a broad stone or family selector when the +restriction needs to be exact. This addition uses the existing JSON metadata +matcher and does not change old providers. Mods that call the new method must +require OreSpawn 4.1.4 or later; older providers keep their existing dependency +range. + This branch targets Minecraft 1.10.2 and Forge 12. Public examples therefore use the public `ResourceLocation(String, String)` constructor. Forge 12 has no `DeferredRegister`, so provider mods use OreSpawn's API-major-1 diff --git a/docs/VERSIONS.md b/docs/VERSIONS.md index a89ad8fe..9880738d 100644 --- a/docs/VERSIONS.md +++ b/docs/VERSIONS.md @@ -51,7 +51,7 @@ Examples: | Minecraft | Loader | Target | Example full version | | --- | --- | ---: | --- | -| 1.10.2 | Forge | `110021` | `4.1.3.110021` | +| 1.10.2 | Forge | `110021` | `4.1.4.110021` | | 1.12.2 | Forge | `112021` | `4.0.6.112021` | | 1.13.2 | Forge | `113021` | `4.0.6.113021` | | 1.20.6 | Forge | `120061` | `4.0.6.120061` | diff --git a/gradle.properties b/gradle.properties index 42c6e12b..c17aaac7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -30,7 +30,7 @@ mod_vendor=Minecraft Mod Development mod_license=LGPL-2.1 mod_license_name=GNU Lesser General Public License, Version 2.1 mod_license_url=https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt -mod_version=4.1.3.110021 +mod_version=4.1.4.110021 mod_group=zone.moddev.mc.orespawn mod_authors=SkyBlade1978, dshadowwolf, the MMD Team mod_description=Configurable, provider-driven terrain, ore, and deposit generation. diff --git a/gradle/release/artifacts.gradle b/gradle/release/artifacts.gradle index aa28aa24..6b0d5b7e 100644 --- a/gradle/release/artifacts.gradle +++ b/gradle/release/artifacts.gradle @@ -77,7 +77,7 @@ tasks.register('verifyReleaseConfiguration') { description = 'Validates the target-qualified release, API, schemas, reports, and publishing identity.' doLast { - if (project.mod_version != '4.1.3.110021' + if (project.mod_version != '4.1.4.110021' || project.mod_group != expectedMavenGroup) { throw new GradleException("Unexpected OreSpawn release version: ${project.mod_version}") } @@ -106,8 +106,8 @@ tasks.register('verifyReleaseConfiguration') { 'src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyOs3ProfileMigration.java', 'README.md', 'CHANGELOG.txt' ].each { path -> - if (!file(path).getText('UTF-8').contains('4.1.3.110021')) { - throw new GradleException("Authoritative release location does not contain 4.1.3.110021: ${path}") + if (!file(path).getText('UTF-8').contains('4.1.4.110021')) { + throw new GradleException("Authoritative release location does not contain 4.1.4.110021: ${path}") } } if (!file('docs/API.md').getText('UTF-8').contains('orespawn@[4.0.6,5.0.0)')) { diff --git a/src/main/java/com/mcmoddev/orespawn/compat/LegacyOs3Bridge.java b/src/main/java/com/mcmoddev/orespawn/compat/LegacyOs3Bridge.java index c7363018..5af35159 100644 --- a/src/main/java/com/mcmoddev/orespawn/compat/LegacyOs3Bridge.java +++ b/src/main/java/com/mcmoddev/orespawn/compat/LegacyOs3Bridge.java @@ -1027,7 +1027,7 @@ private static void writeHumanUpgradeReport(Path destination) throws IOException } } List lines = new ArrayList<>(); - lines.add("OreSpawn 4.1.3.110021 Upgrade Report"); + lines.add("OreSpawn 4.1.4.110021 Upgrade Report"); lines.add("================================"); lines.add(""); lines.add("RESULT: Legacy OreSpawn configuration was consumed and translated for OS4."); diff --git a/src/main/java/cyano/orespawn/OreSpawn.java b/src/main/java/cyano/orespawn/OreSpawn.java index 02b6d108..fc86bf41 100644 --- a/src/main/java/cyano/orespawn/OreSpawn.java +++ b/src/main/java/cyano/orespawn/OreSpawn.java @@ -19,7 +19,7 @@ public class OreSpawn { public static OreSpawn INSTANCE; public static final String MODID = "orespawn"; public static final String NAME = "OreSpawn"; - public static final String VERSION = "4.1.3.110021"; + public static final String VERSION = "4.1.4.110021"; public static final List oreSpawnConfigFiles = new ArrayList<>(); public static final List additionalStoneBlocks = new ArrayList<>(); public static boolean disableVanillaOreGen; diff --git a/src/main/java/zone/moddev/mc/orespawn/OreSpawn.java b/src/main/java/zone/moddev/mc/orespawn/OreSpawn.java index 5758c852..cb9eb94e 100644 --- a/src/main/java/zone/moddev/mc/orespawn/OreSpawn.java +++ b/src/main/java/zone/moddev/mc/orespawn/OreSpawn.java @@ -52,7 +52,7 @@ public class OreSpawn { public static final String MODID = "orespawn"; public static final String NAME = "OreSpawn"; - public static final String VERSION = "4.1.3.110021"; + public static final String VERSION = "4.1.4.110021"; private static final Logger LOGGER = LogManager.getLogger(); diff --git a/src/main/java/zone/moddev/mc/orespawn/api/WorldgenProvider.java b/src/main/java/zone/moddev/mc/orespawn/api/WorldgenProvider.java index a62bf209..6d7d5aa4 100644 --- a/src/main/java/zone/moddev/mc/orespawn/api/WorldgenProvider.java +++ b/src/main/java/zone/moddev/mc/orespawn/api/WorldgenProvider.java @@ -566,6 +566,7 @@ public static final class OreDimensionDefinition implements JsonDefinition { private final Set hostFamilies; private final Map geomes; private final Set hostBlocks; + private final Map> hostStates; private final Set hostTags; private final Set biomeIds; private final Set excludedBiomeIds; @@ -597,6 +598,9 @@ private OreDimensionDefinition(Builder builder) { hostFamilies = Collections.unmodifiableSet(new LinkedHashSet<>(builder.hostFamilies)); geomes = immutableMap(builder.geomes); hostBlocks = immutableSet(builder.hostBlocks); + Map> states = new LinkedHashMap<>(); + builder.hostStates.forEach((block, variants) -> states.put(block, immutableMap(variants))); + hostStates = immutableMap(states); hostTags = immutableSet(builder.hostTags); biomeIds = immutableSet(builder.biomeIds); excludedBiomeIds = immutableSet(builder.excludedBiomeIds); @@ -631,6 +635,8 @@ private OreDimensionDefinition(Builder builder) { public Set hostFamilies() { return hostFamilies; } public Map geomes() { return geomes; } public Set hostBlocks() { return hostBlocks; } + /** Exact legacy variants, separate from whole-block selectors. */ + public Map> hostStates() { return hostStates; } public Set hostTags() { return hostTags; } public Set biomeIds() { return biomeIds; } public Set excludedBiomeIds() { return excludedBiomeIds; } @@ -679,7 +685,15 @@ public JsonObject toJson() { for (GeologyFamily family : hostFamilies) { families.add(new JsonPrimitive(family.configName())); } json.add("host_families", families); json.add("geomes", weights(geomes)); - json.add("host_blocks", weightedIds(hostBlocks, hostBlockWeights, "block")); + JsonArray hosts = weightedIds(hostBlocks, hostBlockWeights, "block"); + hostStates.forEach((block, variants) -> variants.forEach((metadata, weight) -> { + JsonObject state = new JsonObject(); + state.addProperty("block", block.toString()); + state.addProperty("metadata", metadata); + if (weight != 1.0D) state.addProperty("weight", weight); + hosts.add(state); + })); + json.add("host_blocks", hosts); json.add("host_tags", weightedIds(hostTags, hostTagWeights, "tag")); json.add("biome_ids", ids(biomeIds)); json.add("excluded_biome_ids", ids(excludedBiomeIds)); @@ -711,6 +725,7 @@ public static final class Builder { private final Set hostFamilies = new LinkedHashSet<>(); private final Map geomes = new LinkedHashMap<>(); private final Set hostBlocks = new LinkedHashSet<>(); + private final Map> hostStates = new LinkedHashMap<>(); private final Set hostTags = new LinkedHashSet<>(); private final Set biomeIds = new LinkedHashSet<>(); private final Set excludedBiomeIds = new LinkedHashSet<>(); @@ -751,6 +766,25 @@ public Builder placementChannel(ResourceLocation value) { public Builder hostFamily(GeologyFamily value) { hostFamilies.add(value); return this; } public Builder geomeWeight(ResourceLocation geome, double value) { geomes.put(geome, value); return this; } public Builder hostBlock(ResourceLocation value) { hostBlocks.add(value); return this; } + + /** Selects one legacy block variant, such as plain stone (metadata zero). */ + public Builder hostState(ResourceLocation block, int metadata) { + return hostState(block, metadata, 1.0D); + } + + /** Adds an exact variant with the same replacement weight as hostBlock. */ + public Builder hostState(ResourceLocation block, int metadata, double weight) { + Objects.requireNonNull(block, "block"); + if (metadata < 0 || metadata > 15) { + throw new IllegalArgumentException("Legacy host metadata must be within 0..15"); + } + + double validatedWeight = replacementWeight(weight); + hostStates.computeIfAbsent(block, ignored -> new LinkedHashMap<>()) + .put(metadata, validatedWeight); + return this; + } + public Builder hostTag(ResourceLocation value) { hostTags.add(value); return this; } public Builder biome(ResourceLocation value) { biomeIds.add(value); return this; } public Builder excludeBiome(ResourceLocation value) { excludedBiomeIds.add(value); return this; } @@ -791,7 +825,8 @@ public OreDimensionDefinition build() { || nodeSize < 1 || nodeSize > 32) { throw new IllegalStateException("Invalid ore placement values for " + dimension); } - if (enabled && hostFamilies.isEmpty() && hostBlocks.isEmpty() && hostTags.isEmpty()) { + if (enabled && hostFamilies.isEmpty() && hostBlocks.isEmpty() + && hostStates.isEmpty() && hostTags.isEmpty()) { throw new IllegalStateException("Enabled ore dimension has no hosts: " + dimension); } return new OreDimensionDefinition(this); diff --git a/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyMineralogyProfileMigration.java b/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyMineralogyProfileMigration.java index 1845ca8e..e8bafced 100644 --- a/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyMineralogyProfileMigration.java +++ b/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyMineralogyProfileMigration.java @@ -125,7 +125,7 @@ private static void writeUpgradeReport(Path worldRoot, Path configDirectory, } List lines = new ArrayList<>(); - lines.add("OreSpawn 4.1.3.110021 Upgrade Report"); + lines.add("OreSpawn 4.1.4.110021 Upgrade Report"); lines.add("================================"); lines.add(""); lines.add("RESULT: Existing Mineralogy " + mineralogyVersion diff --git a/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyOs3ProfileMigration.java b/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyOs3ProfileMigration.java index 7b05e71f..cae11bdf 100644 --- a/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyOs3ProfileMigration.java +++ b/src/main/java/zone/moddev/mc/orespawn/worldgen/LegacyOs3ProfileMigration.java @@ -65,7 +65,7 @@ private static void writeInitialUpgradeReport(Path configDirectory, boolean forceRetrogen, boolean flatBedrock, boolean retrogenBedrock, int bedrockLayers) throws IOException { String newline = System.lineSeparator(); - String text = "OreSpawn 4.1.3.110021 Upgrade Report" + newline + String text = "OreSpawn 4.1.4.110021 Upgrade Report" + newline + "================================" + newline + newline + "RESULT: Legacy OreSpawn settings were imported into the OS4 profile." + newline + "- Manage vanilla ores: " + manageVanilla + newline diff --git a/src/test/java/zone/moddev/mc/orespawn/api/ExactHostStateApiTest.java b/src/test/java/zone/moddev/mc/orespawn/api/ExactHostStateApiTest.java new file mode 100644 index 00000000..0271dc67 --- /dev/null +++ b/src/test/java/zone/moddev/mc/orespawn/api/ExactHostStateApiTest.java @@ -0,0 +1,92 @@ +package zone.moddev.mc.orespawn.api; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.lang.reflect.Method; + +import org.junit.jupiter.api.Test; + +import net.minecraft.util.ResourceLocation; + +class ExactHostStateApiTest { + + @Test + void publicBuilderCanSelectPlainStoneWithoutItsIgneousVariants() throws Exception { + WorldgenProvider.OreDimensionDefinition.Builder builder = + WorldgenProvider.OreDimensionDefinition.builder(new ResourceLocation("minecraft:overworld")); + Method hostState = builder.getClass().getMethod("hostState", ResourceLocation.class, int.class); + hostState.invoke(builder, new ResourceLocation("minecraft:stone"), 0); + + assertEquals("[{\"block\":\"minecraft:stone\",\"metadata\":0}]", + builder.build().toJson().getAsJsonArray("host_blocks").toString()); + } + + @Test + void exactHostsAreImmutableWeightedAndDoNotChangeOldBlockSelectors() { + ResourceLocation stone = new ResourceLocation("minecraft:stone"); + WorldgenProvider.OreDimensionDefinition.Builder builder = + WorldgenProvider.OreDimensionDefinition.builder(new ResourceLocation("minecraft:overworld")); + String original = builder.hostBlock(stone).build().toJson().toString(); + WorldgenProvider.OreDimensionDefinition exact = builder.hostState(stone, 0, 0.5D).build(); + + assertEquals(0.5D, exact.hostStates().get(stone).get(0)); + assertThrows(UnsupportedOperationException.class, () -> exact.hostStates().clear()); + assertThrows(UnsupportedOperationException.class, () -> exact.hostStates().get(stone).put(1, 1.0D)); + builder.hostState(stone, 1); + assertEquals(1, exact.hostStates().get(stone).size()); + assertEquals(original, WorldgenProvider.OreDimensionDefinition + .builder(new ResourceLocation("minecraft:overworld")).hostBlock(stone).build().toJson().toString()); + assertThrows(IllegalArgumentException.class, () -> builder.hostState(stone, -1)); + assertThrows(IllegalArgumentException.class, () -> builder.hostState(stone, 16)); + assertThrows(NullPointerException.class, () -> builder.hostState(null, 0)); + } + + @Test + void rejectedWeightsDoNotBypassTheNoHostCheck() { + assertAll("invalid weights", () -> rejectWithoutAddingHost(-0.1D), + () -> rejectWithoutAddingHost(1.1D), () -> rejectWithoutAddingHost(Double.NaN), + () -> rejectWithoutAddingHost(Double.POSITIVE_INFINITY), + () -> rejectWithoutAddingHost(Double.NEGATIVE_INFINITY)); + } + + private static void rejectWithoutAddingHost(double weight) { + WorldgenProvider.OreDimensionDefinition.Builder builder = + WorldgenProvider.OreDimensionDefinition.builder(new ResourceLocation("minecraft:overworld")); + assertThrows(IllegalArgumentException.class, + () -> builder.hostState(new ResourceLocation("minecraft:stone"), 0, weight)); + assertThrows(IllegalStateException.class, builder::build, + "A rejected host must not make an empty rule valid: " + weight); + } + + @Test + void rejectedWeightsLeaveExistingHostsUnchanged() { + ResourceLocation stone = new ResourceLocation("minecraft:stone"); + ResourceLocation dirt = new ResourceLocation("minecraft:dirt"); + WorldgenProvider.OreDimensionDefinition.Builder builder = + WorldgenProvider.OreDimensionDefinition.builder(new ResourceLocation("minecraft:overworld")) + .hostState(stone, 0, 0.5D); + String original = builder.build().toJson().toString(); + assertThrows(IllegalArgumentException.class, () -> builder.hostState(dirt, 0, Double.NaN)); + assertThrows(IllegalArgumentException.class, () -> builder.hostState(stone, 0, 2.0D)); + WorldgenProvider.OreDimensionDefinition result = builder.build(); + assertFalse(result.hostStates().containsKey(dirt)); + assertEquals(0.5D, result.hostStates().get(stone).get(0)); + assertEquals(original, result.toJson().toString()); + } + + @Test + void endpointsAndSeveralVariantsSerializeInInsertionOrder() { + WorldgenProvider.OreDimensionDefinition value = + WorldgenProvider.OreDimensionDefinition.builder(new ResourceLocation("minecraft:overworld")) + .hostState(new ResourceLocation("minecraft:stone"), 0, 0.0D) + .hostState(new ResourceLocation("minecraft:stone"), 1, 0.5D) + .hostState(new ResourceLocation("minecraft:stone"), 6, 1.0D).build(); + assertEquals("[{\"block\":\"minecraft:stone\",\"metadata\":0,\"weight\":0.0}," + + "{\"block\":\"minecraft:stone\",\"metadata\":1,\"weight\":0.5}," + + "{\"block\":\"minecraft:stone\",\"metadata\":6}]", + value.toJson().getAsJsonArray("host_blocks").toString()); + } +} diff --git a/src/test/java/zone/moddev/mc/orespawn/worldgen/ExactHostStateBakeTest.java b/src/test/java/zone/moddev/mc/orespawn/worldgen/ExactHostStateBakeTest.java new file mode 100644 index 00000000..9f92f464 --- /dev/null +++ b/src/test/java/zone/moddev/mc/orespawn/worldgen/ExactHostStateBakeTest.java @@ -0,0 +1,56 @@ +package zone.moddev.mc.orespawn.worldgen; + +import static org.junit.jupiter.api.Assertions.*; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Random; + +import com.google.gson.JsonObject; + +import org.junit.jupiter.api.Test; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.util.ResourceLocation; + +import zone.moddev.mc.orespawn.api.WorldgenProvider; +import zone.moddev.mc.orespawn.test.Forge12TestBootstrap; + +class ExactHostStateBakeTest { + @Test + void providerStatesReachTheExistingMatcherWithoutAcceptingSiblingVariants() throws Exception { + Forge12TestBootstrap.registerVanilla(); + if (zone.moddev.mc.orespawn.init.OreSpawnPatterns.registry() + .getValue(new ResourceLocation("orespawn:default")) == null) { + zone.moddev.mc.orespawn.init.OreSpawnPatterns.registerTypes(new net.minecraftforge.event.RegistryEvent.Register<>( + zone.moddev.mc.orespawn.api.OreSpawnPatternRegistry.REGISTRY_NAME, + zone.moddev.mc.orespawn.init.OreSpawnPatterns.registry())); + } + JsonObject provider = WorldgenProvider.builder("coaltest", 1) + .ore(new ResourceLocation("coaltest:coal"), new ResourceLocation("minecraft:coal_ore"), + ore -> ore.dimension(WorldIds.OVERWORLD, placement -> placement + .hostState(new ResourceLocation("minecraft:stone"), 0))) + .build().toJson(); + provider.addProperty("manage_vanilla_ores", true); + String before = provider.toString(); + + Method geology = GeomeConfig.class.getDeclaredMethod("bake", JsonObject.class, ResourceLocation.class); + geology.setAccessible(true); + BakedGeomeConfig config = (BakedGeomeConfig) geology.invoke(null, new JsonObject(), WorldIds.OVERWORLD); + Method bake = OreSpawnOreGeneration.class.getDeclaredMethod("bakeOres", JsonObject.class, BakedGeomeConfig.class); + bake.setAccessible(true); + Object baked = bake.invoke(null, provider, config); + Field byDimension = baked.getClass().getDeclaredField("byDimension"); + byDimension.setAccessible(true); + Object[] rules = (Object[]) ((Map) byDimension.get(baked)).get(WorldIds.OVERWORLD); + assertEquals(1, rules.length); + Method accepts = rules[0].getClass().getDeclaredMethod("accepts", IBlockState.class, Random.class, BakedGeomeConfig.class); + accepts.setAccessible(true); + for (int metadata = 0; metadata <= 6; metadata++) { + assertEquals(metadata == 0, accepts.invoke(rules[0], Blocks.STONE.getStateFromMeta(metadata), new Random(1), config)); + } + assertEquals(before, provider.toString()); + } +}