Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix OpenComputers/CodeChickenLib network leaks & EnderStorage frequency tracking #496

Merged
merged 5 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,8 @@ All changes are toggleable via config files.
* **Duplication Fixes:** Fixes various duplication exploits
* **Chocolate Quest Repoured**
* **Legacy Golden Feather:** Restores the golden feather behavior from the original Better Dungeons mod
* **CodeChicken Lib**
* **Packet Leak Fix:** Fixes network ByteBuf leaks from PacketCustom
* **CoFH Core**
* **Vorpal Enchantment Damage:** Sets the damage multiplier of the Vorpal enchantment
* **Compact Machines**
Expand All @@ -304,6 +306,8 @@ All changes are toggleable via config files.
* **Extinguishing Dodges:** Chance per dodge to extinguish the player when burning
* **Feathers Helper API Fix:** Fixes server-sided crashes when the Feathers Helper API is utilized
* **Sprinting Integration:** Configurable consumption of feathers when the player is sprinting
* **Ender Storage**
* **Fix Frequency Tracking:** Fixes storage frequencies being tracked multiple times
* **Epic Siege Mod**
* **Disable Digger AI Debug:** Disables leftover debug logging inside the digger AI of the beta builds
* **Extra Utilities 2**
Expand Down Expand Up @@ -347,6 +351,8 @@ All changes are toggleable via config files.
* **Radiation Environment Map:** Changes the data table of the radiation environment handler to improve tick time
* **OpenBlocks**
* **Last Stand Trigger Fix:** Fixes the Last Stand enchantment triggering too early on pre-mitigation damage (before enchants, potions, etc), instead of on post-mitigation damage.
* **OpenComputers**
* **Packet Leak Fix:** Fixes network ByteBuf leaks from PacketHandler
* **ProjectRed**
* **Duplication Fixes:** Fixes various duplication exploits
* **Quark**
Expand Down
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ dependencies {
compileOnly rfg.deobf('curse.maven:ceramics-250617:3158763')
compileOnly rfg.deobf('curse.maven:chameleon-230497:2450900')
compileOnly rfg.deobf('curse.maven:chickens-241941:2537643')
compileOnly rfg.deobf('curse.maven:codechickenlib-242818:2779848')
compileOnly rfg.deobf('curse.maven:collective-342584:3533131')
compileOnly rfg.deobf('curse.maven:cqrepoured-303422:3953103')
compileOnly rfg.deobf('curse.maven:elementary-staffs-346007:2995593')
Expand All @@ -151,6 +152,7 @@ dependencies {
compileOnly rfg.deobf('curse.maven:modtweaker-220954:3840577')
compileOnly rfg.deobf('curse.maven:nuclearcraft-226254:3784145')
compileOnly rfg.deobf('curse.maven:openblocks-228816:2699056')
compileOnly rfg.deobf('curse.maven:opencomputers-223008:5274236')
compileOnly rfg.deobf('curse.maven:reborn-core-237903:3330308')
compileOnly rfg.deobf('curse.maven:reskillable-286382:2815686')
compileOnly rfg.deobf('curse.maven:requious-frakto-336748:3218640')
Expand All @@ -177,12 +179,12 @@ dependencies {
compileOnly 'curse.maven:arcanearchives-311357:3057332'
compileOnly 'curse.maven:bewitchment-285439:3044569'
compileOnly 'curse.maven:chisel-235279:2915375'
compileOnly 'curse.maven:codechickenlib-242818:2779848'
compileOnly 'curse.maven:cofhworld-271384:2920434'
compileOnly 'curse.maven:compactmachines-224218:2707509'
compileOnly 'curse.maven:effortlessbuilding-302113:2847346'
compileOnly 'curse.maven:endercore-231868:2972849'
compileOnly 'curse.maven:enderio-64578:2989201'
compileOnly 'curse.maven:enderstorage-245174:2755787'
compileOnly 'curse.maven:extrautilities-225561:2678374'
compileOnly 'curse.maven:forgemultipartcbe-258426:2755790' // aka "CB Multipart"
compileOnly 'curse.maven:guideapi-228832:2645992'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public class UTConfigMods
@Config.Name("CB Multipart/Forge Multipart CBE")
public static final CBMultipartCategory CB_MULTIPART = new CBMultipartCategory();

@Config.LangKey("cfg.universaltweaks.modintegration.ccl")
@Config.Name("CodeChicken Lib")
public static final CodeChickenLibCategory CCL = new CodeChickenLibCategory();

@Config.LangKey("cfg.universaltweaks.modintegration.chisel")
@Config.Name("Chisel")
public static final ChiselCategory CHISEL = new ChiselCategory();
Expand Down Expand Up @@ -79,6 +83,10 @@ public class UTConfigMods
@Config.Name("Elenai Dodge 2")
public static final ElenaiDodge2Category ELENAI_DODGE_2 = new ElenaiDodge2Category();

@Config.LangKey("cfg.universaltweaks.modintegration.enderstorage")
@Config.Name("Ender Storage")
public static final EnderStorageCategory ENDER_STORAGE = new EnderStorageCategory();

@Config.LangKey("cfg.universaltweaks.modintegration.esm")
@Config.Name("Epic Siege Mod")
public static final EpicSiegeModCategory EPIC_SIEGE_MOD = new EpicSiegeModCategory();
Expand Down Expand Up @@ -147,6 +155,10 @@ public class UTConfigMods
@Config.Name("OpenBlocks")
public static final OpenBlocksCategory OPEN_BLOCKS = new OpenBlocksCategory();

@Config.LangKey("cfg.universaltweaks.modintegration.opencomputers")
@Config.Name("OpenComputers")
public static final OpenComputersCategory OPEN_COMPUTERS = new OpenComputersCategory();

@Config.LangKey("cfg.universaltweaks.modintegration.projectred")
@Config.Name("ProjectRed")
public static final ProjectRedCategory PROJECTRED = new ProjectRedCategory();
Expand Down Expand Up @@ -354,6 +366,14 @@ public static class ChocolateQuestCategory
public boolean utCQRGoldenFeatherToggle = true;
}

public static class CodeChickenLibCategory
{
@Config.RequiresMcRestart
@Config.Name("Packet Leak Fix")
@Config.Comment("Fixes network ByteBuf leaks from PacketCustom")
public boolean utPacketLeakFixToggle = true;
}

public static class CoFHCoreCategory
{
@Config.Name("Vorpal Enchantment Damage")
Expand Down Expand Up @@ -411,6 +431,14 @@ public static class ElenaiDodge2Category
public int utED2SprintingFeatherRequirement = 6;
}

public static class EnderStorageCategory
{
@Config.RequiresMcRestart
@Config.Name("Fix Frequency Tracking")
@Config.Comment("Fixes storage frequencies being tracked multiple times")
public boolean utFrequencyTrackFixToggle = true;
}

public static class EpicSiegeModCategory
{
@Config.RequiresMcRestart
Expand Down Expand Up @@ -647,6 +675,14 @@ public static class OpenBlocksCategory
public boolean utLastStandFixToggle = true;
}

public static class OpenComputersCategory
{
@Config.RequiresMcRestart
@Config.Name("Packet Leak Fix")
@Config.Comment("Fixes network ByteBuf leaks from PacketHandler")
public boolean utPacketLeakFixToggle = true;
}

public static class ProjectRedCategory
{
@Config.RequiresMcRestart
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ public class UTMixinLoader implements ILateMixinLoader
put("mixins.mods.cbmultipart.json", () -> loaded("forgemultipartcbe") && UTConfigMods.CB_MULTIPART.utMemoryLeakFixToggle);
put("mixins.mods.ceramics.json", () -> loaded("ceramics"));
put("mixins.mods.chisel.tcomplement.dupes.json", () -> loaded("chisel") && loaded("tcomplement") && UTConfigMods.CHISEL.utDuplicationFixesToggle);
put("mixins.mods.codechickenlib.json", () -> loaded("codechickenlib") && UTConfigMods.CCL.utPacketLeakFixToggle);
put("mixins.mods.cofhcore.json", () -> loaded("cofhcore"));
put("mixins.mods.collective.json", () -> loaded("collective"));
put("mixins.mods.cqrepoured.json", () -> loaded("cqrepoured"));
put("mixins.mods.effortlessbuilding.json", () -> loaded("effortlessbuilding"));
put("mixins.mods.elementarystaffs.json", () -> loaded("element"));
put("mixins.mods.elenaidodge2.json", () -> loaded("elenaidodge2"));
put("mixins.mods.enderstorage.json", () -> loaded("enderstorage") && UTConfigMods.ENDER_STORAGE.utFrequencyTrackFixToggle);
put("mixins.mods.epicsiegemod.json", () -> loaded("epicsiegemod"));
put("mixins.mods.erebus.cabbage.json", () -> loaded("erebus") && UTConfigMods.EREBUS.utCabbageDrop);
put("mixins.mods.erebus.json", () -> loaded("erebus"));
Expand All @@ -78,6 +80,7 @@ public class UTMixinLoader implements ILateMixinLoader
put("mixins.mods.netherrocks.json", () -> loaded("netherrocks"));
put("mixins.mods.nuclearcraft.json", () -> loaded("nuclearcraft"));
put("mixins.mods.openblocks.json", () -> loaded("openblocks") && UTConfigMods.OPEN_BLOCKS.utLastStandFixToggle);
put("mixins.mods.opencomputers.json", () -> loaded("opencomputers") && UTConfigMods.OPEN_COMPUTERS.utPacketLeakFixToggle);
put("mixins.mods.quark.dupes.json", () -> loaded("quark") && UTConfigMods.QUARK.utDuplicationFixesToggle);
put("mixins.mods.requiousfrakto.json", () -> loaded("requious") && UTConfigMods.REQUIOUS_FRAKTO.utParticleFixesToggle);
put("mixins.mods.reskillable.json", () -> loaded("reskillable"));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package mod.acgaming.universaltweaks.mods.codechickenlib.mixin;

import codechicken.lib.packet.PacketCustom;
import net.minecraft.network.INetHandler;
import org.apache.commons.lang3.Validate;
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.CallbackInfo;

// Courtesy of jchung01
@Mixin(value = PacketCustom.ClientInboundHandler.class, remap = false)
public class UTPacketCustomClientMixin
{
/**
* This releases the COPIED ByteBuf that was created and assigned to PacketCustom.buf in the ctor.
* @reason Release wrapped ByteBuf after whatever mod has handled the packet.
*/
@Inject(method = "handle", at = @At(value = "INVOKE", target = "Lcodechicken/lib/packet/ICustomPacketHandler$IClientPacketHandler;handlePacket(Lcodechicken/lib/packet/PacketCustom;Lnet/minecraft/client/Minecraft;Lnet/minecraft/network/play/INetHandlerPlayClient;)V", shift = At.Shift.AFTER))
private void utReleaseClientBuf(INetHandler netHandler, String channel, PacketCustom packet, CallbackInfo ci)
{
Validate.isTrue(packet.refCnt() == 1);
packet.release();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package mod.acgaming.universaltweaks.mods.codechickenlib.mixin;

import codechicken.lib.packet.PacketCustom;
import io.netty.channel.ChannelHandlerContext;
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
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.CallbackInfo;

// Courtesy of jchung01
@Mixin(value = PacketCustom.CustomInboundHandler.class, remap = false)
public class UTPacketCustomReleaseMixin
{
/**
* This releases the ORIGINAL FMLProxyPacket payload that was passed into and copied by PacketCustom's constructor.
* <p>
* For S->C packets, some are reused and sent to multiple clients, so those packets are retained in {@link UTPacketCustomRetainMixin}.
* @reason Release the message's payload after everything has been handled.
*/
@Inject(method = "channelRead0(Lio/netty/channel/ChannelHandlerContext;Lnet/minecraftforge/fml/common/network/internal/FMLProxyPacket;)V", at = @At(value = "TAIL"))
private void utReleasePayload(ChannelHandlerContext ctx, FMLProxyPacket msg, CallbackInfo ci)
{
msg.payload().release();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package mod.acgaming.universaltweaks.mods.codechickenlib.mixin;

import java.util.List;
import java.util.function.Predicate;
import codechicken.lib.packet.PacketCustom;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.INetHandler;
import net.minecraft.network.Packet;
import net.minecraft.server.management.PlayerChunkMapEntry;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

/**
* This mixin retains PacketCustom payloads, increasing the ref count by the number of players
* that are to receive the packet. This is necessary as the payload is shared between all receivers
* and each receiver releases the payload in {@link UTPacketCustomReleaseMixin}.
* <p>
* CCL doesn't fully utilize Forge's built-in networking, so this mixin adds the missing behavior that
* {@link net.minecraftforge.fml.common.network.FMLOutboundHandler.OutboundTarget#selectNetworks} and
* {@link net.minecraftforge.fml.common.network.FMLOutboundHandler#write}
* would normally do to clean up packets.
* @author jchung01
*/
@Mixin(value = PacketCustom.class, remap = false)
public abstract class UTPacketCustomRetainMixin
{
@Shadow
public abstract boolean release();

@Inject(method = "sendToClients(Lnet/minecraft/network/Packet;)V", at = @At(value = "HEAD"))
private static void utRetainForAllClients(Packet<INetHandler> packet, CallbackInfo ci)
{
ut$retainForPlayers(packet, player -> true);
}

@Inject(method = "sendToAllAround", at = @At(value = "HEAD"))
private static void utRetainForAllAround(Packet<INetHandler> packet, double x, double y, double z, double range, int dim, CallbackInfo ci)
{
ut$retainForPlayers(packet, player -> {
if (player.dimension != dim) return false;
double dx = player.posX - x;
double dy = player.posY - y;
double dz = player.posZ - z;
return dx * dx + dy * dy + dz * dz < range * range;
});
}

@Inject(method = "sendToDimension(Lnet/minecraft/network/Packet;I)V", at = @At(value = "HEAD"))
private static void utRetainForAllInDimension(Packet<INetHandler> packet, int dim, CallbackInfo ci)
{
ut$retainForPlayers(packet, player -> player.dimension == dim);
}

@Inject(method = "sendToChunk(Lnet/minecraft/network/Packet;Lnet/minecraft/world/World;II)V", at = @At(value = "HEAD"))
private static void utRetainForAllInChunk(Packet<INetHandler> packet, World world, int chunkX, int chunkZ, CallbackInfo ci)
{
PlayerChunkMapEntry playersInChunk = ((WorldServer) world).getPlayerChunkMap().getEntry(chunkX, chunkZ);
if (playersInChunk != null) ut$retainForPlayers(packet, playersInChunk::containsPlayer);
}

@Inject(method = "sendToOps(Lnet/minecraft/network/Packet;)V", at = @At(value = "HEAD"))
private static void utRetainForOps(Packet<INetHandler> packet, CallbackInfo ci)
{
ut$retainForPlayers(packet, player -> FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().canSendCommands(player.getGameProfile()));
}

/**
* Release this buf after copying it, just to be safe.
*/
@Inject(method = "toPacket", at = @At(value = "RETURN"))
private void utReleaseOriginal(CallbackInfoReturnable<FMLProxyPacket> cir)
{
this.release();
}

@Unique
private static void ut$retainForPlayers(Packet<INetHandler> packet, Predicate<EntityPlayerMP> condition)
{
if (packet instanceof FMLProxyPacket)
{
List<EntityPlayerMP> playerList = FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayers();
// Check for null dispatchers like Forge's FMLOutboundHandler.OutboundTarget#selectNetworks does.
Predicate<EntityPlayerMP> hasNetworkDispatcher = player -> player.connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get() != null;
int retainCount = (int) (playerList.stream().filter(condition.and(hasNetworkDispatcher)).count() - 1);
if (retainCount > 0) ((FMLProxyPacket) packet).payload().retain(retainCount);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package mod.acgaming.universaltweaks.mods.codechickenlib.mixin;

import codechicken.lib.packet.PacketCustom;
import net.minecraft.network.INetHandler;
import org.apache.commons.lang3.Validate;
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.CallbackInfo;

// Courtesy of jchung01
@Mixin(value = PacketCustom.ServerInboundHandler.class, remap = false)
public class UTPacketCustomServerMixin
{
/**
* This releases the COPIED ByteBuf that was created and assigned to PacketCustom.buf in the ctor.
* @reason Release wrapped ByteBuf after whatever mod has handled the packet.
*/
@Inject(method = "handle", at = @At(value = "INVOKE", target = "Lcodechicken/lib/packet/ICustomPacketHandler$IServerPacketHandler;handlePacket(Lcodechicken/lib/packet/PacketCustom;Lnet/minecraft/entity/player/EntityPlayerMP;Lnet/minecraft/network/play/INetHandlerPlayServer;)V", shift = At.Shift.AFTER))
private void utReleaseServerBuf(INetHandler netHandler, String channel, PacketCustom packet, CallbackInfo ci)
{
Validate.isTrue(packet.refCnt() == 1);
packet.release();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package mod.acgaming.universaltweaks.mods.enderstorage.mixin;

import java.util.Objects;
import codechicken.enderstorage.api.Frequency;
import codechicken.lib.colour.EnumColour;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;

// Courtesy of jchung01
@Mixin(value = Frequency.class, remap = false)
public class UTFrequencyMixin
{
@Shadow
public EnumColour left;
@Shadow
public EnumColour middle;
@Shadow
public EnumColour right;
@Shadow
public String owner;

/**
* Add equals() override to fulfill Object equality contract.
*/
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Frequency that = (Frequency) o;
return left == that.left && middle == that.middle && right == that.right && Objects.equals(owner, that.owner);
}

/**
* @author jchung01
* @reason Use a more proper hashCode method.
*/
@Override
@Overwrite
public int hashCode()
{
return Objects.hash(left, middle, right, owner);
}
}
Loading
Loading