From d5a8b5e18d2749f848bc0113ba3f42112e65c285 Mon Sep 17 00:00:00 2001 From: Unknown <lemadec.fr@gmail.com> Date: Sat, 31 Aug 2019 13:52:43 +0200 Subject: [PATCH] Improved world border usability - use action bar to reduce chat spamming - inform player when cancelling nether portal opening - render the celestia object border using vanilla renderer --- .../cr0s/warpdrive/core/ClassTransformer.java | 67 +++++++++++ .../cr0s/warpdrive/data/CelestialBorder.java | 113 ++++++++++++++++++ .../cr0s/warpdrive/data/CelestialObject.java | 9 ++ .../data/CelestialObjectManager.java | 36 ++++++ .../cr0s/warpdrive/event/LivingHandler.java | 12 +- .../assets/warpdrive/lang/de_de.lang | 1 + .../assets/warpdrive/lang/en_us.lang | 1 + .../assets/warpdrive/lang/fr_fr.lang | 7 +- .../assets/warpdrive/lang/nl_nl.lang | 1 + .../assets/warpdrive/lang/ru_ru.lang | 1 + .../assets/warpdrive/lang/zh_cn.lang | 1 + .../assets/warpdrive/lang/zh_tw.lang | 1 + 12 files changed, 241 insertions(+), 9 deletions(-) create mode 100644 src/main/java/cr0s/warpdrive/data/CelestialBorder.java diff --git a/src/main/java/cr0s/warpdrive/core/ClassTransformer.java b/src/main/java/cr0s/warpdrive/core/ClassTransformer.java index 075f5bc0..d7f6fb23 100644 --- a/src/main/java/cr0s/warpdrive/core/ClassTransformer.java +++ b/src/main/java/cr0s/warpdrive/core/ClassTransformer.java @@ -36,6 +36,7 @@ public class ClassTransformer implements net.minecraft.launchwrapper.IClassTrans private static final String GRAVITY_MANAGER_CLASS = "cr0s/warpdrive/data/GravityManager"; private static final String CLOAK_MANAGER_CLASS = "cr0s/warpdrive/data/CloakManager"; + private static final String CELESTIAL_OBJECT_MANAGER_CLASS = "cr0s/warpdrive/data/CelestialObjectManager"; private static final boolean debugLog = false; private static final String ASM_DUMP_BEFORE = "asm/warpdrive.before"; @@ -69,6 +70,12 @@ public class ClassTransformer implements net.minecraft.launchwrapper.IClassTrans nodeMap.put("ForgeHooks.class", "ForgeHooks"); nodeMap.put("loadAdvancements.name", "lambda$loadAdvancements$0"); nodeMap.put("loadAdvancements.desc", "(Lnet/minecraftforge/fml/common/ModContainer;Ljava/util/Map;Ljava/nio/file/Path;Ljava/nio/file/Path;)Ljava/lang/Boolean;"); + + nodeMap.put("RenderGlobal.class", "buw"); + nodeMap.put("renderWorldBorder.name", "func_180449_a"); + nodeMap.put("renderWorldBorder.desc", "(Lnet/minecraft/entity/Entity;F)V"); + nodeMap.put("getWorldBorder.name", "func_175723_af"); + nodeMap.put("getWorldBorder.desc", "()Lnet/minecraft/world/border/WorldBorder;"); } @Override @@ -119,6 +126,10 @@ public class ClassTransformer implements net.minecraft.launchwrapper.IClassTrans bytesNew = transformMinecraftForgeHooks(bytesOld); break; + case "net.minecraft.client.renderer.RenderGlobal": + bytesNew = transformMinecraftRenderGlobal(bytesOld); + break; + default: bytesNew = null; } @@ -743,6 +754,62 @@ public class ClassTransformer implements net.minecraft.launchwrapper.IClassTrans return bytesNew; } + private byte[] transformMinecraftRenderGlobal(@Nonnull final byte[] bytes) { + final ClassNode classNode = new ClassNode(); + final ClassReader classReader = new ClassReader(bytes); + classReader.accept(classNode, 0); + + final int countExpected = 1; + int countTransformed = 0; + for (final MethodNode methodNode : classNode.methods) { + // if (debugLog) { FMLLoadingPlugin.logger.info(String.format("- Method %s %s", methodNode.name, methodNode.desc)); } + + if ( (methodNode.name.equals(nodeMap.get("renderWorldBorder.name")) || methodNode.name.equals("renderWorldBorder")) + && methodNode.desc.equals(nodeMap.get("renderWorldBorder.desc")) ) { + FMLLoadingPlugin.logger.debug(String.format("Found method to transform: %s %s", + methodNode.name, methodNode.desc)); + + int indexInstruction = 0; + + while (indexInstruction < methodNode.instructions.size()) { + final AbstractInsnNode abstractNode = methodNode.instructions.get(indexInstruction); + if (debugLog) { decompile(abstractNode); } + + // change WorldBorder worldborder = this.field_72769_h.func_175723_af(); + // into WorldBorder worldborder = CelestiaObjectManager.getWorldBorder(world); + if (abstractNode instanceof MethodInsnNode) { + final MethodInsnNode nodeAt = (MethodInsnNode) abstractNode; + + if (nodeAt.name.equals(nodeMap.get("getWorldBorder.name")) || nodeAt.name.equals("getWorldBorder")) { + final MethodInsnNode overwriteNode = new MethodInsnNode( + Opcodes.INVOKESTATIC, + CELESTIAL_OBJECT_MANAGER_CLASS, + "World_getWorldBorder", + "(Lnet/minecraft/world/World;)Lnet/minecraft/world/border/WorldBorder;", + false); + methodNode.instructions.set(nodeAt, overwriteNode); + if (debugLog) { FMLLoadingPlugin.logger.info(String.format("Injecting into %s.%s %s", classNode.name, methodNode.name, methodNode.desc)); } + countTransformed++; + } + } + + indexInstruction++; + } + } + } + + if (countTransformed != countExpected) { + FMLLoadingPlugin.logger.error(String.format("Transformation failed for %s (%d/%d), aborting...", classNode.name, countTransformed, countExpected)); + return bytes; + } + + final ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); // | ClassWriter.COMPUTE_FRAMES); + classNode.accept(writer); + final byte[] bytesNew = writer.toByteArray(); + FMLLoadingPlugin.logger.info(String.format("Successful injection in %s", classNode.name)); + return bytesNew; + } + private void removeInstruction(@Nonnull final MethodNode methodNode, final int indexInstruction) { final AbstractInsnNode abstractNodeToRemove = methodNode.instructions.get(indexInstruction); if (debugLog) { diff --git a/src/main/java/cr0s/warpdrive/data/CelestialBorder.java b/src/main/java/cr0s/warpdrive/data/CelestialBorder.java new file mode 100644 index 00000000..27d4182d --- /dev/null +++ b/src/main/java/cr0s/warpdrive/data/CelestialBorder.java @@ -0,0 +1,113 @@ +package cr0s.warpdrive.data; + +import javax.annotation.Nonnull; + +import net.minecraft.world.border.EnumBorderStatus; +import net.minecraft.world.border.WorldBorder; + + +/** + * An overloaded world border to allow rectangular shapes. + * + * @author LemADEC + */ +public class CelestialBorder extends WorldBorder { + + public int centerX, centerZ; + public int radiusX, radiusZ; + + public CelestialBorder(final int centerX, final int centerZ, + final int radiusX, final int radiusZ) { + this.centerX = centerX; + this.centerZ = centerZ; + this.radiusX = radiusX; + this.radiusZ = radiusZ; + } + + @Nonnull + @Override + public EnumBorderStatus getStatus() { + return EnumBorderStatus.STATIONARY; + } + + @Override + public double minX() { + return centerX - radiusX; + } + + @Override + public double minZ() { + return centerZ - radiusZ; + } + + @Override + public double maxX() { + return centerX + radiusX; + } + + @Override + public double maxZ() { + return centerZ + radiusZ; + } + + @Override + public double getCenterX() + { + return centerX; + } + + @Override + public double getCenterZ() + { + return centerZ; + } + + @Override + public void setCenter(final double x, final double z) { + assert false; + } + + @Override + public double getDiameter() { + assert false; + return super.getDiameter(); + } + + @Override + public long getTimeUntilTarget() { + assert false; + return 0L; + } + + @Override + public double getTargetSize() { + return 2 * Math.max(radiusX, radiusZ); + } + + @Override + public void setTransition(final double newSize) { + super.setTransition(newSize); + } + + @Override + public void setTransition(final double oldSize, final double newSize, final long time) { + super.setTransition(oldSize, newSize, time); + } + + @Override + public void setSize(final int size) { + // no operation + } + + @Override + public int getSize() { + return 2 * Math.max(radiusX, radiusZ); + } + + @Override + public String toString() { + return String.format("CelestialBorder [@ %d %d Border(%d %d)]", + centerX, centerZ, + 2 * radiusX, 2 * radiusZ ); + } +} \ No newline at end of file diff --git a/src/main/java/cr0s/warpdrive/data/CelestialObject.java b/src/main/java/cr0s/warpdrive/data/CelestialObject.java index 497087c0..2e61cd30 100644 --- a/src/main/java/cr0s/warpdrive/data/CelestialObject.java +++ b/src/main/java/cr0s/warpdrive/data/CelestialObject.java @@ -24,6 +24,7 @@ import net.minecraft.nbt.NBTTagList; import net.minecraft.util.IStringSerializable; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.world.border.WorldBorder; import net.minecraftforge.common.util.Constants.NBT; @@ -81,6 +82,7 @@ public class CelestialObject implements Cloneable, IStringSerializable, ICelesti public CelestialObject parent; private boolean isHyperspace; + private WorldBorder cache_worldBorder; private AxisAlignedBB cache_aabbWorldBorder; private AxisAlignedBB cache_aabbAreaToReachParent; private AxisAlignedBB cache_aabbAreaInParent; @@ -485,6 +487,13 @@ public class CelestialObject implements Cloneable, IStringSerializable, ICelesti return new VectorI(dimensionCenterX - parentCenterX, 0, dimensionCenterZ - parentCenterZ); } + public WorldBorder getWorldBorder() { + if (cache_worldBorder == null) { + cache_worldBorder = new CelestialBorder(dimensionCenterX, dimensionCenterZ, borderRadiusX, borderRadiusZ); + } + return cache_worldBorder; + } + @Override public AxisAlignedBB getWorldBorderArea() { if (cache_aabbWorldBorder == null) { diff --git a/src/main/java/cr0s/warpdrive/data/CelestialObjectManager.java b/src/main/java/cr0s/warpdrive/data/CelestialObjectManager.java index 275adbb5..f9cd60bd 100644 --- a/src/main/java/cr0s/warpdrive/data/CelestialObjectManager.java +++ b/src/main/java/cr0s/warpdrive/data/CelestialObjectManager.java @@ -2,11 +2,14 @@ package cr0s.warpdrive.data; import cr0s.warpdrive.Commons; import cr0s.warpdrive.WarpDrive; +import cr0s.warpdrive.api.WarpDriveText; import cr0s.warpdrive.config.InvalidXmlException; import cr0s.warpdrive.config.XmlFileManager; import javax.annotation.Nonnull; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.math.AxisAlignedBB; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @@ -22,6 +25,7 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraft.world.border.WorldBorder; import net.minecraftforge.common.DimensionManager; @@ -172,6 +176,14 @@ public class CelestialObjectManager extends XmlFileManager { final CelestialObject celestialObjectPortal = get(world, blockPos.getX(), blockPos.getZ()); if (celestialObjectPortal != null) { if (!celestialObjectPortal.isInsideBorder(blockPos.getX(), blockPos.getZ()) ) { + final EntityPlayer entityPlayer = world.getClosestPlayer(blockPos.getX(), blockPos.getY(), blockPos.getZ(), 10.0D, false); + if (entityPlayer != null) { + entityPlayer.sendStatusMessage( + new WarpDriveText(Commons.getStyleWarning(), "warpdrive.world_border.portal_denied"), true); + } + WarpDrive.logger.info(String.format("Nether portal opening cancelled %s for player %s: portal entry is outside the world border", + entityPlayer == null ? "-null-" : entityPlayer.getName(), + Commons.format(world, blockPos) )); return false; } @@ -187,6 +199,14 @@ public class CelestialObjectManager extends XmlFileManager { final int zExit = (int) Math.floor(blockPos.getZ() * factor); if ( Math.abs(xExit - celestialObjectExit.dimensionCenterX) > celestialObjectExit.borderRadiusX || Math.abs(zExit - celestialObjectExit.dimensionCenterZ) > celestialObjectExit.borderRadiusZ ) { + final EntityPlayer entityPlayer = world.getClosestPlayer(blockPos.getX(), blockPos.getY(), blockPos.getZ(), 10.0D, false); + if (entityPlayer != null) { + entityPlayer.sendStatusMessage( + new WarpDriveText(Commons.getStyleWarning(), "warpdrive.world_border.portal_denied"), true); + } + WarpDrive.logger.info(String.format("Nether portal opening cancelled for player %s %s: portal exit is outside the world border", + entityPlayer == null ? "-null-" : entityPlayer.getName(), + Commons.format(world, blockPos) )); return false; } } @@ -218,6 +238,22 @@ public class CelestialObjectManager extends XmlFileManager { return CLIENT.celestialObjects; } + @SuppressWarnings("unused") // Core mod + @SideOnly(Side.CLIENT) + public static WorldBorder World_getWorldBorder(@Nonnull final World world) { + final WorldBorder worldBorder = world.getWorldBorder(); + final EntityPlayer entityPlayer = Minecraft.getMinecraft().player; + if ( entityPlayer == null + || entityPlayer.world != world ) { + return worldBorder; + } + final CelestialObject celestialObject = get(world, (int) entityPlayer.posX, (int) entityPlayer.posZ); + if (celestialObject == null) { + return worldBorder; + } + return celestialObject.getWorldBorder(); + } + // *** non-static methods *** private void addOrUpdateInRegistry(@Nonnull final CelestialObject celestialObject, final boolean isUpdating) { diff --git a/src/main/java/cr0s/warpdrive/event/LivingHandler.java b/src/main/java/cr0s/warpdrive/event/LivingHandler.java index 21640468..2504bc12 100644 --- a/src/main/java/cr0s/warpdrive/event/LivingHandler.java +++ b/src/main/java/cr0s/warpdrive/event/LivingHandler.java @@ -112,17 +112,17 @@ public class LivingHandler { if ( Math.abs(distanceSquared) <= BORDER_WARNING_RANGE_BLOCKS_SQUARED && entityLivingBase instanceof EntityPlayer && entityLivingBase.ticksExisted % 40 == 0) { - Commons.addChatMessage( entityLivingBase, - new WarpDriveText(Commons.getStyleWarning(), "warpdrive.world_border.in_range", - (int) Math.sqrt(Math.abs(distanceSquared))) ); + ((EntityPlayer) entityLivingBase).sendStatusMessage( + new WarpDriveText(Commons.getStyleWarning(), "warpdrive.world_border.in_range", + (int) Math.sqrt(Math.abs(distanceSquared))), true ); } } else { if (entityLivingBase instanceof EntityPlayerMP) { if (((EntityPlayerMP) entityLivingBase).capabilities.isCreativeMode) { if (entityLivingBase.ticksExisted % 100 == 0) { - Commons.addChatMessage( entityLivingBase, - new WarpDriveText(Commons.getStyleWarning(), "warpdrive.world_border.outside", - (int) Math.sqrt(Math.abs(distanceSquared))) ); + ((EntityPlayer) entityLivingBase).sendStatusMessage( + new WarpDriveText(Commons.getStyleWarning(), "warpdrive.world_border.outside", + (int) Math.sqrt(Math.abs(distanceSquared))), true ); } return; } diff --git a/src/main/resources/assets/warpdrive/lang/de_de.lang b/src/main/resources/assets/warpdrive/lang/de_de.lang index 17be426f..37c1057c 100644 --- a/src/main/resources/assets/warpdrive/lang/de_de.lang +++ b/src/main/resources/assets/warpdrive/lang/de_de.lang @@ -980,4 +980,5 @@ warpdrive.transporter_signature.set=Transporter room is now linked to %1$s. warpdrive.world_border.in_range=Proximity alert: world border is only %1$d m away! warpdrive.world_border.outside=You're %1$d m outside the world border... +warpdrive.world_border.portal_denied=Portal opening cancelled to prevent a certain death! warpdrive.world_border.reached=You've reached the world border... diff --git a/src/main/resources/assets/warpdrive/lang/en_us.lang b/src/main/resources/assets/warpdrive/lang/en_us.lang index 79e477b7..3d1b75b9 100644 --- a/src/main/resources/assets/warpdrive/lang/en_us.lang +++ b/src/main/resources/assets/warpdrive/lang/en_us.lang @@ -980,4 +980,5 @@ warpdrive.transporter_signature.set=Transporter room is now linked to %1$s. warpdrive.world_border.in_range=Proximity alert: world border is only %1$d m away! warpdrive.world_border.outside=You're %1$d m outside the world border... +warpdrive.world_border.portal_denied=Portal opening cancelled to prevent a certain death! warpdrive.world_border.reached=You've reached the world border... diff --git a/src/main/resources/assets/warpdrive/lang/fr_fr.lang b/src/main/resources/assets/warpdrive/lang/fr_fr.lang index 60af29e7..7d481712 100644 --- a/src/main/resources/assets/warpdrive/lang/fr_fr.lang +++ b/src/main/resources/assets/warpdrive/lang/fr_fr.lang @@ -978,6 +978,7 @@ warpdrive.transporter_signature.set_self=Transporter room can't target itself! warpdrive.transporter_signature.set_same=Transporter room is already linked to %1$s. warpdrive.transporter_signature.set=Transporter room is now linked to %1$s. -warpdrive.world_border.in_range=Proximity alert: world border is only %1$d m away! -warpdrive.world_border.outside=You're %1$d m outside the world border... -warpdrive.world_border.reached=You've reached the world border... +warpdrive.world_border.in_range=Alerte de proximité: frontière du monde à %1$d m! +warpdrive.world_border.outside=Tu es %1$d m au-delà de la frontière du monde... +warpdrive.world_border.portal_denied=Ouverture du portail annulée pour éviter une mort certaine! +warpdrive.world_border.reached=Tu as atteint la frontière du monde... diff --git a/src/main/resources/assets/warpdrive/lang/nl_nl.lang b/src/main/resources/assets/warpdrive/lang/nl_nl.lang index e8a707b9..c5c267c4 100644 --- a/src/main/resources/assets/warpdrive/lang/nl_nl.lang +++ b/src/main/resources/assets/warpdrive/lang/nl_nl.lang @@ -979,4 +979,5 @@ warpdrive.transporter_signature.set=Transporter room is now linked to %1$s. warpdrive.world_border.in_range=Proximity alert: world border is only %1$d m away! warpdrive.world_border.outside=You're %1$d m outside the world border... +warpdrive.world_border.portal_denied=Portal opening cancelled to prevent a certain death! warpdrive.world_border.reached=You've reached the world border... diff --git a/src/main/resources/assets/warpdrive/lang/ru_ru.lang b/src/main/resources/assets/warpdrive/lang/ru_ru.lang index ead35727..352cf00d 100644 --- a/src/main/resources/assets/warpdrive/lang/ru_ru.lang +++ b/src/main/resources/assets/warpdrive/lang/ru_ru.lang @@ -980,4 +980,5 @@ warpdrive.transporter_signature.set=Transporter room is now linked to %1$s. warpdrive.world_border.in_range=Proximity alert: world border is only %1$d m away! warpdrive.world_border.outside=You're %1$d m outside the world border... +warpdrive.world_border.portal_denied=Portal opening cancelled to prevent a certain death! warpdrive.world_border.reached=You've reached the world border... diff --git a/src/main/resources/assets/warpdrive/lang/zh_cn.lang b/src/main/resources/assets/warpdrive/lang/zh_cn.lang index 61d77057..d6f3b19f 100644 --- a/src/main/resources/assets/warpdrive/lang/zh_cn.lang +++ b/src/main/resources/assets/warpdrive/lang/zh_cn.lang @@ -985,4 +985,5 @@ warpdrive.transporter_signature.set=Transporter room is now linked to %1$s. warpdrive.world_border.in_range=Proximity alert: world border is only %1$d m away! warpdrive.world_border.outside=You're %1$d m outside the world border... +warpdrive.world_border.portal_denied=Portal opening cancelled to prevent a certain death! warpdrive.world_border.reached=You've reached the world border... diff --git a/src/main/resources/assets/warpdrive/lang/zh_tw.lang b/src/main/resources/assets/warpdrive/lang/zh_tw.lang index 98f889c7..e615c64d 100644 --- a/src/main/resources/assets/warpdrive/lang/zh_tw.lang +++ b/src/main/resources/assets/warpdrive/lang/zh_tw.lang @@ -979,4 +979,5 @@ warpdrive.transporter_signature.set=Transporter room is now linked to %1$s. warpdrive.world_border.in_range=Proximity alert: world border is only %1$d m away! warpdrive.world_border.outside=You're %1$d m outside the world border... +warpdrive.world_border.portal_denied=Portal opening cancelled to prevent a certain death! warpdrive.world_border.reached=You've reached the world border...