Jump to content

Recommended Posts

Posted

I want to create an extension for my mod that requires another mod, but I don't want to have to make separate mods that add that functionality. So instead, I want to integrate that extension in the main mod, but make it so that it fires when that mod is installed alongside.

 

Any ideas?

Posted
  On 2/23/2014 at 10:40 AM, diesieben07 said:

Make an interface, let's call it Module. In there add the methods you need, load() should be enough for a start. Then in your main mod make a Collection of these modules and call the load() method on every one of them in preInit. Then make class that implements said Module interface and does the mod interaction stuff. Then you check with Loader.isModLoaded()= if the other mod is loaded and if so, load the module and add it to the collection. Otherwise you don't load it. Make sure you do not directly reference the class name of the module, only via a String constant (Class.forName("whatever.your.package.is.MyModule").newInstance()) so that it really only gets loaded when the other mod is there.

 

Hope that made any sense. Describing a coding concept is hard :D

 

Would it be okay if you were to add source code for me to clarify? Sorry, it's just that I couldn't get my head around that. I know how interfaces work, but...

Posted

A simpler, but perhaps less elegant solution:

// in your main mod class:
public static boolean isOtherModLoaded;

// in PreInit, initialize the field:
isOtherModLoaded = Loader.isModLoaded("other_mod_id");

// then whenever you want to do something that relates to that other mod,
// just check if it's loaded:
if (isOtherModLoaded) {
// do your stuff
}

Posted

diesieben07's and other similar methods is the only way I know of if you have source dependencies where you want to import any type from the other mod, rather than just use a basic Block returned by GameRegistry or such. If that "do your stuff" depends on anything from the other mod, then you will get a NoClassDefFoundError as soon as Java tries to load your classes because it tries to fully resolve everything as soon as the class files are loaded, not waiting until the first reference is actually executed (the contents of your if statement).

 

Just make a central class (ideally in its own package to keep things separate, say mymodpackage.othermod.Extension implementing an interface mymodpackage.IExtension) for the extension. And make sure that nothing else in your mod ever imports one of the classes from that package (likely to give you a NoClassDefFound if the other mod isn't present).

 

If you detect the mod is present (be careful of load order, e.g. I think its possible for Loader.isModLoaded to return false for a mod that is present if you call it too early, possible preinit and certainly any static initialisers) then use "(IExtension)Class.forName("mymodpackage.othermod.Extension").newInstance()" to get an instance of that class without it ever being imported (Java will only attempt to load those class files at this point, avoiding the NoClassDefFound if the other mod is not present). You could also thus do a try/catch around the Class.forName(...).netInstancerather than check Loader.isModLoaded.

Posted
  On 2/23/2014 at 12:36 PM, Sync Views said:

diesieben07's and other similar methods is the only way I know of if you have source dependencies where you want to import any type from the other mod, rather than just use a basic Block returned by GameRegistry or such. If that "do your stuff" depends on anything from the other mod, then you will get a NoClassDefFoundError as soon as Java tries to load your classes because it tries to fully resolve everything as soon as the class files are loaded, not waiting until the first reference is actually executed (the contents of your if statement).

 

Just make a central class (ideally in its own package to keep things separate, say mymodpackage.othermod.Extension implementing an interface mymodpackage.IExtension) for the extension. And make sure that nothing else in your mod ever imports one of the classes from that package (likely to give you a NoClassDefFound if the other mod isn't present).

 

If you detect the mod is present (be careful of load order, e.g. I think its possible for Loader.isModLoaded to return false for a mod that is present if you call it too early, possible preinit and certainly any static initialisers) then use "(IExtension)Class.forName("mymodpackage.othermod.Extension").newInstance()" to get an instance of that class without it ever being imported (Java will only attempt to load those class files at this point, avoiding the NoClassDefFound if the other mod is not present). You could also thus do a try/catch around the Class.forName(...).netInstancerather than check Loader.isModLoaded.

Okay, I think this is slightly easier for me to understand, but I may need some example code of this to clarify.

Posted
  On 2/23/2014 at 12:04 PM, coolAlias said:

A simpler, but perhaps less elegant solution:

// in your main mod class:
public static boolean isOtherModLoaded;

// in PreInit, initialize the field:
isOtherModLoaded = Loader.isModLoaded("other_mod_id");

// then whenever you want to do something that relates to that other mod,
// just check if it's loaded:
if (isOtherModLoaded) {
// do your stuff
}

This is exactly as I do. And consider dependencies - after, required-after...

Posted
  On 2/23/2014 at 4:05 PM, Alexiy said:

This is exactly as I do. And consider dependencies - after, required-after...

No, I don't want to declare dependencies, I want my mod to be in its simple state when the other mods aren't loaded, but when those other mods are loaded, I want to make it so that extensions for those mods only load up then.

Posted
  On 2/23/2014 at 5:58 PM, Ti Ex Ex said:

No, I don't want to declare dependencies, I want my mod to be in its simple state when the other mods aren't loaded, but when those other mods are loaded, I want to make it so that extensions for those mods only load up then.

"Dependency" in this case does not mean that your mod requires the other mod, it's a field in the mcmod.info file that FML uses to determine load order, so if your mod is "dependent" i.e. capable of using stuff from another mod, then FML will be sure to load that mod first; this ensures that Loader.isModLoaded will work correctly when it comes your mod's turn to load.

 

On a side note, the method I described works fine even for classes that implement / extend a class in another mod, so long as you do not use that class anywhere in your mod when the other mod is not loaded. For instance, I have a sword class for my Zelda swords, and I wanted them compatible with BattleGear2 dual-wielding, so this is what I did:

// create a second class extending my swords:
public class ItemZeldaSwordBG2 extends ItemZeldaSword implements IBattlegearWeapon {
// super constructor plus BG2 interface implementation only
}

// then when I declare my items:
if (Loader.isModLoaded("battlegear2")) {
swordKokiri = new ItemZeldaSwordBG2(blah blah blah);
} else {
swordKokiri = new ItemZeldaSword(blah blah blah);
}

In this way  my mod works fine with or without BattleGear2, but if BG2 is installed alongside, it will use the correct class that interfaces with BG2.

 

It seems wasteful to have 2 classes for the same Item, but I couldn't figure out any way to add the interface and have the mod still work independently.

Posted
  On 2/23/2014 at 11:46 PM, coolAlias said:

On a side note, the method I described works fine even for classes that implement / extend a class in another mod, so long as you do not use that class anywhere in your mod when the other mod is not loaded. For instance, I have a sword class for my Zelda swords, and I wanted them compatible with BattleGear2 dual-wielding, so this is what I did:

// create a second class extending my swords:
public class ItemZeldaSwordBG2 extends ItemZeldaSword implements IBattlegearWeapon {
// super constructor plus BG2 interface implementation only
}

// then when I declare my items:
if (Loader.isModLoaded("battlegear2")) {
swordKokiri = new ItemZeldaSwordBG2(blah blah blah);
} else {
swordKokiri = new ItemZeldaSword(blah blah blah);
}

In this way  my mod works fine with or without BattleGear2, but if BG2 is installed alongside, it will use the correct class that interfaces with BG2.

 

It seems wasteful to have 2 classes for the same Item, but I couldn't figure out any way to add the interface and have the mod still work independently.

Had to add my answer here, since i work on Battlegear2.

The @Optional from fml can "remove" interfaces depending on a mod being installed or not.

This is one case where bytecode manipulation is more interesting than reflection, since it allows to hide the code that would crash/throw exception otherwise.

The best part being that you don't need to understand asm to use @Optional.

 

Posted
  On 2/24/2014 at 12:01 AM, GotoLink said:

Had to add my answer here, since i work on Battlegear2.

The @Optional from fml can "remove" interfaces depending on a mod being installed or not.

This is one case where bytecode manipulation is more interesting than reflection, since it allows to hide the code that would crash/throw exception otherwise.

The best part being that you don't need to understand asm to use @Optional.

I don't suppose you could provide a short example of how the annotation would look above a class? Whenever I try to add it, I get an error saying I need to fix my project setup because it can't find Optional, and even manually importing the cpw.mods.fml.common package doesn't resolve the issue.

 

The java docs in the Optional class itself weren't enough for me to make sense of what the syntax ought to be. Sorry if this is considered basic Java, but it's not something I'm familiar with.

 

Thanks for the help!

Posted
  On 2/24/2014 at 3:07 AM, coolAlias said:

I don't suppose you could provide a short example of how the annotation would look above a class? Whenever I try to add it, I get an error saying I need to fix my project setup because it can't find Optional, and even manually importing the cpw.mods.fml.common package doesn't resolve the issue.

 

The java docs in the Optional class itself weren't enough for me to make sense of what the syntax ought to be. Sorry if this is considered basic Java, but it's not something I'm familiar with.

 

Thanks for the help!

Well, i guess it would help a lot of people to understand, so, here is a full description.

 

Optional has three annotations, Optional.@InterfaceList, Optional.@Interface, Optional.@Method.

The first two use @Target(ElementType.TYPE), meaning you put them above the class declaration. (like @Mod)

The latter has @Target(ElementType.METHOD) is obviously supposed to be put above a method. (like @Mod.EventHandler)

 

Optional.@InterfaceList accepts only a array of @Interface, while @Method only accepts a string, the modid.

 

Example time !

 

@Interface(iface="mods.battlegear2.api.IDyable", modid="battlegear2", striprefs = true)//Will strip IDyable interface from Battlegear2 API if it isn't loaded
public class ItemGun extends Item implements ISheathed, IDyable{

//imagine some working code here

@Method(modid="battlegear2")//Will strip that specific method if Battlegear2 isn't loaded
public boolean sheatheOnBack(ItemStack item){
     return false;
}
}

 

@InterfaceList(@Interface(iface="class.path.Interface1", modid="examplemod1"), @Interface(iface="class.path.Interface2", modid="examplemod2"))
public class AwesomeImplementation implements Interface1, Interface2{

Posted
  On 2/24/2014 at 1:15 PM, GotoLink said:

Well, i guess it would help a lot of people to understand, so, here is a full description.

 

Optional has three annotations, Optional.@InterfaceList, Optional.@Interface, Optional.@Method.

The first two use @Target(ElementType.TYPE), meaning you put them above the class declaration. (like @Mod)

The latter has @Target(ElementType.METHOD) is obviously supposed to be put above a method. (like @Mod.EventHandler)

 

Optional.@InterfaceList accepts only a array of @Interface, while @Method only accepts a string, the modid.

 

Example time !

Wow, no wonder it wasn't working for me, I was trying to add the @Optional directly...<facepalm>

Thanks so much for explaining that. This will be extremely useful :D

 

EDIT: Though this still doesn't prevent me from crashing when I try to run the client in Eclipse with BG2 as a referenced library... hmmm. One step at a time :P

Posted
  On 2/24/2014 at 1:45 PM, coolAlias said:

Wow, no wonder it wasn't working for me, I was trying to add the @Optional directly...<facepalm>

Thanks so much for explaining that. This will be extremely useful :D

 

EDIT: Though this still doesn't prevent me from crashing when I try to run the client in Eclipse with BG2 as a referenced library... hmmm. One step at a time :P

The ModAPITransformer should do the job.

I don't see why it wouldn't ?

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • But your Launcher does not find it   Java path is: /run/user/1000/doc/3f910b8/java Checking Java version... Java checker returned some invalid data we don't understand: Check the Azul Zulu site and select your OS and download the latest Java 8 build for Linux https://www.azul.com/downloads/?version=java-8-lts&package=jre#zulu After installation, check the path and put this path into your Launcher Java settings (Java Executable)
    • Try other builds of pehkui and origins++ until you find a working combination
    • Some Create addons are only compatible with Create 6 or Create 5 - so not both versions at the same time Try older builds of Create Stuff and Additions This is the last build before the Create 6 update: https://www.curseforge.com/minecraft/mc-mods/create-stuff-additions/files/6168370
    • ✅ Crobo Coupon Code: 51k3b0je — Get Your \$25 Amazon Gift Card Bonus! If you’re new to Crobo and want to make the most out of your first transaction, you’ve come to the right place. The **Crobo coupon code: 51k3b0je** is a fantastic way to get started. By using this code, you can unlock an exclusive **\$25 Amazon gift card** after completing your first eligible transfer. Let’s dive deep into how the **Crobo coupon code: 51k3b0je** works, why you should use it, and how to claim your reward. --- 🌟 What is Crobo? Crobo is a trusted, modern platform designed for **international money transfers**. It offers fast, secure, and low-cost transactions, making it a favorite choice for individuals and businesses alike. Crobo is committed to transparency, low fees, and competitive exchange rates. And with promo deals like the **Crobo coupon code: 51k3b0je**, it becomes even more attractive. Crobo focuses on providing customers with: * Quick transfer speeds * Minimal fees * Safe, encrypted transactions * Great referral and promo code rewards When you choose Crobo, you’re choosing a platform that values your time, money, and loyalty. And now with the **Crobo coupon code: 51k3b0je**, you can start your Crobo journey with a **bonus reward**! ---# 💥 What is the Crobo Coupon Code: 51k3b0je? The **Crobo coupon code: 51k3b0je** is a **special promotional code** designed for new users. By entering this code during signup, you’ll be eligible for: ✅ A **\$25 Amazon gift card** after your first qualifying transfer. ✅ Access to Crobo’s referral system to earn more rewards. ✅ The ability to combine with future seasonal Crobo discounts. Unlike generic promo codes that just offer small fee reductions, the **Crobo coupon code: 51k3b0je** directly gives you a tangible, valuable reward — perfect for online shopping or gifting. --- ### 🎯 Why Use Crobo Coupon Code: 51k3b0je? There are many reasons why users choose to apply the **Crobo coupon code: 51k3b0je**: 🌟 **Free bonus reward** — Your first transfer can instantly earn you a \$25 Amazon gift card. 🌟 **Trusted platform** — Crobo is known for secure, fast, and affordable transfers. 🌟 **Easy to apply** — Simply enter **Crobo coupon code: 51k3b0je** at signup — no complicated steps. 🌟 **Referral opportunities** — Once you’ve used **Crobo coupon code: 51k3b0je**, you can invite friends and earn more rewards. 🌟 **Stackable savings** — Pair **Crobo coupon code: 51k3b0je** with Crobo’s ongoing offers or holiday deals for even more benefits. --- ### 📝 How to Use Crobo Coupon Code: 51k3b0je Getting started with **Crobo coupon code: 51k3b0je** is quick and easy. Just follow these steps: 1️⃣ **Download the Crobo app** (available on Google Play Store and Apple App Store) or visit the official Crobo website. 2️⃣ **Start the sign-up process** by entering your basic details (name, email, phone number, etc.). 3️⃣ When prompted, enter **Crobo coupon code: 51k3b0je** in the promo code or coupon code field. 4️⃣ Complete your first transaction — be sure to meet the minimum amount required to qualify for the reward (usually specified in Crobo’s promo terms). 5️⃣ After the transaction is verified, receive your **\$25 Amazon gift card** directly via email or within your Crobo account. --- ### 💡 Tips to Maximize Your Crobo Coupon Code: 51k3b0je Bonus 👉 **Transfer the minimum qualifying amount or more** — this ensures you meet the conditions for the gift card. 👉 **Refer friends after your signup** — Crobo allows users who’ve signed up with codes like **Crobo coupon code: 51k3b0je** to share their own code for extra bonuses. 👉 **Check for additional Crobo promotions** — sometimes Crobo offers seasonal or regional deals that stack with the coupon code. 👉 **Complete your transaction soon after signup** — many bonuses have time limits, so act quickly! --- ### 🚀 Frequently Asked Questions about Crobo Coupon Code: 51k3b0je **Q: Can I use Crobo coupon code: 51k3b0je if I already have a Crobo account?** A: No — the **Crobo coupon code: 51k3b0je** is intended for **new users only**. It must be applied during the initial registration process. --- **Q: How long does it take to get the \$25 Amazon gift card after using Crobo coupon code: 51k3b0je?** A: Typically, the gift card is sent **within a few business days** after your first qualifying transfer is completed and verified. --- **Q: Are there hidden fees when using Crobo coupon code: 51k3b0je?** A: No — Crobo is transparent about its fees. The **Crobo coupon code: 51k3b0je** simply adds a bonus reward without increasing your costs. --- **Q: Can I combine Crobo coupon code: 51k3b0je with other promo codes?** A: The **Crobo coupon code: 51k3b0je** is generally applied as a standalone signup bonus. However, Crobo often offers **ongoing promotions** that may apply to future transactions. ---  📌 Reference Crobo promo code: {51k3b0je} Crobo discount code: {51k3b0je} --- # 🌍 Final Thoughts If you want to enjoy safe, fast, and affordable money transfers with an added bonus, **Crobo coupon code: 51k3b0je** is your best option. Not only will you experience excellent service, but you’ll also earn a **\$25 Amazon gift card** — a reward that you can use immediately for shopping or gifts. 👉 **Don’t wait — sign up today using Crobo coupon code: 51k3b0je and claim your bonus!**
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.