Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

A suggestion about automating object registration


ZDoctor
 Share

Recommended Posts

Registering items/blocks/etc is a real hassle, and usually big mods add their own support for registering a bunch of items. Which can be broken with an update. Perhaps it would be better if forge automated that process instead. I worked on such a system that may help.

 

For some time I worked on a mode called LazyModder and now LazyLibrary. The goal of the mod was to make modding easier for modders by handling a lot of the repetitive stuff when it comes registration of items/blocks/entities/etc.

 

I was successful and even made a few mods that use the lib, but I think it would be better if it was built in. I will explain a few of the classes and implementation could be as simple as adding all the classes so modders can have the option of using them, or just adding the methods, interfaces, etc directly to the item class. I am a proponent of the former option.

 

My library adds several classes on which others are built upon and has 2 classes dedicated for handling registration of the objects and their models. With an additional class dedicated to handling sorting the objects for registration and is the parent of the last two classes so that register objects are more readily available (similar to a proxy).

 

The EasyRegistry(GitHub) class is has a register method that takes in an IAutoRegister. These classes should automatically register themselves here and modders can do it manually if they like. The RegistryHandler(GitHub) class subscribes to the registration events and registers the appropriate objects to their registry. The ModelRegistryHandler(GitHub) class subscribes to the relevant Model Registration events and handles registering block/item/entity models along with some helper methods for binding TESR and living entity models.

 

The EasyItem(GitHub) class extends Item and handles its own registration. It adds support for subtypes (which are also automatically registered along with their models) and supports custom names based on meta(subtypes). It can even take in an item as an argument and automatically register that item as well. The EasyBlock(GitHub) class is similar to the item class. It extends the block class, has the same constructors and will automatically create an ItemBlock and register that. It also supports changing the ItemBlock as well. The EasyTileEntityBlock(GitHub) class extends EasyBlock(GitHub) and implements ITileEntity and adds default implementations that can be overridden.

 

Finally, the EasyLivingEntity(GitHub) class adds a few default values for entities (tracking range, send velocity update and update frequency; I'm pretty sure I used the values of an IronGolem) and adds egg support by just telling it what color the egg is or calling setHasEgg and passing true (default colors are black). It has a method getRendererClass that will try to guess the renderer class name based on the given entity name and the package of the entity class following the format <Package>.<modId>.client.renderer.entity.Render + <entityName>. The player would have to make their own renderer class within the expected package and would need to link it to their model class.

 

Some code example:

MoTD(GitHub) adds 13 entities with eggs and with models in 13 lines. By passing their Entity classes(GitHub) and created their EntitiyRenderer(GitHub) which the EasyLivingEntity(GitHub) class was able to find by itself.

MOTDBlocks(GitHub) created several blocks that extended EasyBlock(GitHub) by just passing a name and material. And MOTDItems(GitHub) created several items by just passing a name and creative tab to BaseItem(GitHub) that extends EasyItem(GitHub).

 

My hope with the automation of registration is for modders to be able to focus on adding content rather than registering it and perhaps make updating mods easier. My library has a bunch of other classes as well, but these are the base classes I feel would be the easiest to implement. These changes only add code and is aimed to work with the system with no changes to that system needed. Adding these classes wouldn't break anything.

 

Link to comment
Share on other sites

Short answer: No

Long Answer: All of this fluf just causes modders to do things incorrectly. All your default values are wrong, and nobody will change them thus causing duplicated defaults all over the place. Auto-magical registration is just ASKING for things to be statically initialized which your examples are showing are the case. Which is something we've been crusading against for years because it one of the things that prevents mods from being hot swapable. Not to mention your little hack to swap the current mod for registration is bad. As it screws up override tracking as well as bypasses the warning about invalid registry names. At the end of the day, you are not saving any time/code. As you still have to initalize your mods SOMEWHERE {you're doing it in preinit, you SHOULD be doing it in the Register event} and your method promotes way to many bad habits and technical issues that we've been trying to get modders to fix for years.

I do Forge for free, however the servers to run it arn't free, so anything is appreciated.
Patreon: http://www.patreon.com/lexmanos
Paypal: http://paypal.me/LexManos

BitCoin: 1Q8rWvUNMM2T1ZfDaFeeYQyVXtYoeT6tTn

Link to comment
Share on other sites

 

4 hours ago, LexManos said:

 As you still have to initalize your mods SOMEWHERE {you're doing it in preinit, you SHOULD be doing it in the Register event} and your method promotes way to many bad habits and technical issues that we've been trying to get modders to fix for years.

2

I don't quite understand what you mean by this. My mod/lib does not simply register in the preinit. It follows the same specifications that forge wants modders to follow. Modders can initialize items in the preInit, but in the background, my mod tracks these entries and waits for the appropriate registration event before registering them. What bad habits are you talking about? What technical issues?

 

4 hours ago, LexManos said:

All your default values are wrong, and nobody will change them thus causing duplicated defaults all over the place.

 

The only defaults I have is for living entities, and perhaps not many will change them unless they know what they are doing or what they are for. But I wouldn't call them wrong as they are based on vanilla values. Perhaps not all of them are at optimal values, but I personally don't know what are or how to determine them. And are you certain that these duplicate default will cause any problems? If so, why?

 

4 hours ago, LexManos said:

All of this fluf just causes modders to do things incorrectly.

1

I am not sure how it would cause modders to do things incorrectly. From my own personal experience, it is quite nice to just pass a few values and have everything handle for me. It makes debugging easier as I know what I can count on not being broken. What exactly would the be doing incorrectly? I would love to know, perhaps I can fix it.

 

4 hours ago, LexManos said:

Auto-magical registration is just ASKING for things to be statically initialized which your examples are showing are the case. Which is something we've been crusading against for years because it one of the things that prevents mods from being hot swapable.

4

I don't quite understand what you mean by this. Perhaps it's just my ignorance. I assume by "Auto-magical registration" you meant automatic registration. What do you mean having things statically initialized prevents mods from being hot-swappable? I'm no expert about hot swapping, so what does this have to do with anything? The way that Forge is now, you have to restart if you want to register a new item/block/etc and that is more of an issue with Minecraft's code if I am not mistaken. In my eclipse workspace, I've been able to run debug and change code (which as I understand it is hot-swapping the code) and it works as expected.

 

If forge wants to prevent modders from doing certain things, then I would assume a better alternative should be offered. My system isn't perfect, but I know for sure that it is a whole lot easier, consistent and maintainable than the current structure.

 

4 hours ago, LexManos said:

Not to mention your little hack to swap the current mod for registration is bad. As it screws up override tracking as well as bypasses the warning about invalid registry names. 

 

On what grounds do you claim this? My system is like a secretary to forge, so if you had to items or whatever that had the same modid and unlocalized name, it would not interfere with any errors forge would have with this. How does it screw up the tracking? It essentially tells forge, "hey here's an object that needs to be registered, and it's for this mod." No duplicate entry would be allowed.

 

Perhaps it is just that my code that the code that I have is a bit hard to parse. Perhaps I'll work on a smaller version so that only the registration is there as to not distract from the code. Is there something that I missed? I truly do want feedback. I am sure an automated registration system would be good for forge. Mods would be easier to maintain and sometimes can carry over to a new version of minecraft. At the very least something should be done about so that the greatest challenge to learning to mod Minecraft isn't just getting an item or block to show up in game.

 

Link to comment
Share on other sites

The way I automized my registrations:

  • Make a HashSet of Blocks/Items in your CommonProxy.
  • In your Block/Item constructor, add the current instance of the class to the HashSet. (ie. CommonProxy.BLOCKS.add(this);)
  • During RegistryEvent.Register, go through your HashSet and register each object (if we're talking about IForgeRegistryEntrys, otherwise register it during the preInit or init phase). Use a Stream, a for-loop, whatever you want.

The same applies to models and other client-side stuff.

Link to comment
Share on other sites

21 minutes ago, TheTrollguy_ said:

The way I automized my registrations:

  • Make a HashSet of Blocks/Items in your CommonProxy.
  •  In your Block/Item constructor, add the current instance of the class to the HashSet. (ie. CommonProxy.BLOCKS.add(this);)
  • During RegistryEvent.Register, go through your HashSet and register each object (if we're talking about IForgeRegistryEntrys, otherwise register it during the preInit or init phase). Use a Stream, a for-loop, whatever you want.

The same applies to models and other client-side stuff.

This approach screams "static initializers" and static initializers are bad. Just instantinate your blocks/items/whatever directly in the registry event. Not in a static initializer, not in FML events. You are also doing extra unnecessary work, think about it. Thirst you instantinate your stuff somewhere, then you add them to the set in the constructor, then you loop through the set in the event. That's at the very least 3 lines of code per block. Now think of the recommended approach. You instantinate your stuff directly in the registry event as an argument passed to register. That's one line of code per thing. With the recommended approach you are doing only 33% of the work.

Also CommonProxy makes no sense. Proxies are for separating sided only code. Common code goes whereever but your proxy.

  • Thanks 1
Link to comment
Share on other sites

1 minute ago, V0idWa1k3r said:

This approach screams "static initializers" and static initializers are bad. Just instantinate your blocks/items/whatever directly in the registry event. Not in a static initializer, not in FML events. You are also doing extra unnecessary work, think about it. Thirst you instantinate your stuff somewhere, then you add them to the set in the constructor, then you loop through the set in the event. That's at the very least 3 lines of code per block. Now think of the recommended approach. You instantinate your stuff directly in the registry event as an argument passed to register. That's one line of code per thing. With the recommended approach you are doing only 33% of the work.

Also CommonProxy makes no sense. Proxies are for separating sided only code. Common code goes whereever but your proxy.

 

Well, I never actually thought about that approach. Now that I really think about it, it does make a lot of sense. Thanks for the heads up! :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
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.

 Share



  • Recently Browsing

    No registered users viewing this page.

  • Posts

    • I updated my codes. What is the problem now?
    • ---- Minecraft Crash Report ---- // Hey, that tickles! Hehehe! Time: 9/28/21, 5:37 PM Description: Mod loading error has occurred java.lang.Exception: Mod Loading has failed     at net.minecraftforge.fmllegacy.CrashReportExtender.dumpModLoadingCrashReport(CrashReportExtender.java:69) ~[forge-1.17.1-37.0.0-universal.jar%2356!:?] {re:classloading}     at net.minecraftforge.fmlclient.ClientModLoader.completeModLoading(ClientModLoader.java:193) ~[forge-1.17.1-37.0.0-universal.jar%2356!:?] {re:classloading,pl:runtimedistcleaner:A}     at net.minecraft.client.Minecraft.lambda$new$1(Minecraft.java:551) ~[client-1.17.1-20210706.113038-srg.jar%2352!:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}     at net.minecraft.Util.m_137521_(Util.java:361) ~[client-1.17.1-20210706.113038-srg.jar%2352!:?] {re:classloading}     at net.minecraft.client.Minecraft.lambda$new$2(Minecraft.java:545) ~[client-1.17.1-20210706.113038-srg.jar%2352!:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}     at net.minecraft.client.gui.screens.LoadingOverlay.m_6305_(LoadingOverlay.java:135) ~[client-1.17.1-20210706.113038-srg.jar%2352!:?] {re:classloading,pl:runtimedistcleaner:A}     at net.minecraft.client.renderer.GameRenderer.m_109093_(GameRenderer.java:873) ~[client-1.17.1-20210706.113038-srg.jar%2352!:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}     at net.minecraft.client.Minecraft.m_91383_(Minecraft.java:1035) ~[client-1.17.1-20210706.113038-srg.jar%2352!:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}     at net.minecraft.client.Minecraft.m_91374_(Minecraft.java:655) ~[client-1.17.1-20210706.113038-srg.jar%2352!:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}     at net.minecraft.client.main.Main.main(Main.java:186) ~[client-1.17.1-20210706.113038-srg.jar%2352!:?] {re:classloading,pl:runtimedistcleaner:A}     at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] {}     at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78) ~[?:?] {}     at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] {}     at java.lang.reflect.Method.invoke(Method.java:567) ~[?:?] {}     at net.minecraftforge.fml.loading.targets.CommonClientLaunchHandler.lambda$launchService$0(CommonClientLaunchHandler.java:45) ~[fmlloader-1.17.1-37.0.0.jar%2321!:?] {}     at cpw.mods.modlauncher.LaunchServiceHandlerDecorator.launch(LaunchServiceHandlerDecorator.java:37) [modlauncher-9.0.7.jar%235!:?] {}     at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:53) [modlauncher-9.0.7.jar%235!:?] {}     at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:71) [modlauncher-9.0.7.jar%235!:?] {}     at cpw.mods.modlauncher.Launcher.run(Launcher.java:106) [modlauncher-9.0.7.jar%235!:?] {}     at cpw.mods.modlauncher.Launcher.main(Launcher.java:77) [modlauncher-9.0.7.jar%235!:?] {}     at cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:26) [modlauncher-9.0.7.jar%235!:?] {}     at cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:23) [modlauncher-9.0.7.jar%235!:?] {}     at cpw.mods.bootstraplauncher.BootstrapLauncher.main(BootstrapLauncher.java:84) [bootstraplauncher-0.1.15.jar:?] {} A detailed walkthrough of the error, its code path and all known details is as follows: --------------------------------------------------------------------------------------- -- Head -- Thread: Render thread Stacktrace:     at net.minecraftforge.versions.forge.ForgeVersion.<clinit>(ForgeVersion.java:48) ~[forge-1.17.1-37.0.0-universal.jar%2356!:?] {re:classloading} -- MOD forge -- Details:     Caused by 0: java.lang.reflect.InvocationTargetException         at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?] {}         at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:78) ~[?:?] {}         at jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:?] {}         at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[?:?] {}         at java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[?:?] {}         at net.minecraftforge.fml.javafmlmod.FMLModContainer.constructMod(FMLModContainer.java:81) ~[javafmllanguage-1.17.1-37.0.0.jar%2354!:?] {}         at net.minecraftforge.fml.ModContainer.lambda$buildTransitionHandler$4(ModContainer.java:120) ~[fmlcore-1.17.1-37.0.0.jar%2353!:?] {}         at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1800) ~[?:?] {}         at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1792) ~[?:?] {}         at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:295) ~[?:?] {}         at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1016) ~[?:?] {}         at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1665) ~[?:?] {}         at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1598) ~[?:?] {}         at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183) ~[?:?] {}     Caused by 1: java.lang.ExceptionInInitializerError         at net.minecraftforge.common.ForgeMod.<init>(ForgeMod.java:136) ~[forge-1.17.1-37.0.0-universal.jar%2356!:?] {re:classloading}         at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?] {}         at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:78) ~[?:?] {}         at jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:?] {}         at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[?:?] {}         at java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[?:?] {}         at net.minecraftforge.fml.javafmlmod.FMLModContainer.constructMod(FMLModContainer.java:81) ~[javafmllanguage-1.17.1-37.0.0.jar%2354!:?] {}         at net.minecraftforge.fml.ModContainer.lambda$buildTransitionHandler$4(ModContainer.java:120) ~[fmlcore-1.17.1-37.0.0.jar%2353!:?] {}         at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1800) ~[?:?] {}         at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1792) ~[?:?] {}         at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:295) ~[?:?] {}         at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1016) ~[?:?] {}         at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1665) ~[?:?] {}         at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1598) ~[?:?] {}         at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183) ~[?:?] {}     Mod File: forge-1.17.1-37.0.0-universal.jar     Failure message: Forge (forge) has failed to load correctly         java.lang.reflect.InvocationTargetException: null     Mod Version: 37.0.0     Mod Issue URL: http://www.minecraftforge.net/     Exception message: java.lang.RuntimeException: Missing forge spec, cannot continue Stacktrace:     at net.minecraftforge.versions.forge.ForgeVersion.<clinit>(ForgeVersion.java:48) ~[forge-1.17.1-37.0.0-universal.jar%2356!:?] {re:classloading}     at net.minecraftforge.common.ForgeMod.<init>(ForgeMod.java:136) ~[forge-1.17.1-37.0.0-universal.jar%2356!:?] {re:classloading}     at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?] {}     at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:78) ~[?:?] {}     at jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:?] {}     at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[?:?] {}     at java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[?:?] {}     at net.minecraftforge.fml.javafmlmod.FMLModContainer.constructMod(FMLModContainer.java:81) ~[javafmllanguage-1.17.1-37.0.0.jar%2354!:?] {}     at net.minecraftforge.fml.ModContainer.lambda$buildTransitionHandler$4(ModContainer.java:120) ~[fmlcore-1.17.1-37.0.0.jar%2353!:?] {}     at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1800) ~[?:?] {}     at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1792) ~[?:?] {}     at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:295) ~[?:?] {}     at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1016) ~[?:?] {}     at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1665) ~[?:?] {}     at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1598) ~[?:?] {}     at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183) ~[?:?] {} -- System Details -- Details:     Minecraft Version: 1.17.1     Minecraft Version ID: 1.17.1     Operating System: Windows 10 (amd64) version 10.0     Java Version: 16.0.1, Microsoft     Java VM Version: OpenJDK 64-Bit Server VM (mixed mode), Microsoft     Memory: 875057712 bytes (834 MiB) / 2013265920 bytes (1920 MiB) up to 2147483648 bytes (2048 MiB)     CPUs: 16     Processor Vendor: AuthenticAMD     Processor Name: AMD Ryzen 7 5800H with Radeon Graphics              Identifier: AuthenticAMD Family 25 Model 80 Stepping 0     Microarchitecture: Zen 3     Frequency (GHz): 3.19     Number of physical packages: 1     Number of physical CPUs: 8     Number of logical CPUs: 16     Graphics card #0 name: NVIDIA GeForce RTX 3060 Laptop GPU     Graphics card #0 vendor: NVIDIA (0x10de)     Graphics card #0 VRAM (MB): 4095.00     Graphics card #0 deviceId: 0x2560     Graphics card #0 versionInfo: DriverVersion=30.0.14.7212     Graphics card #1 name: AMD Radeon(TM) Graphics     Graphics card #1 vendor: Advanced Micro Devices, Inc. (0x1002)     Graphics card #1 VRAM (MB): 512.00     Graphics card #1 deviceId: 0x1638     Graphics card #1 versionInfo: DriverVersion=27.20.14040.14001     Memory slot #0 capacity (MB): 8192.00     Memory slot #0 clockSpeed (GHz): 3.20     Memory slot #0 type: DDR4     Memory slot #1 capacity (MB): 8192.00     Memory slot #1 clockSpeed (GHz): 3.20     Memory slot #1 type: DDR4     Virtual memory max (MB): 20779.76     Virtual memory used (MB): 17684.32     Swap memory total (MB): 5059.52     Swap memory used (MB): 393.09     JVM Flags: 9 total; -XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump -Xss1M -Xmx2G -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M     ModLauncher: 9.0.7+91+master.8569cdf     ModLauncher launch target: forgeclient     ModLauncher naming: srg     ModLauncher services:           eventbus PLUGINSERVICE           object_holder_definalize PLUGINSERVICE           runtime_enum_extender PLUGINSERVICE           capability_inject_definalize PLUGINSERVICE           accesstransformer PLUGINSERVICE           runtimedistcleaner PLUGINSERVICE           fml TRANSFORMATIONSERVICE      FML Language Providers:          minecraft@1.0         javafml@null     Mod List:          client-1.17.1-20210706.113038-srg.jar             |Minecraft                     |minecraft                     |1.17.1              |COMMON_SET|Manifest: NOSIGNATURE         forge-1.17.1-37.0.0-universal.jar                 |Forge                         |forge                         |37.0.0              |ERROR     |Manifest: 22:af:21:d8:19:82:7f:93:94:fe:2b:ac:b7:e4:41:57:68:39:87:b1:a7:5c:c6:44:f9:25:74:21:14:f5:0d:90
    • You must pass your ModID to @EventBusSubscriber unless it is on your @Mod class. Is the event called? Does it do the correct thing?
    • it worked, thank you so much
    • Channels are bound to a single mod, they are not meant to be shared. Why do you want to do this?
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

By using this site, you agree to our Privacy Policy.