diff --git a/README.md b/README.md index 852f3b89..f38ddd2d 100644 --- a/README.md +++ b/README.md @@ -237,6 +237,10 @@ All changes are toggleable via config files. * **Weaken Wither Structure Requirements:** Allows creating Withers with non-air blocks in the bottom corners of the structure * **XP Bottle Amount:** Sets the amount of experience spawned by bottles o' enchanting * **XP Level Cap:** Sets the maximum experience level players can reach +* **Void Teleport:** + * Options allow toggling the setting globally, controlling to what Y-level the entity is teleported, if blindness is applied, maximum number of consecutive times, and how much and in what way fall damage is taken + * **Configure Entities:** Configures what entities can be teleported, and if the player is teleported + * **Configure Dimensions:** Configures what dimensions the effect can take place in ![](https://i.imgur.com/1EmHZlb.png) diff --git a/src/main/java/mod/acgaming/universaltweaks/config/UTConfigTweaks.java b/src/main/java/mod/acgaming/universaltweaks/config/UTConfigTweaks.java index d2fd95dd..3984eafc 100644 --- a/src/main/java/mod/acgaming/universaltweaks/config/UTConfigTweaks.java +++ b/src/main/java/mod/acgaming/universaltweaks/config/UTConfigTweaks.java @@ -419,6 +419,10 @@ public static class EntitiesCategory @Config.Name("Water Fall Damage") public final WaterFallDamageCategory WATER_FALL_DAMAGE = new WaterFallDamageCategory(); + @Config.LangKey("cfg.universaltweaks.tweaks.entities.voidteleport") + @Config.Name("Void Teleport") + public final VoidTeleportCategory VOID_TELEPORT = new VoidTeleportCategory(); + @Config.Name("Adaptive XP Drops") @Config.Comment ({ @@ -890,6 +894,104 @@ public static class WaterFallDamageCategory @Config.Comment("How much fall damage gets reduced by water per tick") public double utFallDamageValue = 2.0D; } + + public static class VoidTeleportCategory + { + @Config.RequiresMcRestart + @Config.Name("[01] Void Teleport Toggle") + @Config.Comment("Enables Void Teleport, where falling out below a dimension will teleport you to the top of the dimension") + public boolean utVoidTeleportToggle = false; + + @Config.Name("[02] Prevent Void Damage") + @Config.Comment + ({ + "Prevents taking a tick of void damage before being teleported", + "If this is false, entities will take 4 damage every time Void Teleport activates, preventing infinite looping" + }) + public boolean utPreventVoidDamage = true; + + @Config.Name("[03] Target Y-Level") + @Config.Comment + ({ + "Y-level to teleport the entity", + "If the target Y-level is lower than the highest block in that coordinate, will teleport the entity to the highest location instead" + }) + public int utTargetYLevel = 300; + + @Config.Name("[04] Apply Blindness on Teleport") + @Config.Comment("Applies the blindness effect for 3 seconds when teleporting") + public boolean utTeleportBlindness = true; + + @Config.Name("[05] Clamp Falling Speed") + @Config.Comment("Prevents Y motion from being less than this") + public double utClampSpeedTo = -1; + + @Config.Name("[06] Fall Distance Height") + @Config.Comment + ({ + "Height to override the fallDistance variable with when landing after having teleported", + "When set to less than 0, [07] Fall Damage Taken applies instead" + }) + public float utFallHeight = -1; + + @Config.Name("[07] Fall Damage Taken") + @Config.Comment + ({ + "Amount of fall damage taken when landing on a block", + "Negative numbers deal damage relative to the entity's max health", + "Only applies if [06] Fall Distance Height is less than 0" + }) + public float utFallDamageTaken = -1; + + @Config.Name("[08] Allow Fall Damage Taken to Kill") + @Config.Comment + ({ + "Sets if [07] Fall Damage Taken can kill entities", + "Does not apply to fall damage taken due to [06] Fall Distance Height" + }) + public boolean utAllowSpecificFallDamageToKill = true; + + @Config.Name("[09] Maximum Times to Teleport Consecutively") + @Config.Comment("Maximum number of times to teleport the entity without the entity landing before no longer teleporting. Used to prevent infinite loops") + public int utMaxCombo = 100; + + @Config.Name("[10] Apply Void Teleport to Players") + @Config.Comment("Controls if players are teleported by Void Teleport") + public boolean utForgivePlayers = true; + + @Config.Name("[11] Entity List") + @Config.Comment + ({ + "List of the resource location names for entities concerning Void Teleport", + "Behavior depends on the list mode" + }) + public String[] utEntityList = new String[] {}; + + @Config.Name("[12] Entity List Mode") + @Config.Comment + ({ + "Blacklist Mode: Entities that won't be impacted by Void Teleport, others will", + "Whitelist Mode: Entities that will be impacted by Void Teleport, others won't" + }) + public EnumLists utEntityListMode = EnumLists.WHITELIST; + + @Config.Name("[13] Dimension List") + @Config.Comment + ({ + "List of dimensions concerning Void Teleport", + "Behavior depends on the list mode", + "Can be dimension name or ID" + }) + public String[] utDimensionList = new String[] {}; + + @Config.Name("[14] Dimension List Mode") + @Config.Comment + ({ + "Blacklist Mode: Dimensions that don't have Void Teleport enabled, others do", + "Whitelist Mode: Dimensions that have Void Teleport enabled, others don't" + }) + public EnumLists utDimensionListMode = EnumLists.BLACKLIST; + } } public static class ItemsCategory diff --git a/src/main/java/mod/acgaming/universaltweaks/core/UTLoadingPlugin.java b/src/main/java/mod/acgaming/universaltweaks/core/UTLoadingPlugin.java index d9e2a2dc..962a6357 100644 --- a/src/main/java/mod/acgaming/universaltweaks/core/UTLoadingPlugin.java +++ b/src/main/java/mod/acgaming/universaltweaks/core/UTLoadingPlugin.java @@ -110,6 +110,7 @@ public class UTLoadingPlugin implements IFMLLoadingPlugin, IEarlyMixinLoader put("mixins.tweaks.entities.speed.player.json", () -> UTConfigTweaks.ENTITIES.PLAYER_SPEED.utPlayerSpeedToggle); put("mixins.tweaks.entities.taming.horse.json", () -> UTConfigTweaks.ENTITIES.UNDEAD_HORSES.utTamingUndeadHorsesToggle); put("mixins.tweaks.entities.trading.json", () -> UTConfigTweaks.ENTITIES.utVillagerTradeLevelingToggle || UTConfigTweaks.ENTITIES.utVillagerTradeRestockToggle); + put("mixins.tweaks.entities.voidteleport.json", () -> UTConfigTweaks.ENTITIES.VOID_TELEPORT.utVoidTeleportToggle); put("mixins.tweaks.items.attackcooldown.server.json", () -> UTConfigTweaks.ITEMS.ATTACK_COOLDOWN.utAttackCooldownToggle); put("mixins.tweaks.items.eating.json", () -> UTConfigTweaks.ITEMS.utAlwaysEatToggle); put("mixins.tweaks.items.hardcorebuckets.json", () -> UTConfigTweaks.ITEMS.utHardcoreBucketsToggle); diff --git a/src/main/java/mod/acgaming/universaltweaks/tweaks/entities/voidteleport/mixin/UTVoidTeleportEntity.java b/src/main/java/mod/acgaming/universaltweaks/tweaks/entities/voidteleport/mixin/UTVoidTeleportEntity.java new file mode 100644 index 00000000..646e9b7a --- /dev/null +++ b/src/main/java/mod/acgaming/universaltweaks/tweaks/entities/voidteleport/mixin/UTVoidTeleportEntity.java @@ -0,0 +1,118 @@ +package mod.acgaming.universaltweaks.tweaks.entities.voidteleport.mixin; + +import mod.acgaming.universaltweaks.config.UTConfigTweaks; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityList; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.DimensionType; +import net.minecraftforge.common.DimensionManager; +import org.spongepowered.asm.mixin.Mixin; +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.Arrays; +import java.util.List; + +// Courtesy of WaitingIdly +@Mixin(EntityLivingBase.class) +public abstract class UTVoidTeleportEntity +{ + @Unique + private static final String universalTweaks$combo = "universalTweaks$consecutiveVoidTeleportTimes"; + + @Unique + private static boolean isEnabledForDimension(int dimension) + { + List list = Arrays.asList(UTConfigTweaks.ENTITIES.VOID_TELEPORT.utDimensionList); + DimensionType dimensionType = DimensionManager.getProviderType(dimension); + String dimensionName = dimensionType == null ? null : dimensionType.getName(); + + boolean isWhitelist = UTConfigTweaks.ENTITIES.VOID_TELEPORT.utDimensionListMode == UTConfigTweaks.EnumLists.WHITELIST; + return isWhitelist == (list.contains(dimensionName) || list.contains(String.valueOf(dimension))); + } + + @Unique + private static boolean isEnabledForEntity(Entity entity) + { + List list = Arrays.asList(UTConfigTweaks.ENTITIES.VOID_TELEPORT.utEntityList); + ResourceLocation resourceLocation = EntityList.getKey(entity); + if (resourceLocation == null) return false; + + boolean isWhitelist = UTConfigTweaks.ENTITIES.VOID_TELEPORT.utEntityListMode == UTConfigTweaks.EnumLists.WHITELIST; + return list.contains(resourceLocation.toString()) == isWhitelist; + } + + @Inject(method = "outOfWorld", at = @At("HEAD"), cancellable = true) + public void utTransferPlayerToDimension(CallbackInfo ci) + { + if (!UTConfigTweaks.ENTITIES.VOID_TELEPORT.utVoidTeleportToggle) return; + EntityLivingBase entity = (EntityLivingBase) (Object) this; + if (!isEnabledForDimension(entity.dimension)) return; + if (UTConfigTweaks.ENTITIES.VOID_TELEPORT.utMaxCombo >= 0 && entity.getEntityData().getInteger(universalTweaks$combo) > UTConfigTweaks.ENTITIES.VOID_TELEPORT.utMaxCombo) return; + + if ((UTConfigTweaks.ENTITIES.VOID_TELEPORT.utForgivePlayers && entity instanceof EntityPlayer) || isEnabledForEntity(entity)) + { + if (UTConfigTweaks.ENTITIES.VOID_TELEPORT.utPreventVoidDamage) ci.cancel(); + if (UTConfigTweaks.ENTITIES.VOID_TELEPORT.utTeleportBlindness) entity.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, 60, 3)); + + int highestClearLocation = entity.getEntityWorld().getHeight(MathHelper.floor(entity.posX), MathHelper.floor(entity.posZ)); + int targetY = UTConfigTweaks.ENTITIES.VOID_TELEPORT.utTargetYLevel < highestClearLocation ? highestClearLocation : UTConfigTweaks.ENTITIES.VOID_TELEPORT.utTargetYLevel; + entity.setPositionAndUpdate(entity.posX, targetY, entity.posZ); + entity.motionY = Math.min(0, Math.max(UTConfigTweaks.ENTITIES.VOID_TELEPORT.utClampSpeedTo, entity.motionY)); + + if (entity.getEntityData().hasKey(universalTweaks$combo)) + { + entity.getEntityData().setInteger(universalTweaks$combo, entity.getEntityData().getInteger(universalTweaks$combo) + 1); + } + else + { + entity.getEntityData().setInteger(universalTweaks$combo, 1); + } + } + } + + @Inject(method = "updateFallState", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;updateFallState(DZLnet/minecraft/block/state/IBlockState;Lnet/minecraft/util/math/BlockPos;)V")) + public void utUpdateFallState(double y, boolean onGroundIn, IBlockState state, BlockPos pos, CallbackInfo ci) + { + if (!UTConfigTweaks.ENTITIES.VOID_TELEPORT.utVoidTeleportToggle) return; + EntityLivingBase entity = (EntityLivingBase) (Object) this; + if (onGroundIn && entity.getEntityData().hasKey(universalTweaks$combo)) + { + entity.getEntityData().removeTag(universalTweaks$combo); + + if (entity.isInWater()) return; + if (entity instanceof EntityPlayer && (((EntityPlayer) entity).capabilities.isFlying || ((EntityPlayer) entity).capabilities.allowFlying)) return; + + if (UTConfigTweaks.ENTITIES.VOID_TELEPORT.utFallHeight < 0) + { + entity.fallDistance = 0; + float setting = UTConfigTweaks.ENTITIES.VOID_TELEPORT.utFallDamageTaken; + if (setting != 0) + { + float damage = setting < 0 ? entity.getMaxHealth() + setting : setting; + if (!UTConfigTweaks.ENTITIES.VOID_TELEPORT.utAllowSpecificFallDamageToKill) damage = Float.min(entity.getHealth() - 1, damage); + if (damage > 0) + { + entity.playSound(SoundEvents.ENTITY_GENERIC_BIG_FALL, 1.0F, 1.0F); + entity.attackEntityFrom(DamageSource.FALL, damage); + } + } + } + else + { + entity.fallDistance = UTConfigTweaks.ENTITIES.VOID_TELEPORT.utFallHeight; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/mod/acgaming/universaltweaks/util/compat/UTObsoleteModsHandler.java b/src/main/java/mod/acgaming/universaltweaks/util/compat/UTObsoleteModsHandler.java index 6cc35569..457f6518 100644 --- a/src/main/java/mod/acgaming/universaltweaks/util/compat/UTObsoleteModsHandler.java +++ b/src/main/java/mod/acgaming/universaltweaks/util/compat/UTObsoleteModsHandler.java @@ -67,6 +67,7 @@ public class UTObsoleteModsHandler put("fastleafdecay", () -> UTConfigTweaks.BLOCKS.utLeafDecayToggle); put("fencejumper", () -> UTConfigTweaks.BLOCKS.utFenceWallJumpToggle); put("finite-fluid-control", () -> UTConfigTweaks.BLOCKS.FINITE_WATER.utFiniteWaterToggle); + put("forgivingvoid", () -> UTConfigTweaks.ENTITIES.VOID_TELEPORT.utVoidTeleportToggle); put("framevoidpatch", () -> UTConfigBugfixes.BLOCKS.utItemFrameVoidToggle); put("getittogetherdrops", () -> UTConfigTweaks.ITEMS.ITEM_ENTITIES.utItemEntitiesToggle); put("givemebackmyhp", () -> UTConfigBugfixes.ENTITIES.utMaxHealthToggle); diff --git a/src/main/resources/assets/universaltweaks/lang/en_us.lang b/src/main/resources/assets/universaltweaks/lang/en_us.lang index 5dc05f78..a0182468 100644 --- a/src/main/resources/assets/universaltweaks/lang/en_us.lang +++ b/src/main/resources/assets/universaltweaks/lang/en_us.lang @@ -124,6 +124,7 @@ cfg.universaltweaks.tweaks.entities.sleeping=Sleeping cfg.universaltweaks.tweaks.entities.spawncaps=Spawn Caps cfg.universaltweaks.tweaks.entities.undeadhorses=Undead Horses cfg.universaltweaks.tweaks.entities.waterfalldamage=Water Fall Damage +cfg.universaltweaks.tweaks.entities.voidteleport=Void Teleport cfg.universaltweaks.tweaks.items.attackcooldown=Attack Cooldown cfg.universaltweaks.tweaks.items.infinity=Infinity cfg.universaltweaks.tweaks.items.itementities=Item Entities diff --git a/src/main/resources/mixins.tweaks.entities.voidteleport.json b/src/main/resources/mixins.tweaks.entities.voidteleport.json new file mode 100644 index 00000000..a6168175 --- /dev/null +++ b/src/main/resources/mixins.tweaks.entities.voidteleport.json @@ -0,0 +1,7 @@ +{ + "package": "mod.acgaming.universaltweaks.tweaks.entities.voidteleport.mixin", + "refmap": "universaltweaks.refmap.json", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "mixins": ["UTVoidTeleportEntity"] +} \ No newline at end of file