WIP HOWTO replace or alter buildin IC2e machines or stuff added by other addons (mod over a mod)

  • First of all, if you dont like reflections or reverse engineering this article not for you.
    Code included still WIP and some parts "not very good" due to lack of time to benchmark everything.
    Expected that you use Forge with SRG names for development.


    Story:
    In far far away SMP server players were unable to find iridium sample, some users joined dark side, others kept looting with no success.
    After 2 hours run i decided that this is fucking korea and must be fixed;
    This thread about how to replace TE objects on existing world without loss of devices.


    Modding go in two stages:
    First you mush ensure that your code executed in proper time, in current case after all mods you wanted to edit already constructed and ready to go, this can be cone by loadafter annotation (for each mod you want to alter) or by forcing your mod to construct last:



    This method resort modlist and place mod with modid "YOURMODNAMEID" to last position of list, this shoud be done only single time (i missed init field soo it called two times but no harm done), calling this method shoud be done at preinit stage.
    Main part of code shoud be placed to postinit stage, in other case result in undefined.


    Note: "Fetch_FieldEx" is wrapper over reflections that search fields of class and all it's superclasses.


    Second stage is actual changes, this done by reflections, when scaning for fields workspace and srg name shoud be checked, in other case your workspace or constructed mod will fail to work:

    Code
    discover = (HashMap) UnsafeImp.Fetch_FieldEx(TileEntity.class, "nameToClassMap","field_70326_a");


    Fetch_FieldEx will discover and read field with given name: nameToClassMap for workspace and field_70326_a for SRG obfuscated enviroment.


    To minimize version dependency reflections used only when absolutely necessary, in our case registerTileEntity throw exception if TE with given name already present soo we remove it from Map before registering modded TE:


    Code
    discover.remove("Replicator");
    		GameRegistry.registerTileEntity(TileEntityReplicatorImp.class, "Replicator");


    TileEntityReplicatorImp.class is custom version of TileEntityReplicator :



    Now replicator is pattern storage itself with all registered scanner recipes build in, also it's completely API compatable, soo other mods that want pattern storage also will have access to all recipes.


    This change effect only replicators loaded from world save, new placed replicators will keep initial class, this i result of IC2e multiblock implementation, additional TE declaration hardcoded into blockMachine2.class, soo we have no choice expect replace it to:


    Replacement done in two stages, first we cleanup blocklist:

    Quote

    Block.blocksList[Ic2Items.replicator.itemID] = null;


    NOTE: Ic2Items.replicator.itemID hold block ID, this can be seen from original constructor's source code.
    Without this game will fail to start.


    Due to IC2e blockIDassigner bug, leaving item reference will cause game crash without stating that problem with dublicate ID soo we also cleanup item reference:

    Code
    Item.itemsList	[Ic2Items.replicator.itemID] = null;


    Now we can register block again, since there is no constructor with ID specification, we must "cheat" IC2 with fake configuration that return value we want:



    Now we can allocate block again with same ID but different class:

    Code
    new BlockMachine2Imp(new ConfigurationImp(new Property("block",Ic2Items.replicator.itemID+"",Type.INTEGER)), InternalName.blockMachine2);


    Now we can run game, place Replicator and enjoy all recipes embedded initially.
    Same actions can be used to replace all types of TE objects including vanilla ones (disabling furnace or changing vanilla chest size anyone?);
    ps. same work in bukkit, this allow to a replace nearly everything serverside, if done properly all changes will work smooth in unmodded client.

    • Official Post

    RawCode, I know you downloaded GT several times now (there is no other reason to go look into the first post of my Thread right after I post the Changelog to my Update). I guess that was for testing purposes.


    And It is easyly possible to load after GT. I even have an API Hook for that if people don't want to mess with load orders.

  • this all about mods and modders who dont like any type of modifications and ever dont support config options (there is no config option for replicator-scanner-storage combo to open all recipes initially), currently IC2e block and TE registration does not allow to replace or change buildin stuff without magic, methods like createTileEntity hardcoded, block constructors are hardcoded.


    some versions ago recycler banlist and miner's valueble ore featured hardcoded components (or still have hardcoded part not checked fresh versions) that cannot be removed without hacks.


    as for mods, i try to download and decompile\check source of everything, few days ago i found method for one sided windows (ARS magica) that can be used in multiple places, also it will fit IC2e obscurator, there is no way to learn something without checking work of other people.

    • Official Post

    So I tried to use your Code and it works indeed. Good, that I have an API for loading Stuff after my Postload Phase if someone REALLY wants to do that. I would use "after:*", but UE-Basic-Components is breaking that Feature by being the one using it (since still only one single Mod can use "after:*" at once).


    Incredible, that this little hacky piece of Code makes the whole Mod much more compatible with other Mods.

    if other mod used similar technique result is undefined or infinite loop based on exact implementation

    If another Mod uses this same technique "properly", then no Infinite Loops will happen. One just needs to do it in preload, since it won't affect the preload phase at all. And if you want to be 100% sure, just make it so, that this Function can only be called once.

  • Is here any way you can make it through @Mod Annotation with required-after: "modid" and also required-before: "modid" ?

    public void getForumUserData(Signature signature, User user) { if(user.equalsTo("Cass") && user.isOnline() { Forum.Out.println("signature")})return;}

  • You mean like "after:*"? Nope that doesn't work at all.

    Yep. I know few mods which using it. But, maybe its only tag if mod isnt installed it print on screen : Missing mod: Thaumcraft: Any etc. maybe.
    Well, Im not as big developer as you are, so, Im like you tell me that. Thnx :)

    public void getForumUserData(Signature signature, User user) { if(user.equalsTo("Cass") && user.isOnline() { Forum.Out.println("signature")})return;}