diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/ListFeature.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/features/ListFeature.java deleted file mode 100644 index 629fb041..00000000 --- a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/ListFeature.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.betterx.bclib.api.v2.levelgen.features; - -import net.minecraft.core.BlockPos; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.WorldGenLevel; -import net.minecraft.world.level.block.Mirror; -import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; - -import org.betterx.bclib.util.StructureHelper; - -import java.util.List; - -public class ListFeature extends NBTFeature { - private final List list; - private StructureInfo selected; - - public ListFeature(List list, BlockState defaultBlock) { - super(defaultBlock); - this.list = list; - } - - @Override - protected StructureTemplate getStructure(WorldGenLevel world, BlockPos pos, RandomSource random) { - selected = list.get(random.nextInt(list.size())); - return selected.getStructure(); - } - - @Override - protected boolean canSpawn(WorldGenLevel world, BlockPos pos, RandomSource random) { - int cx = pos.getX() >> 4; - int cz = pos.getZ() >> 4; - return ((cx + cz) & 1) == 0 && pos.getY() > 58;// && world.getBlockState(pos.below()).is(EndTags.GEN_TERRAIN); - } - - @Override - protected Rotation getRotation(WorldGenLevel world, BlockPos pos, RandomSource random) { - return Rotation.getRandom(random); - } - - @Override - protected Mirror getMirror(WorldGenLevel world, BlockPos pos, RandomSource random) { - return Mirror.values()[random.nextInt(3)]; - } - - @Override - protected int getYOffset(StructureTemplate structure, WorldGenLevel world, BlockPos pos, RandomSource random) { - return selected.offsetY; - } - - @Override - protected TerrainMerge getTerrainMerge(WorldGenLevel world, BlockPos pos, RandomSource random) { - return selected.terrainMerge; - } - - @Override - protected void addStructureData(StructurePlaceSettings data) { - } - - public static final class StructureInfo { - public final TerrainMerge terrainMerge; - public final String structurePath; - public final int offsetY; - - private StructureTemplate structure; - - public StructureInfo(String structurePath, int offsetY, TerrainMerge terrainMerge) { - this.terrainMerge = terrainMerge; - this.structurePath = structurePath; - this.offsetY = offsetY; - } - - public StructureTemplate getStructure() { - if (structure == null) { - structure = StructureHelper.readStructure(structurePath); - } - return structure; - } - } -} diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/NBTFeature.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/features/NBTFeature.java deleted file mode 100644 index 92c09cbc..00000000 --- a/src/main/java/org/betterx/bclib/api/v2/levelgen/features/NBTFeature.java +++ /dev/null @@ -1,235 +0,0 @@ -package org.betterx.bclib.api.v2.levelgen.features; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.BlockPos.MutableBlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Holder; -import net.minecraft.core.Vec3i; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtIo; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.WorldGenLevel; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Mirror; -import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; -import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; -import net.minecraft.world.level.levelgen.structure.BoundingBox; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; - -import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI; -import org.betterx.bclib.api.v2.levelgen.structures.templatesystem.DestructionStructureProcessor; -import org.betterx.bclib.api.v2.tag.CommonBlockTags; -import org.betterx.bclib.util.BlocksHelper; - -import java.io.IOException; -import java.io.InputStream; - -//TODO: 1.19 Check if we can merge this with the new TemplateFeature! -public abstract class NBTFeature extends DefaultFeature { - private final BlockState defaultBlock; - - public NBTFeature(BlockState defaultBlock) { - this.defaultBlock = defaultBlock; - } - - protected static final DestructionStructureProcessor DESTRUCTION = new DestructionStructureProcessor(); - - protected abstract StructureTemplate getStructure(WorldGenLevel world, BlockPos pos, RandomSource random); - - protected abstract boolean canSpawn(WorldGenLevel world, BlockPos pos, RandomSource random); - - protected abstract Rotation getRotation(WorldGenLevel world, BlockPos pos, RandomSource random); - - protected abstract Mirror getMirror(WorldGenLevel world, BlockPos pos, RandomSource random); - - protected abstract int getYOffset(StructureTemplate structure, - WorldGenLevel world, - BlockPos pos, - RandomSource random); - - protected abstract TerrainMerge getTerrainMerge(WorldGenLevel world, BlockPos pos, RandomSource random); - - protected abstract void addStructureData(StructurePlaceSettings data); - - protected BlockPos getGround(WorldGenLevel world, BlockPos center) { - Holder biome = world.getBiome(center); - ResourceLocation id = BiomeAPI.getBiomeID(biome); - if (id.getNamespace().contains("moutain") || id.getNamespace().contains("lake")) { - int y = getAverageY(world, center); - return new BlockPos(center.getX(), y, center.getZ()); - } else { - int y = getAverageYWG(world, center); - return new BlockPos(center.getX(), y, center.getZ()); - } - } - - protected int getAverageY(WorldGenLevel world, BlockPos center) { - int y = getYOnSurface(world, center.getX(), center.getZ()); - y += getYOnSurface(world, center.getX() - 2, center.getZ() - 2); - y += getYOnSurface(world, center.getX() + 2, center.getZ() - 2); - y += getYOnSurface(world, center.getX() - 2, center.getZ() + 2); - y += getYOnSurface(world, center.getX() + 2, center.getZ() + 2); - return y / 5; - } - - protected int getAverageYWG(WorldGenLevel world, BlockPos center) { - int y = getYOnSurfaceWG(world, center.getX(), center.getZ()); - y += getYOnSurfaceWG(world, center.getX() - 2, center.getZ() - 2); - y += getYOnSurfaceWG(world, center.getX() + 2, center.getZ() - 2); - y += getYOnSurfaceWG(world, center.getX() - 2, center.getZ() + 2); - y += getYOnSurfaceWG(world, center.getX() + 2, center.getZ() + 2); - return y / 5; - } - - @Override - public boolean place(FeaturePlaceContext context) { - WorldGenLevel world = context.level(); - RandomSource random = context.random(); - BlockPos center = context.origin(); - - center = new BlockPos(((center.getX() >> 4) << 4) | 8, 128, ((center.getZ() >> 4) << 4) | 8); - center = getGround(world, center); - - if (!canSpawn(world, center, random)) { - return false; - } - - int posY = center.getY() + 1; - StructureTemplate structure = getStructure(world, center, random); - Rotation rotation = getRotation(world, center, random); - Mirror mirror = getMirror(world, center, random); - BlockPos offset = StructureTemplate.transform( - new BlockPos(structure.getSize()), - mirror, - rotation, - BlockPos.ZERO - ); - center = center.offset(0, getYOffset(structure, world, center, random) + 0.5, 0); - - BoundingBox bounds = makeBox(center); - StructurePlaceSettings placementData = new StructurePlaceSettings() - .setRotation(rotation) - .setMirror(mirror) - .setBoundingBox(bounds); - addStructureData(placementData); - center = center.offset(-offset.getX() * 0.5, 0, -offset.getZ() * 0.5); - structure.placeInWorld(world, center, center, placementData, random, 4); - - TerrainMerge merge = getTerrainMerge(world, center, random); - int x1 = center.getX(); - int z1 = center.getZ(); - int x2 = x1 + offset.getX(); - int z2 = z1 + offset.getZ(); - if (merge != TerrainMerge.NONE) { - MutableBlockPos mut = new MutableBlockPos(); - - if (x2 < x1) { - int a = x1; - x1 = x2; - x2 = a; - } - - if (z2 < z1) { - int a = z1; - z1 = z2; - z2 = a; - } - - int surfMax = posY - 1; - for (int x = x1; x <= x2; x++) { - mut.setX(x); - for (int z = z1; z <= z2; z++) { - mut.setZ(z); - mut.setY(surfMax); - BlockState state = world.getBlockState(mut); - if (!isTerrain(state) && state.isFaceSturdy(world, mut, Direction.DOWN)) { - for (int i = 0; i < 10; i++) { - mut.setY(mut.getY() - 1); - BlockState stateSt = world.getBlockState(mut); - if (!isTerrain(stateSt)) { - if (merge == TerrainMerge.SURFACE) { - boolean isTop = mut.getY() == surfMax && state.getMaterial().isSolidBlocking(); - Holder b = world.getBiome(mut); - BlockState top = (isTop - ? BiomeAPI.findTopMaterial(b) - : BiomeAPI.findUnderMaterial(b)).orElse(defaultBlock); - BlocksHelper.setWithoutUpdate(world, mut, top); - } else { - BlocksHelper.setWithoutUpdate(world, mut, state); - } - } else { - if (isTerrain(state) && state.getMaterial().isSolidBlocking()) { - if (merge == TerrainMerge.SURFACE) { - Holder b = world.getBiome(mut); - BlockState bottom = BiomeAPI.findUnderMaterial(b).orElse(defaultBlock); - BlocksHelper.setWithoutUpdate(world, mut, bottom); - } else { - BlocksHelper.setWithoutUpdate(world, mut, state); - } - } - break; - } - } - } - } - } - } - //BlocksHelper.fixBlocks(world, new BlockPos(x1, center.getY(), z1), new BlockPos(x2, center.getY() + offset.getY(), z2)); - - return true; - } - - private boolean isTerrain(BlockState state) { - return state.is(CommonBlockTags.END_STONES) || state.is(CommonBlockTags.NETHER_STONES); - } - - protected BoundingBox makeBox(BlockPos pos) { - int sx = ((pos.getX() >> 4) << 4) - 16; - int sz = ((pos.getZ() >> 4) << 4) - 16; - int ex = sx + 47; - int ez = sz + 47; - return BoundingBox.fromCorners(new Vec3i(sx, 0, sz), new Vec3i(ex, 255, ez)); - } - - protected static StructureTemplate readStructure(ResourceLocation resource) { - String ns = resource.getNamespace(); - String nm = resource.getPath(); - - try { - InputStream inputstream = MinecraftServer.class.getResourceAsStream("/data/" + ns + "/structures/" + nm + ".nbt"); - return readStructureFromStream(inputstream); - } catch (IOException e) { - e.printStackTrace(); - } - - return null; - } - - private static StructureTemplate readStructureFromStream(InputStream stream) throws IOException { - CompoundTag nbttagcompound = NbtIo.readCompressed(stream); - - StructureTemplate template = new StructureTemplate(); - template.load(nbttagcompound); - - return template; - } - - public enum TerrainMerge { - NONE, SURFACE, OBJECT; - - public static TerrainMerge getFromString(String type) { - if (type.equals("surface")) { - return SURFACE; - } else if (type.equals("object")) { - return OBJECT; - } else { - return NONE; - } - } - } -} diff --git a/src/main/java/org/betterx/bclib/interfaces/LootPoolAccessor.java b/src/main/java/org/betterx/bclib/interfaces/LootPoolAccessor.java new file mode 100644 index 00000000..01e2838d --- /dev/null +++ b/src/main/java/org/betterx/bclib/interfaces/LootPoolAccessor.java @@ -0,0 +1,10 @@ +package org.betterx.bclib.interfaces; + +import net.minecraft.world.level.storage.loot.LootPool; +import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer; + +import java.util.List; + +public interface LootPoolAccessor { + LootPool bcl_mergeEntries(List newEntries); +} diff --git a/src/main/java/org/betterx/bclib/mixin/common/LootPoolMixin.java b/src/main/java/org/betterx/bclib/mixin/common/LootPoolMixin.java new file mode 100644 index 00000000..bc47a725 --- /dev/null +++ b/src/main/java/org/betterx/bclib/mixin/common/LootPoolMixin.java @@ -0,0 +1,56 @@ +package org.betterx.bclib.mixin.common; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.LootPool; +import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer; +import net.minecraft.world.level.storage.loot.functions.LootItemFunction; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import net.minecraft.world.level.storage.loot.providers.number.NumberProvider; + +import com.google.common.collect.Lists; +import org.betterx.bclib.interfaces.LootPoolAccessor; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Predicate; + +@Mixin(LootPool.class) +public class LootPoolMixin implements LootPoolAccessor { + @Shadow + @Final + public LootPoolEntryContainer[] entries; + @Shadow + @Final + public LootItemCondition[] conditions; + @Shadow + @Final + private Predicate compositeCondition; + @Shadow + @Final + public LootItemFunction[] functions; + @Shadow + @Final + private BiFunction compositeFunction; + @Shadow + @Final + public NumberProvider rolls; + @Shadow + @Final + public NumberProvider bonusRolls; + + @Override + public LootPool bcl_mergeEntries(List newEntries) { + final List merged = Lists.newArrayList(entries); + merged.addAll(newEntries); + + return new LootPool(merged.toArray(new LootPoolEntryContainer[0]), + this.conditions, + this.functions, + this.rolls, + this.bonusRolls); + } +} diff --git a/src/main/java/org/betterx/bclib/util/LootUtil.java b/src/main/java/org/betterx/bclib/util/LootUtil.java index 04ea0634..08af407b 100644 --- a/src/main/java/org/betterx/bclib/util/LootUtil.java +++ b/src/main/java/org/betterx/bclib/util/LootUtil.java @@ -7,10 +7,17 @@ import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.storage.loot.BuiltInLootTables; import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.LootPool; import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import org.betterx.bclib.BCLib; +import org.betterx.bclib.interfaces.LootPoolAccessor; + +import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -31,4 +38,36 @@ public class LootUtil { if (table == LootTable.EMPTY) return Optional.empty(); return Optional.of(table.getRandomItems(ctx)); } + + public static boolean addToPool(LootTable.Builder table, int index, ArrayList newEntries) { + List pools = new ArrayList<>(0); + try { + for (Field f : table.getClass() + .getDeclaredFields()) { + if (List.class.isAssignableFrom(f.getType())) { + f.setAccessible(true); + List list = (List) f.get(table); + if (list != null && list.size() > 0) { + Object first = list.get(0); + if (first != null && LootPool.class.isAssignableFrom(first.getClass())) { + pools = (List) list; + break; + } + } + } + } + + if (pools != null && pools.size() > index) { + LootPool pool = pools.get(index); + LootPoolAccessor acc = (LootPoolAccessor) pool; + pools.set(index, acc.bcl_mergeEntries(newEntries)); + + return true; + } + } catch (Throwable t) { + BCLib.LOGGER.error("ERROR building loot table: " + t.getMessage()); + } + + return false; + } } diff --git a/src/main/resources/bclib.accesswidener b/src/main/resources/bclib.accesswidener index 37195b58..7ce04adb 100644 --- a/src/main/resources/bclib.accesswidener +++ b/src/main/resources/bclib.accesswidener @@ -12,4 +12,5 @@ accessible class net/minecraft/world/level/levelgen/presets/WorldPresets$Boot extendable class net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator #Methods -accessible method net/minecraft/client/gui/screens/worldselection/WorldGenSettingsComponent updateSettings (Lnet/minecraft/client/gui/screens/worldselection/WorldCreationContext$Updater;)V \ No newline at end of file +accessible method net/minecraft/client/gui/screens/worldselection/WorldGenSettingsComponent updateSettings (Lnet/minecraft/client/gui/screens/worldselection/WorldCreationContext$Updater;)V +accessible method net/minecraft/world/level/storage/loot/LootPool ([Lnet/minecraft/world/level/storage/loot/entries/LootPoolEntryContainer;[Lnet/minecraft/world/level/storage/loot/predicates/LootItemCondition;[Lnet/minecraft/world/level/storage/loot/functions/LootItemFunction;Lnet/minecraft/world/level/storage/loot/providers/number/NumberProvider;Lnet/minecraft/world/level/storage/loot/providers/number/NumberProvider;)V \ No newline at end of file diff --git a/src/main/resources/bclib.mixins.common.json b/src/main/resources/bclib.mixins.common.json index cf2ac888..49b27c46 100644 --- a/src/main/resources/bclib.mixins.common.json +++ b/src/main/resources/bclib.mixins.common.json @@ -20,6 +20,7 @@ "EnchantingTableBlockMixin", "ItemStackMixin", "LayerLightSectionStorageMixin", + "LootPoolMixin", "MainMixin", "MinecraftServerMixin", "MobSpawnSettingsAccessor",