diff --git a/build.gradle.kts b/build.gradle.kts index 84ae5cc..c243e15 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ plugins { `maven-publish` signing idea - id("net.minecraftforge.gradle").version("5.1.27") + id("net.minecraftforge.gradle").version("6.+") id("org.spongepowered.mixin").version("0.7-SNAPSHOT") id("com.github.johnrengelman.shadow").version("7.1.2") id("com.github.hierynomus.license").version("0.16.1") @@ -123,16 +123,20 @@ repositories { } } +legacy { + fixClasspath.set(true) + extractMappings.set(true) +} dependencies { minecraft(group = "net.minecraftforge", name = "forge", version = theForgeVersion) // provided by cubicchunks implementation - implementation("org.spongepowered:mixin:0.8.1-SNAPSHOT") { - isTransitive = false + implementation("org.spongepowered:mixin:0.8.3-SNAPSHOT") { + isTransitive = true } - implementation(fg.deobf("curse.maven:hackForMixinFMLAgent_deobfedDeps_-223896:2680892")) + compileOnly(fg.deobf("curse.maven:hackForMixinFMLAgent_deobfedDeps_-223896:2680892")) shade("com.flowpowered:flow-noise:1.0.1-SNAPSHOT") shade("org.spongepowered:noise:2.0.0-SNAPSHOT") @@ -256,7 +260,7 @@ tasks { } val sourcesJar by creating(Jar::class) { - classifier = "sources" + archiveClassifier.set("sources") from(sourceSets["main"].java.srcDirs) } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 69a9715..59bc51a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/asm/coremod/CubicGenCoreMod.java b/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/asm/coremod/CubicGenCoreMod.java index a86ea06..6fa3096 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/asm/coremod/CubicGenCoreMod.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/asm/coremod/CubicGenCoreMod.java @@ -52,12 +52,14 @@ public String[] getASMTransformerClass() { Mixins.addConfiguration("cubicgen.mixins.json"); if (System.getProperty("net.minecraftforge.gradle.GradleStart.srg.srg-mcp") != null) { return new String[]{ + "io.github.opencubicchunks.cubicchunks.cubicgen.asm.coremod.MapGenVillageCubicConstructorTransform", "io.github.opencubicchunks.cubicchunks.cubicgen.asm.coremod.MapGenStrongholdCubicConstructorTransform", // hack for FG5 dev environment - dependency ATs aren't applied at runtime "io.github.opencubicchunks.cubicchunks.cubicgen.asm.coremod.MalisisCoreAT" }; } else { return new String[]{ + "io.github.opencubicchunks.cubicchunks.cubicgen.asm.coremod.MapGenVillageCubicConstructorTransform", "io.github.opencubicchunks.cubicchunks.cubicgen.asm.coremod.MapGenStrongholdCubicConstructorTransform" }; } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/asm/coremod/MapGenVillageCubicConstructorTransform.java b/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/asm/coremod/MapGenVillageCubicConstructorTransform.java new file mode 100644 index 0000000..c2d835b --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/asm/coremod/MapGenVillageCubicConstructorTransform.java @@ -0,0 +1,116 @@ +/* + * This file is part of Cubic World Generation, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2020 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.cubicgen.asm.coremod; + +import io.github.opencubicchunks.cubicchunks.cubicgen.asm.Mappings; +import net.minecraft.launchwrapper.IClassTransformer; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; + +import java.util.List; + +public class MapGenVillageCubicConstructorTransform implements IClassTransformer { + private static final Logger LOGGER = LogManager.getLogger(); + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) { + if (basicClass == null) return null; + if ("net.minecraft.world.gen.structure.MapGenVillage$Start".equals(transformedName)) { + ClassReader cr = new ClassReader(basicClass); + ClassNode node = new ClassNode(); + cr.accept(node, 0); + applyTransform(node); + ClassWriter cw = new ClassWriter(0); + node.accept(cw); + return cw.toByteArray(); + } + return basicClass; + } + + private void applyTransform(ClassNode node) { + LOGGER.info("Transforming class {}: adding reinitCubicVillage method as copy of constructor", node.name); + String components = Mappings.getNameFromSrg("field_75075_a"); + String boundingBox = Mappings.getNameFromSrg("field_75074_b"); + LOGGER.debug("components field name: {}", components); + LOGGER.debug("boundingBox field name: {}", boundingBox); + + String structureStart = "net/minecraft/world/gen/structure/StructureStart"; + String structureBoundingBoxDesc = "Lnet/minecraft/world/gen/structure/StructureBoundingBox;"; + node.fields.add(new FieldNode(Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC, + "cubicchunks$baseY", Type.getDescriptor(int.class), null, 0)); + + MethodNode createdMethod = null; + for (MethodNode method : node.methods) { + LOGGER.debug("Checking method {}{}", method.name, method.desc); + if (method.name.equals("") && method.desc.equals("(Lnet/minecraft/world/World;Ljava/util/Random;III)V")) { + LOGGER.debug("Found target constructor: {}{}", method.name, method.desc); + MethodNode newMethod = new MethodNode(method.access, "reinitCubicVillage", + "(Lnet/minecraft/world/World;Ljava/util/Random;III)V", null, null); + MethodVisitor mv = new MethodVisitor(Opcodes.ASM5, newMethod) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + // note: none of these transformation require any stack map frames changes or maxs changes + // so they are not recomputed + if (opcode == Opcodes.INVOKESPECIAL && name.equals("") && owner.equals(structureStart)) { + LOGGER.debug("Replacing superconstructor call: {}{}", name, desc); + Type[] types = Type.getArgumentTypes(desc); + // remove superconstructor call, pop parameters + for (Type type : types) { + super.visitInsn(type.getSize() == 1 ? Opcodes.POP : Opcodes.POP2); + } + // keep "this" + // clear components + // no need to ALOAD 0, kept from superconstructor call + super.visitTypeInsn(Opcodes.CHECKCAST, structureStart); + super.visitFieldInsn(Opcodes.GETFIELD, structureStart, components, Type.getDescriptor(List.class)); + super.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.getInternalName(List.class), "clear", "()V", true); + // set bounding box to null + super.visitVarInsn(Opcodes.ALOAD, 0); + super.visitTypeInsn(Opcodes.CHECKCAST, structureStart); + super.visitInsn(Opcodes.ACONST_NULL); + super.visitFieldInsn(Opcodes.PUTFIELD, structureStart, boundingBox, structureBoundingBoxDesc); + } else { + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + } + }; + method.accept(mv); + createdMethod = newMethod; + break; + } + } + if (createdMethod == null) { + throw new RuntimeException("net.minecraft.world.gen.structure.MapGenVillage$Start constructor with descriptor " + + "(Lnet/minecraft/world/World;Ljava/util/Random;III)V not found! This should not be possible."); + } + node.methods.add(createdMethod); + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/asm/mixin/common/MixinVillageStart.java b/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/asm/mixin/common/MixinVillageStart.java new file mode 100644 index 0000000..d7e2055 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/asm/mixin/common/MixinVillageStart.java @@ -0,0 +1,69 @@ +/* + * This file is part of Cubic World Generation, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2020 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.cubicgen.asm.mixin.common; + +import io.github.opencubicchunks.cubicchunks.cubicgen.customcubic.structure.feature.CubicVillageGenerator; +import mcp.MethodsReturnNonnullByDefault; +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.MapGenVillage; +import net.minecraft.world.gen.structure.StructureStart; +import org.spongepowered.asm.mixin.Dynamic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Random; + +import javax.annotation.ParametersAreNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@Mixin(MapGenVillage.Start.class) +public abstract class MixinVillageStart extends StructureStart implements CubicVillageGenerator.CubicStart { + + @Unique private Random cubicWorldGen$constructorRandom; + + // added by class transformer (MapGenVillageCubicConstructorTransform) + + @SuppressWarnings("ShadowTarget") + @Dynamic + @Shadow(remap = false) + private void reinitCubicVillage(World world, Random random, int chunkX, int chunkZ, int size) { + throw new AssertionError(); + } + + @Inject(method = "(Lnet/minecraft/world/World;Ljava/util/Random;III)V", at = @At("RETURN")) + private void cubicChunksConstruct(World worldIn, Random random, int chunkX, int chunkZ, int villageSize, CallbackInfo ci) { + this.cubicWorldGen$constructorRandom = random; + } + + @Override + public void initCubicVillage(World world, int cubeY, int size) { + this.initCubic(world, cubeY); + this.reinitCubicVillage(world, cubicWorldGen$constructorRandom, getChunkPosX(), getChunkPosZ(), size); + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/customcubic/CustomTerrainGenerator.java b/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/customcubic/CustomTerrainGenerator.java index 7561be8..cefa1c1 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/customcubic/CustomTerrainGenerator.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/customcubic/CustomTerrainGenerator.java @@ -46,6 +46,7 @@ import io.github.opencubicchunks.cubicchunks.cubicgen.customcubic.structure.CubicCaveGenerator; import io.github.opencubicchunks.cubicchunks.cubicgen.customcubic.structure.CubicRavineGenerator; import io.github.opencubicchunks.cubicchunks.cubicgen.customcubic.structure.feature.CubicStrongholdGenerator; +import io.github.opencubicchunks.cubicchunks.cubicgen.customcubic.structure.feature.CubicVillageGenerator; import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; @@ -93,6 +94,7 @@ public class CustomTerrainGenerator extends BasicCubeGenerator { private ICubicStructureGenerator caveGenerator; private ICubicStructureGenerator ravineGenerator; private ICubicFeatureGenerator strongholds; + private ICubicFeatureGenerator villages; private IBiomeBlockReplacer[] replacers; @@ -126,15 +128,17 @@ private void init(World world, BiomeProvider biomeProvider, CustomGeneratorSetti } InitCubicStructureGeneratorEvent caveEvent = new InitCubicStructureGeneratorEvent(EventType.CAVE, new CubicCaveGenerator(), world); - InitCubicStructureGeneratorEvent strongholdsEvent = new InitCubicStructureGeneratorEvent( - EventType.STRONGHOLD, new CubicStrongholdGenerator(conf), world); + InitCubicStructureGeneratorEvent villagesEvent = new InitCubicStructureGeneratorEvent(EventType.VILLAGE, new CubicVillageGenerator(conf), world); + InitCubicStructureGeneratorEvent strongholdsEvent = new InitCubicStructureGeneratorEvent(EventType.STRONGHOLD, new CubicStrongholdGenerator(conf), world); InitCubicStructureGeneratorEvent ravineEvent = new InitCubicStructureGeneratorEvent(EventType.RAVINE, new CubicRavineGenerator(conf), world); MinecraftForge.TERRAIN_GEN_BUS.post(caveEvent); + MinecraftForge.TERRAIN_GEN_BUS.post(villagesEvent); MinecraftForge.TERRAIN_GEN_BUS.post(strongholdsEvent); MinecraftForge.TERRAIN_GEN_BUS.post(ravineEvent); this.caveGenerator = caveEvent.getNewGen(); + this.villages = (ICubicFeatureGenerator) villagesEvent.getNewGen(); this.strongholds = (CubicFeatureGenerator) strongholdsEvent.getNewGen(); this.ravineGenerator = ravineEvent.getNewGen(); @@ -276,21 +280,26 @@ private void fill3dBiomes(int cubeX, int cubeY, int cubeZ, CubePrimer primer) { Random rand = Coords.coordsSeedRandom(cube.getWorld().getSeed(), cube.getX(), cube.getY(), cube.getZ()); MinecraftForge.EVENT_BUS.post(new PopulateCubeEvent.Pre(world, rand, pos.getX(), pos.getY(), pos.getZ(), false)); + villages.generateStructure(world, rand, pos); strongholds.generateStructure(world, rand, pos); populators.get(cubicBiome.getBiome()).generate(world, rand, pos, cubicBiome.getBiome()); - MinecraftForge.EVENT_BUS.post(new PopulateCubeEvent.Post(world, rand, pos.getX(), pos.getY(), pos.getZ(), false)); + MinecraftForge.EVENT_BUS.post(new PopulateCubeEvent.Post(world, rand, pos.getX(), pos.getY(), pos.getZ(), true)); CubeGeneratorsRegistry.generateWorld(world, rand, pos, cubicBiome.getBiome()); } } @Override public void recreateStructures(ICube cube) { + this.villages.generate(world, null, cube.getCoords()); this.strongholds.generate(world, null, cube.getCoords()); } @Nullable @Override public BlockPos getClosestStructure(String name, BlockPos pos, boolean findUnexplored) { if ("Stronghold".equals(name)) { - return strongholds.getNearestStructurePos((World) world, pos, true); + return strongholds.getNearestStructurePos(world, pos, true); + } + if ("Village".equals(name)) { + return villages.getNearestStructurePos(world, pos, true); } return null; } @@ -351,6 +360,9 @@ public void generateStructures(CubePrimer cube, CubePos cubePos) { if (this.conf.ravines) { this.ravineGenerator.generate(world, cube, cubePos); } + if(this.conf.villages) { + this.villages.generate(world, cube, cubePos); + } if (this.conf.strongholds) { this.strongholds.generate(world, cube, cubePos); } @@ -368,6 +380,10 @@ public final ICubicStructureGenerator getRavineGenerator() { return ravineGenerator; } + public final ICubicFeatureGenerator getVillages() { + return villages; + } + public CustomGeneratorSettings getConfig() { return conf; } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/customcubic/structure/feature/CubicVillageGenerator.java b/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/customcubic/structure/feature/CubicVillageGenerator.java new file mode 100644 index 0000000..a2fa3eb --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/cubicgen/customcubic/structure/feature/CubicVillageGenerator.java @@ -0,0 +1,174 @@ +/* + * This file is part of Cubic World Generation, licensed under the MIT License (MIT). + * + * Copyright (c) 2015-2020 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.github.opencubicchunks.cubicchunks.cubicgen.customcubic.structure.feature; + +import io.github.opencubicchunks.cubicchunks.api.util.CubePos; +import io.github.opencubicchunks.cubicchunks.api.worldgen.structure.feature.CubicFeatureGenerator; +import io.github.opencubicchunks.cubicchunks.api.worldgen.structure.feature.ICubicFeatureStart; +import io.github.opencubicchunks.cubicchunks.cubicgen.customcubic.CustomGeneratorSettings; +import mcp.MethodsReturnNonnullByDefault; +import net.minecraft.init.Biomes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.MapGenBase; +import net.minecraft.world.gen.structure.MapGenVillage; +import net.minecraft.world.gen.structure.StructureStart; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import static io.github.opencubicchunks.cubicchunks.api.util.Coords.cubeToCenterBlock; + +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public class CubicVillageGenerator extends CubicFeatureGenerator { + + public static List VILLAGE_SPAWN_BIOMES = Arrays.asList(Biomes.PLAINS, Biomes.DESERT, Biomes.SAVANNA, Biomes.TAIGA); + private int size; + private int distance; + private final CustomGeneratorSettings conf; + private final int minTownSeparation; + + public CubicVillageGenerator(CustomGeneratorSettings conf) { + super(2, 0); + this.conf = conf; + this.distance = 32; + this.minTownSeparation = 8; + + } + + public CubicVillageGenerator(CustomGeneratorSettings conf, Map map) { + this(conf); + + for (Map.Entry entry : map.entrySet()) { + if (entry.getKey().equals("size")) { + this.size = MathHelper.getInt(entry.getValue(), this.size, 0); + } else if (entry.getKey().equals("distance")) { + this.distance = MathHelper.getInt(entry.getValue(), this.distance, 9); + } + } + } + + @Override + public String getStructureName() { + return "Village"; + } + + @Nullable + @Override + public BlockPos getNearestStructurePos(World world, BlockPos startPos, boolean findUnexplored) { + int distanceStep = this.distance; + + int i = startPos.getX() >> 4; + int j = startPos.getZ() >> 4; + int k = 0; + + for (Random random = new Random(); k <= 100; ++k) { + for (int l = -k; l <= k; ++l) { + boolean flag = l == -k || l == k; + + for (int i1 = -k; i1 <= k; ++i1) { + boolean flag1 = i1 == -k || i1 == k; + + if (flag || flag1) { + int j1 = i + distanceStep * l; + int k1 = j + distanceStep * i1; + + if (j1 < 0) { + j1 -= distanceStep - 1; + } + + if (k1 < 0) { + k1 -= distanceStep - 1; + } + + int l1 = j1 / distanceStep; + int i2 = k1 / distanceStep; + Random random1 = world.setRandomSeed(l1, i2, 10387312); + l1 = l1 * distanceStep; + i2 = i2 * distanceStep; + + l1 = l1 + random1.nextInt(distanceStep - 8); + i2 = i2 + random1.nextInt(distanceStep - 8); + + MapGenBase.setupChunkSeed(world.getSeed(), random, l1, i2); + random.nextInt(); + + if (this.canSpawnStructureAtCoords(world, random, l1, 64, i2)) { + return new BlockPos(cubeToCenterBlock(l1), 64, cubeToCenterBlock(i2)); + } else if (k == 0) { + break; + } + } + } + + if (k == 0) { + break; + } + } + } + return null; + } + + @Override + protected boolean canSpawnStructureAtCoords(World world, Random rand, int chunkX, int chunkY, int chunkZ) { + int i = chunkX; + int j = chunkZ; + + if (chunkX < 0) { + chunkX -= this.distance - 1; + } + + if (chunkZ < 0) { + chunkZ -= this.distance - 1; + } + + int k = chunkX + rand.nextInt(this.distance - 8); + int l = chunkZ + rand.nextInt(this.distance - 8); + + if (i == k && j == l) { + return world.getBiomeProvider().areBiomesViable(cubeToCenterBlock(i), cubeToCenterBlock(j), 0, VILLAGE_SPAWN_BIOMES); + } + + return false; + } + + @Override + protected StructureStart getStructureStart(World world, Random rand, int chunkX, int chunkY, int chunkZ) { + StructureStart start = new MapGenVillage.Start(world, rand, chunkX, chunkZ, this.size); + CubicStart cubic = (CubicStart) start; + cubic.initCubicVillage(world, chunkY, this.size); + return start; + } + + public interface CubicStart extends ICubicFeatureStart { + void initCubicVillage(World world, int cubeY, int size); + } +} diff --git a/src/main/resources/cubicgen.mixins.json b/src/main/resources/cubicgen.mixins.json index 514f166..372d1bc 100644 --- a/src/main/resources/cubicgen.mixins.json +++ b/src/main/resources/cubicgen.mixins.json @@ -12,6 +12,12 @@ "conformVisibility": true }, "mixins": [ + "common.IUIContainer", + "common.MixinSaveHandler", + "common.MixinStrongholdStart", + "common.MixinUIComponent", + "common.MixinVillageStart", + "common.MixinWorldInfo", "common.accessor.IBiome", "common.accessor.IBiomeForest", "common.accessor.IBiomeMesa", @@ -20,12 +26,7 @@ "common.accessor.IBiomeSnow", "common.accessor.IBiomeTaiga", "common.accessor.INoiseGeneratorImproved", - "common.extras.FarLands", - "common.IUIContainer", - "common.MixinSaveHandler", - "common.MixinStrongholdStart", - "common.MixinUIComponent", - "common.MixinWorldInfo" + "common.extras.FarLands" ], "client": [], "server": []