This commit is contained in:
Zoë
2022-07-12 18:46:32 -07:00
parent 5c2998c91c
commit dd9f421972
19 changed files with 221 additions and 238 deletions

View File

@@ -1,17 +0,0 @@
package com.dfsek.terra.fabric;
import net.gudenau.minecraft.asm.api.v1.AsmInitializer;
import net.gudenau.minecraft.asm.api.v1.AsmRegistry;
import com.dfsek.terra.fabric.util.FabricLoaderUtil;
import com.dfsek.terra.lifecycle.asm.FertilizableASM;
import com.dfsek.terra.lifecycle.util.LoaderUtil;
public class FabricASMEntryPoint implements AsmInitializer {
@Override
public void onInitializeAsm() {
LoaderUtil.INSTANCE = new FabricLoaderUtil();
AsmRegistry.getInstance().registerTransformer(new FertilizableASM());
}
}

View File

@@ -1,18 +0,0 @@
package com.dfsek.terra.fabric.util;
import com.dfsek.terra.lifecycle.util.LoaderUtil;
import net.fabricmc.loader.api.FabricLoader;
public class FabricLoaderUtil extends LoaderUtil {
@Override
public String mapClassName(String namespace, String className) {
return FabricLoader.getInstance().getMappingResolver().mapClassName(namespace, className);
}
@Override
public String mapMethodName(String namespace, String owner, String name, String descriptor) {
return FabricLoader.getInstance().getMappingResolver().mapMethodName(namespace, owner, name, descriptor);
}
}

View File

@@ -18,9 +18,6 @@
"entrypoints": {
"main": [
"com.dfsek.terra.fabric.FabricEntryPoint"
],
"gud_asm": [
"com.dfsek.terra.fabric.FabricASMEntryPoint"
]
},
"mixins": [

View File

@@ -37,6 +37,7 @@ import com.dfsek.terra.mod.config.BiomeAdditionsSoundTemplate;
import com.dfsek.terra.mod.config.BiomeMoodSoundTemplate;
import com.dfsek.terra.mod.config.BiomeParticleConfigTemplate;
import com.dfsek.terra.mod.config.EntityTypeTemplate;
import com.dfsek.terra.mod.config.FertilizableConfig;
import com.dfsek.terra.mod.config.MusicSoundTemplate;
import com.dfsek.terra.mod.config.ProtoPlatformBiome;
import com.dfsek.terra.mod.config.SoundEventTemplate;
@@ -95,7 +96,8 @@ public abstract class ModPlatform extends AbstractPlatform {
.registerLoader(SpawnEntry.class, SpawnEntryTemplate::new)
.registerLoader(SpawnTypeConfig.class, SpawnTypeConfig::new)
.registerLoader(SpawnSettings.class, SpawnSettingsTemplate::new)
.registerLoader(VillagerType.class, VillagerTypeTemplate::new);
.registerLoader(VillagerType.class, VillagerTypeTemplate::new)
.registerLoader(FertilizableConfig.class, FertilizableConfig::new);
}
private ProtoPlatformBiome parseBiome(String id, DepthTracker tracker) throws LoadException {

View File

@@ -0,0 +1,51 @@
package com.dfsek.terra.mod.config;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import net.minecraft.util.Identifier;
import java.util.Map;
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class FertilizableConfig implements ObjectTemplate<FertilizableConfig> {
@Value("strucutres")
@Default
private ProbabilityCollection<ConfiguredStructure> structures = null;
@Value("cooldowns")
@Default
private Map<Identifier, Double> cooldowns = null;
@Value("can-grow")
@Default
private ConfiguredStructure canGrow = null;
@Value("villager-fertilizable")
@Default
private Boolean villagerFertilizable = null;
public ProbabilityCollection<ConfiguredStructure> getStructures() {
return structures;
}
public Map<Identifier, Double> getCooldowns() {
return cooldowns;
}
public ConfiguredStructure getCanGrow() {
return canGrow;
}
public Boolean isVillagerFertilizable() {
return villagerFertilizable;
}
@Override
public FertilizableConfig get() {
return this;
}
}

View File

@@ -20,15 +20,13 @@ import java.util.List;
import java.util.Map;
import com.dfsek.terra.api.properties.Properties;
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class VanillaBiomeProperties implements ConfigTemplate, Properties {
@Value("minecraft.fertilizables")
@Default
private Map<Identifier, ProbabilityCollection<ConfiguredStructure>> fertilizables = Collections.emptyMap();
private Map<Identifier, FertilizableConfig> fertilizables = Collections.emptyMap();
@Value("minecraft.tags")
@Default
@@ -106,7 +104,7 @@ public class VanillaBiomeProperties implements ConfigTemplate, Properties {
@Default
private VillagerType villagerType = null;
public Map<Identifier, ProbabilityCollection<ConfiguredStructure>> getFertilizables() {
public Map<Identifier, FertilizableConfig> getFertilizables() {
return fertilizables;
}

View File

@@ -19,7 +19,7 @@ import com.dfsek.terra.mod.CommonPlatform;
MoveToHiveGoal.class,
MoveToFlowerGoal.class
})
public class BeeMoveGoalsUnsynchronizedRandomAccessFix {
public class BeeMoveGoalsUnsynchronizedRandomAccessFixMixin {
@Redirect(method = "<init>",
at = @At(value = "FIELD", target = "Lnet/minecraft/world/World;random:Lnet/minecraft/util/math/random/Random;"))
public Random redirectRandomAccess(World instance) {

View File

@@ -20,7 +20,7 @@ import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper;
* nether.
*/
@Mixin(NetherFossilStructure.class)
public class NetherFossilOptimization {
public class NetherFossilOptimizationMixin {
@Inject(method = "getStructurePosition", at = @At("HEAD"), cancellable = true)
public void injectFossilPositions(Context context, CallbackInfoReturnable<Optional<StructurePosition>> cir) {
if(context.chunkGenerator() instanceof MinecraftChunkGeneratorWrapper) {

View File

@@ -0,0 +1,32 @@
package com.dfsek.terra.mod.mixin.gameplay;
import net.minecraft.item.BoneMealItem;
import net.minecraft.item.ItemStack;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.dfsek.terra.mod.util.FertilizableUtil;
@Mixin(BoneMealItem.class)
public class BoneMealItemMixin {
private static final Identifier cooldownId = new Identifier("terra", "bone_meal_cooldown");
@Inject(method = "useOnFertilizable", at = @At("HEAD"), cancellable = true)
private static void injectUseOnFertilizable(ItemStack stack, World world, BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
if(world instanceof ServerWorld) {
Boolean value = FertilizableUtil.grow((ServerWorld) world, pos, world.getBlockState(pos), cooldownId);
stack.decrement(1);
if(value != null) {
cir.setReturnValue(value);
}
}
}
}

View File

@@ -0,0 +1,57 @@
package com.dfsek.terra.mod.mixin.gameplay;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.ai.brain.task.BoneMealTask;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Map;
import java.util.Random;
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
import com.dfsek.terra.api.util.Rotation;
import com.dfsek.terra.api.util.vector.Vector3Int;
import com.dfsek.terra.api.world.WritableWorld;
import com.dfsek.terra.mod.config.FertilizableConfig;
import com.dfsek.terra.mod.util.BiomeUtil;
@Mixin(BoneMealTask.class)
public class BoneMealTaskMixin {
@Inject(method = "canBoneMeal", at = @At("HEAD"), cancellable = true)
public void injectCanBoneMeal(BlockPos pos, ServerWorld world, CallbackInfoReturnable<Boolean> cir) {
Map<Identifier, FertilizableConfig> map = BiomeUtil.TERRA_BIOME_FERTILIZABLE_MAP.get(world.getBiome(pos));
if(map != null) {
BlockState blockState = world.getBlockState(pos);
Block block = blockState.getBlock();
FertilizableConfig config = map.get(Registry.BLOCK.getId(block));
if(config != null) {
Boolean villagerFertilizable = config.isVillagerFertilizable();
if(villagerFertilizable != null) {
if(villagerFertilizable) {
ConfiguredStructure canGrow = config.getCanGrow();
if(canGrow != null) {
Random random = (Random) world.getRandom();
cir.setReturnValue(canGrow.getStructure().get(random).generate(
Vector3Int.of(pos.getX(), pos.getY(), pos.getZ()), (WritableWorld) world, random, Rotation.NONE));
return;
}
cir.setReturnValue(true);
return;
}
cir.setReturnValue(false);
return;
}
}
}
}
}

View File

@@ -0,0 +1,32 @@
package com.dfsek.terra.mod.mixin.gameplay;
import net.minecraft.block.BlockState;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import com.dfsek.terra.mod.util.FertilizableUtil;
@Mixin(ServerWorld.class)
public class ServerWorldMixin {
private static final Identifier cooldownId = new Identifier("terra", "random_cooldown");
@Redirect(method = "tickChunk",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/block/BlockState;randomTick(Lnet/minecraft/server/world/ServerWorld;" +
"Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/random/Random;)V"))
public void injectTickChunk(BlockState instance, ServerWorld serverWorld, BlockPos blockPos, Random random) {
Boolean value = FertilizableUtil.grow(serverWorld, blockPos, instance, cooldownId);
if(value != null) {
if(!value) {
instance.randomTick(serverWorld, blockPos, random);
}
}
}
}

View File

@@ -17,10 +17,9 @@ import java.util.Map;
import java.util.Objects;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.mod.CommonPlatform;
import com.dfsek.terra.mod.config.FertilizableConfig;
import com.dfsek.terra.mod.config.ProtoPlatformBiome;
import com.dfsek.terra.mod.config.VanillaBiomeProperties;
import com.dfsek.terra.mod.mixin.access.VillagerTypeAccessor;
@@ -29,7 +28,7 @@ import com.dfsek.terra.mod.mixin.access.VillagerTypeAccessor;
public class BiomeUtil {
private static final Logger logger = LoggerFactory.getLogger(BiomeUtil.class);
public static final Map<RegistryEntry<net.minecraft.world.biome.Biome>, Map<Identifier, ProbabilityCollection<ConfiguredStructure>>>
public static final Map<RegistryEntry<net.minecraft.world.biome.Biome>, Map<Identifier, FertilizableConfig>>
TERRA_BIOME_FERTILIZABLE_MAP = new HashMap<>();
public static final Map<TagKey<net.minecraft.world.biome.Biome>, List<Identifier>>

View File

@@ -1,34 +1,54 @@
package com.dfsek.terra.mod.util;
import com.dfsek.terra.api.util.Rotation;
import com.dfsek.terra.api.util.vector.Vector3Int;
import com.dfsek.terra.api.world.WritableWorld;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.util.registry.Registry;
import java.util.Map;
import java.util.Random;
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.Rotation;
import com.dfsek.terra.api.util.vector.Vector3Int;
import com.dfsek.terra.api.world.WritableWorld;
import com.dfsek.terra.mod.config.FertilizableConfig;
public class FertilizableUtil {
public static boolean grow(ServerWorld world, Random random, BlockPos pos, BlockState state) {
Map<Identifier, ProbabilityCollection<ConfiguredStructure>> fertilizables = BiomeUtil.TERRA_BIOME_FERTILIZABLE_MAP.get(world.getBiome(pos));
if (fertilizables != null) {
ProbabilityCollection<ConfiguredStructure> probabilityCollection = fertilizables.get(Registry.BLOCK.getId(state.getBlock()));
if (probabilityCollection != null) {
ConfiguredStructure structure = probabilityCollection.get((java.util.Random) random);
structure.getStructure().get((java.util.Random) random).generate(Vector3Int.of(pos.getX(), pos.getY(), pos.getZ()), (WritableWorld) world, (java.util.Random) random, Rotation.NONE);
private static final Random mojankRandom = new Random();
public static Boolean grow(ServerWorld world, BlockPos pos, BlockState state, Identifier cooldownId) {
return grow(world, mojankRandom, pos, state, cooldownId);
}
public static Boolean grow(ServerWorld world, Random random, BlockPos pos, BlockState state, Identifier cooldownId) {
Map<Identifier, FertilizableConfig> map = BiomeUtil.TERRA_BIOME_FERTILIZABLE_MAP.get(world.getBiome(pos));
if(map != null) {
Block block = state.getBlock();
FertilizableConfig config = map.get(Registry.BLOCK.getId(block));
if(config != null) {
ConfiguredStructure canGrow = config.getCanGrow();
if(canGrow != null) {
if(!canGrow.getStructure().get(random).generate(
Vector3Int.of(pos.getX(), pos.getY(), pos.getZ()), (WritableWorld) world, random, Rotation.NONE)) {
return false;
}
}
Double cooldown = config.getCooldowns().get(cooldownId);
if(cooldown != null) {
if(random.nextFloat() > cooldown) {
return true;
}
}
config.getStructures().get(random).getStructure().get(random).generate(
Vector3Int.of(pos.getX(), pos.getY(), pos.getZ()), (WritableWorld) world, random, Rotation.NONE);
return true;
}
}
return false;
return null;
}
}

View File

@@ -9,8 +9,11 @@
"access.StateAccessor",
"access.StructureAccessorAccessor",
"access.VillagerTypeAccessor",
"fix.BeeMoveGoalsUnsynchronizedRandomAccessFix",
"fix.NetherFossilOptimization",
"fix.BeeMoveGoalsUnsynchronizedRandomAccessFixMixin",
"fix.NetherFossilOptimizationMixin",
"gameplay.BoneMealItemMixin",
"gameplay.BoneMealTaskMixin",
"gameplay.ServerWorldMixin",
"implementations.compat.GenerationSettingsFloraFeaturesMixin",
"implementations.terra.BiomeMixin",
"implementations.terra.HandleImplementationMixin",

View File

@@ -1,79 +0,0 @@
package com.dfsek.terra.lifecycle.asm;
import net.gudenau.minecraft.asm.api.v1.Identifier;
import net.gudenau.minecraft.asm.api.v1.Transformer;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;
import java.io.IOException;
import com.dfsek.terra.lifecycle.util.ASMUtil;
import com.dfsek.terra.lifecycle.util.LoaderUtil;
import com.dfsek.terra.mod.util.FertilizableUtil;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
public class FertilizableASM implements Transformer {
private static String fertilizableClassName = LoaderUtil.INSTANCE.mapClassName("intermediary", "net.minecraft.class_2256");
private static String fertilizableGrowMethodSignatureBase = String.format("(L%1$s;L%2$s;L%3$s;L%4$s;)",
LoaderUtil.INSTANCE.mapClassName("intermediary", "net.minecraft.class_3218").replace(".", "/"),
LoaderUtil.INSTANCE.mapClassName("intermediary", "net.minecraft.class_5819").replace(".", "/"),
LoaderUtil.INSTANCE.mapClassName("intermediary", "net.minecraft.class_2338").replace(".", "/"),
LoaderUtil.INSTANCE.mapClassName("intermediary", "net.minecraft.class_2680").replace(".", "/"));
private static String fertilizableGrowMethodSignature = fertilizableGrowMethodSignatureBase + "V";
private static String fertilizableGrowMethodName = LoaderUtil.INSTANCE.mapMethodName("intermediary", "net.minecraft.class_2256", "method_9652", "(Lnet/minecraft/class_3218;Lnet/minecraft/class_5819;Lnet/minecraft/class_2338;Lnet/minecraft/class_2680;)V");
@Override
public Identifier getName() {
return new Identifier("terra", "asm_test");
}
@Override
public boolean handlesClass(String name, String transformedName) {
return true;
}
@Override
public boolean transform(ClassNode classNode, Flags flags) {
try {
if (ASMUtil.inheritsFrom(classNode, fertilizableClassName.replace(".", "/"))) {
for (MethodNode method : classNode.methods) {
if (method.name.equals(fertilizableGrowMethodName)) {
if ((method.access & ACC_STATIC) == 0) {
if(method.desc.equals(fertilizableGrowMethodSignature)) {
InsnList list = new InsnList();
list.add(new VarInsnNode(Opcodes.ALOAD, 1));
list.add(new VarInsnNode(Opcodes.ALOAD, 2));
list.add(new VarInsnNode(Opcodes.ALOAD, 3));
list.add(new VarInsnNode(Opcodes.ALOAD, 4));
list.add(new MethodInsnNode(Opcodes.INVOKESTATIC, FertilizableUtil.class.getName().replace(".", "/"), "grow", fertilizableGrowMethodSignatureBase + "Z", false));
LabelNode jmp = new LabelNode();
list.add(new JumpInsnNode(Opcodes.IFNE, jmp));
list.add(new InsnNode(Opcodes.RETURN));
list.add(jmp);
method.instructions.insertBefore(method.instructions.getFirst(), list);
flags.requestFrames();
return true;
}
}
}
}
}
} catch(IOException e) {
throw new RuntimeException(e);
}
return false;
}
}

View File

@@ -1,56 +0,0 @@
package com.dfsek.terra.lifecycle.util;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;
import java.io.IOException;
import java.util.WeakHashMap;
import static org.objectweb.asm.ClassReader.SKIP_CODE;
import static org.objectweb.asm.ClassReader.SKIP_DEBUG;
import static org.objectweb.asm.ClassReader.SKIP_FRAMES;
public class ASMUtil {
static final ThreadLocal<WeakHashMap<String, WeakHashMap<String, Boolean>>> INHERITANCE_CACHE = new ThreadLocal<>();
public static boolean inheritsFrom(ClassNode classNode, String interfaceName) throws IOException {
if (INHERITANCE_CACHE.get() == null) {
INHERITANCE_CACHE.set(new WeakHashMap<>());
}
return inheritsFromInternal(classNode, interfaceName);
}
protected static boolean inheritsFromInternal(ClassNode classNode, String interfaceName) throws IOException {
if (INHERITANCE_CACHE.get().containsKey(classNode.name)) {
if (INHERITANCE_CACHE.get().get(classNode.name).containsKey(interfaceName)) {
return INHERITANCE_CACHE.get().get(classNode.name).get(interfaceName);
}
}
for (String parent : classNode.interfaces) {
if (checkClass(parent, interfaceName)) {
return true;
}
}
if (checkClass(classNode.superName, interfaceName)) {
return true;
}
INHERITANCE_CACHE.get().getOrDefault(classNode.name, new WeakHashMap<>()).put(interfaceName, false);
return false;
}
protected static boolean checkClass(String name, String interfaceName) throws IOException {
if (name.startsWith("java/")) {
return false;
}
boolean isClass = name.equals(interfaceName);
INHERITANCE_CACHE.get().getOrDefault(name, new WeakHashMap<>()).put(interfaceName, isClass);
if (isClass) {
return true;
}
ClassNode node = new ClassNode();
new ClassReader(name).accept(node, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES);
return inheritsFromInternal(node, interfaceName);
}
}

View File

@@ -1,17 +0,0 @@
package com.dfsek.terra.quilt;
import net.gudenau.minecraft.asm.api.v1.AsmInitializer;
import net.gudenau.minecraft.asm.api.v1.AsmRegistry;
import com.dfsek.terra.lifecycle.asm.FertilizableASM;
import com.dfsek.terra.lifecycle.util.LoaderUtil;
import com.dfsek.terra.quilt.util.QuiltLoaderUtil;
public class QuiltASMEntryPoint implements AsmInitializer {
@Override
public void onInitializeAsm() {
LoaderUtil.INSTANCE = new QuiltLoaderUtil();
AsmRegistry.getInstance().registerTransformer(new FertilizableASM());
}
}

View File

@@ -1,18 +0,0 @@
package com.dfsek.terra.quilt.util;
import com.dfsek.terra.lifecycle.util.LoaderUtil;
import org.quiltmc.loader.api.QuiltLoader;
public class QuiltLoaderUtil extends LoaderUtil {
@Override
public String mapClassName(String namespace, String className) {
return QuiltLoader.getMappingResolver().mapClassName(namespace, className);
}
@Override
public String mapMethodName(String namespace, String owner, String name, String descriptor) {
return QuiltLoader.getMappingResolver().mapMethodName(namespace, owner, name, descriptor);
}
}

View File

@@ -26,9 +26,6 @@
],
"pre_launch": [
"com.dfsek.terra.quilt.QuiltPreLaunchEntryPoint"
],
"gud_asm": [
"com.dfsek.terra.quilt.QuiltASMEntryPoint"
]
},
"depends": [