Add mixin to cancel targeting contraption riders\n\n- Cancel TargetingConditions.test if player is riding a contraption/train

This commit is contained in:
BipolarExpedition committed 2026-11-03 16:29:56 -05:00
1 parent f75568214a
commit b54023ff12
9 files changed
+108 -157

No files matched your search

+1
View File
@@ -23,3 +23,4 @@ run
# Files from Forge MDK
forge*changelog.txt
/run-data/
+1 -1
View File
@@ -56,7 +56,7 @@ mod_group_id=com.bipolarexpedition.java.contraptions_are_safe
# The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
mod_authors=BipolarExpedition
# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
mod_description=Example mod description.\nNewline characters can be used and will be replaced properly.
mod_description=Protects players riding contraptions. \nEnsures players seated/riding on a contraption can not be targeted by mobs in most cases.
create_version = 6.0.8-289
ponder_version = 1.0.91
@@ -1,17 +1,17 @@
package com.bipolarexpedition.java.contraptions_are_safe;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
//import net.minecraft.resources.ResourceLocation;
//import net.minecraft.world.item.Item;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.config.ModConfigEvent;
import net.minecraftforge.registries.ForgeRegistries;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
//import net.minecraftforge.registries.ForgeRegistries;
//
//import java.util.Collections;
//import java.util.List;
//import java.util.Set;
//import java.util.stream.Collectors;
// An example config class. This is not required, but it's a good idea to have one to keep your config organized.
// Demonstrates how to use Forge's config APIs
@@ -19,46 +19,30 @@ import java.util.stream.Collectors;
public class Config
{
private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
private static final ForgeConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER
.comment("Whether to log the dirt block on common setup")
.define("logDirtBlock", true);
private static final ForgeConfigSpec.IntValue MAGIC_NUMBER = BUILDER
.comment("A magic number")
.defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE);
public static final ForgeConfigSpec.ConfigValue<String> MAGIC_NUMBER_INTRODUCTION = BUILDER
.comment("What you want the introduction message to be for the magic number")
.define("magicNumberIntroduction", "The magic number is... ");
// a list of strings that are treated as resource locations for items
private static final ForgeConfigSpec.ConfigValue<List<? extends String>> ITEM_STRINGS = BUILDER
.comment("A list of items to log on common setup.")
.defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), Config::validateItemName);
//
// private static final ForgeConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER
// .comment("Whether to log the dirt block on common setup")
// .define("logDirtBlock", true);
//
// private static final ForgeConfigSpec.IntValue MAGIC_NUMBER = BUILDER
// .comment("A magic number")
// .defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE);
//
// public static final ForgeConfigSpec.ConfigValue<String> MAGIC_NUMBER_INTRODUCTION = BUILDER
// .comment("What you want the introduction message to be for the magic number")
// .define("magicNumberIntroduction", "The magic number is... ");
static final ForgeConfigSpec SPEC = BUILDER.build();
public static boolean logDirtBlock;
public static int magicNumber;
public static String magicNumberIntroduction;
public static Set<Item> items;
private static boolean validateItemName(final Object obj)
{
return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(new ResourceLocation(itemName));
}
// public static boolean logDirtBlock;
// public static int magicNumber;
// public static String magicNumberIntroduction;
@SubscribeEvent
static void onLoad(final ModConfigEvent event)
{
logDirtBlock = LOG_DIRT_BLOCK.get();
magicNumber = MAGIC_NUMBER.get();
magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get();
// convert the list of strings into a set of items
items = ITEM_STRINGS.get().stream()
.map(itemName -> ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemName)))
.collect(Collectors.toSet());
// logDirtBlock = LOG_DIRT_BLOCK.get();
// magicNumber = MAGIC_NUMBER.get();
// magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get();
}
}
@@ -1,31 +1,31 @@
package com.bipolarexpedition.java.contraptions_are_safe;
import com.mojang.logging.LogUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.material.MapColor;
import net.minecraftforge.api.distmarker.Dist;
//import net.minecraft.client.Minecraft;
//import net.minecraft.core.registries.Registries;
//import net.minecraft.world.food.FoodProperties;
//import net.minecraft.world.item.BlockItem;
//import net.minecraft.world.item.CreativeModeTab;
//import net.minecraft.world.item.CreativeModeTabs;
//import net.minecraft.world.item.Item;
//import net.minecraft.world.level.block.Block;
//import net.minecraft.world.level.block.Blocks;
//import net.minecraft.world.level.block.state.BlockBehaviour;
//import net.minecraft.world.level.material.MapColor;
//import net.minecraftforge.api.distmarker.Dist;
//import net.minecraftforge.event.BuildCreativeModeTabContentsEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.BuildCreativeModeTabContentsEvent;
import net.minecraftforge.event.server.ServerStartingEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
//import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
//import net.minecraftforge.registries.DeferredRegister;
//import net.minecraftforge.registries.ForgeRegistries;
//import net.minecraftforge.registries.RegistryObject;
import org.slf4j.Logger;
// The value here should match an entry in the META-INF/mods.toml file
@@ -37,28 +37,6 @@ public class ContraptionsAreSafe
// Directly reference a slf4j logger
private static final Logger LOGGER = LogUtils.getLogger();
// Create a Deferred Register to hold Blocks which will all be registered under the "contraptions_are_safe" namespace
public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MODID);
// Create a Deferred Register to hold Items which will all be registered under the "contraptions_are_safe" namespace
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MODID);
// Create a Deferred Register to hold CreativeModeTabs which will all be registered under the "contraptions_are_safe" namespace
public static final DeferredRegister<CreativeModeTab> CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID);
// Creates a new Block with the id "contraptions_are_safe:example_block", combining the namespace and path
public static final RegistryObject<Block> EXAMPLE_BLOCK = BLOCKS.register("example_block", () -> new Block(BlockBehaviour.Properties.of().mapColor(MapColor.STONE)));
// Creates a new BlockItem with the id "contraptions_are_safe:example_block", combining the namespace and path
public static final RegistryObject<Item> EXAMPLE_BLOCK_ITEM = ITEMS.register("example_block", () -> new BlockItem(EXAMPLE_BLOCK.get(), new Item.Properties()));
// Creates a new food item with the id "contraptions_are_safe:example_id", nutrition 1 and saturation 2
public static final RegistryObject<Item> EXAMPLE_ITEM = ITEMS.register("example_item", () -> new Item(new Item.Properties().food(new FoodProperties.Builder()
.alwaysEat().nutrition(1).saturationMod(2f).build())));
// Creates a creative tab with the id "contraptions_are_safe:example_tab" for the example item, that is placed after the combat tab
public static final RegistryObject<CreativeModeTab> EXAMPLE_TAB = CREATIVE_MODE_TABS.register("example_tab", () -> CreativeModeTab.builder()
.withTabsBefore(CreativeModeTabs.COMBAT)
.icon(() -> EXAMPLE_ITEM.get().getDefaultInstance())
.displayItems((parameters, output) -> {
output.accept(EXAMPLE_ITEM.get()); // Add the example item to the tab. For your own tabs, this method is preferred over the event
}).build());
public ContraptionsAreSafe(FMLJavaModLoadingContext context)
{
@@ -67,19 +45,9 @@ public class ContraptionsAreSafe
// Register the commonSetup method for modloading
modEventBus.addListener(this::commonSetup);
// Register the Deferred Register to the mod event bus so blocks get registered
BLOCKS.register(modEventBus);
// Register the Deferred Register to the mod event bus so items get registered
ITEMS.register(modEventBus);
// Register the Deferred Register to the mod event bus so tabs get registered
CREATIVE_MODE_TABS.register(modEventBus);
// Register ourselves for server and other game events we are interested in
MinecraftForge.EVENT_BUS.register(this);
// Register the item to a creative tab
modEventBus.addListener(this::addCreative);
// Register our mod's ForgeConfigSpec so that Forge can create and load the config file for us
context.registerConfig(ModConfig.Type.COMMON, Config.SPEC);
}
@@ -87,21 +55,7 @@ public class ContraptionsAreSafe
private void commonSetup(final FMLCommonSetupEvent event)
{
// Some common setup code
LOGGER.info("HELLO FROM COMMON SETUP");
if (Config.logDirtBlock)
LOGGER.info("DIRT BLOCK >> {}", ForgeRegistries.BLOCKS.getKey(Blocks.DIRT));
LOGGER.info(Config.magicNumberIntroduction + Config.magicNumber);
Config.items.forEach((item) -> LOGGER.info("ITEM >> {}", item.toString()));
}
// Add the example block item to the building blocks tab
private void addCreative(BuildCreativeModeTabContentsEvent event)
{
if (event.getTabKey() == CreativeModeTabs.BUILDING_BLOCKS)
event.accept(EXAMPLE_BLOCK_ITEM);
LOGGER.debug("HELLO FROM COMMON SETUP for Contraptions Are Safe");
}
// You can use SubscribeEvent and let the Event Bus discover methods to call
@@ -109,19 +63,6 @@ public class ContraptionsAreSafe
public void onServerStarting(ServerStartingEvent event)
{
// Do something when the server starts
LOGGER.info("HELLO from server starting");
}
// You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent
@Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public static class ClientModEvents
{
@SubscribeEvent
public static void onClientSetup(FMLClientSetupEvent event)
{
// Some client setup code
LOGGER.info("HELLO FROM CLIENT SETUP");
LOGGER.info("MINECRAFT NAME >> {}", Minecraft.getInstance().getUser().getName());
}
LOGGER.debug("HELLO from Contraptions Are Safe for server starting");
}
}
@@ -0,0 +1,35 @@
package com.bipolarexpedition.java.contraptions_are_safe;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.Entity;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraft.server.level.ServerPlayer;
//@Mod.EventBusSubscriber(
// modid = "contraptions_are_safe",
// bus = Mod.EventBusSubscriber.Bus.FORGE
//)
public final class DebugTicker {
private DebugTicker() {}
// @SubscribeEvent
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
if (event.phase != TickEvent.Phase.END) return;
if (!(event.player instanceof ServerPlayer player)) return;
if (player.tickCount % 20 != 0) return;
player.sendSystemMessage(Component.literal(
"Debug: riding=" + player.isPassenger()
+ ", vehicle=" + player.getVehicle()
+ ", isContraption=" + isSittingContraption(player)
));
}
public static boolean isSittingContraption(ServerPlayer player) {
Entity player_vehicle = player.getVehicle();
return (player_vehicle instanceof AbstractContraptionEntity);
}
}
@@ -0,0 +1,22 @@
package com.bipolarexpedition.java.contraptions_are_safe.mixin;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
import net.minecraft.world.entity.player.Player;
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;
@Mixin(TargetingConditions.class)
public class IgnoreContraptionRidersMixin {
@Inject(method = "test", at = @At("HEAD"), cancellable = true)
private void skipRiders(LivingEntity attacker, LivingEntity target, CallbackInfoReturnable<Boolean> ci) {
if ((target instanceof Player) && (target.getVehicle() instanceof AbstractContraptionEntity)) {
ci.setReturnValue(false);
return;
}
}
}
@@ -1,33 +0,0 @@
package com.bipolarexpedition.java.contraptions_are_safe.mixin;
import com.bipolarexpedition.java.contraptions_are_safe.ContraptionsAreSafe;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
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;
@Mixin(Mob.class)
public class MobTargetingMixin {
@Inject(method = "canAttack(Lnet/minecraft/world/entity/LivingEntity;)Z", at = @At("HEAD"), cancellable = true)
private void preventContraptionTargeting(LivingEntity target, CallbackInfoReturnable<Boolean> cir) {
if (target != null && isOnContraption(target)) {
cir.setReturnValue(false);
}
}
private boolean isOnContraption(Entity entity) {
Entity vehicle = entity.getVehicle();
while (vehicle != null) {
if (vehicle instanceof AbstractContraptionEntity) {
return true;
}
vehicle = vehicle.getVehicle();
}
return false;
}
}
+1 -1
View File
@@ -40,7 +40,7 @@ authors="${mod_authors}" #optional
# NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value.
# IMPORTANT NOTE: this is NOT an instruction as to which environments (CLIENT or DEDICATED SERVER) your mod loads on. Your mod should load (and maybe do nothing!) whereever it finds itself.
#displayTest="MATCH_VERSION" # if nothing is specified, MATCH_VERSION is the default when clientSideOnly=false, otherwise IGNORE_ALL_VERSION when clientSideOnly=true (#optional)
displayTest = "IGNORE_SERVER_VERSION"
mixinConfig = "contraptionsaresafe.mixins.json"
# Access Transformers
@@ -5,8 +5,9 @@
"compatibilityLevel": "JAVA_17",
"refmap": "contraptionsaresafe.refmap.json",
"mixins": [
"MobTargetingMixin"
"IgnoreContraptionRidersMixin"
],
"client": [],
"server": []
"server": [
]
}