samedi 10 août 2019

Creating instance of object without calling superclass constructor

Yes, my title sounds like I'm insane, but bear with me.

I'm trying to log everything a Minecraft Forge mod sends via its SimpleNetworkWrapper instance. To do this, I'm wrapping the instance in a dummy class and inserting the dummy instance into the mod via reflection.
Dummy class:

package net.benjaminurquhart.decimated;

import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.Packet;

public class FakeNetworkWrapper extends SimpleNetworkWrapper {

    private SimpleNetworkWrapper real;

    public FakeNetworkWrapper() {
        super("ctx");
    }

    protected void setChannel(SimpleNetworkWrapper channel) {
        this.real = channel;
    }
    @Override
    public Packet getPacketFrom(IMessage message) {
        return real.getPacketFrom(message);
    }
    @Override
    public void sendToAll(IMessage message) {
        real.sendToAll(message);
    }
    @Override
    public void sendTo(IMessage message, EntityPlayerMP player) {
        real.sendTo(message, player);
    }

    @Override
    public void sendToServer(IMessage message) {
        // Intercept messages here, do logging stuff
        real.sendToServer(message);
    }
}

The problem is, the superclass constructor creates a new packet channel with the given name (in this case, ctx). This breaks the real channel, since I'm creating a new channel with the same name. I can't omit the super call since there's no default constructor, and I prefer not to make a new unused channel with a different name.

Currently, I'm getting around the constructor by using Unsafe:

Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
unsafe = (Unsafe) unsafeField.get(null);

FakeNetworkWrapper wrapper = (FakeNetworkWrapper) unsafe.allocateInstance(FakeNetworkWrapper.class);
wrapper.setChannel(mod.getPacketChannel());

Obviously, I'd like to not use internal classes.

A quick google search shows that I can use serialization or ReflectionFactory instead of Unsafe. ReflectionFactory is also an internal class and serialization seems overkill. I'd also like to not include dependencies not provided by Forge (like this answer suggests).

Is there a way to somehow bypass a call to the superclass constructor without using internal methods or serialization? Again, I understand this is something I shouldn't be doing, but I don't see another way.





Aucun commentaire:

Enregistrer un commentaire