Jump to content

[SOLVED][1.7.2]Registering event handlers for server versus client


Recommended Posts

Posted

Okay, still learning about the client-server architecture.  I'm registering event handlers in my mod and I thought that an event that was client side (like a gui related event) would simply never fire, but it seems that even subscribing it when running on Server will cause a crash.  In other words, I guess you need to have different subscriptions depending on which side you're running. Is that true?

 

To be clear, here is my event handler:

 

package wildanimals;

 

import net.minecraft.client.Minecraft;

import net.minecraftforge.client.event.RenderGameOverlayEvent;

import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;

import net.minecraftforge.event.entity.player.AttackEntityEvent;

import net.minecraftforge.event.entity.player.EntityItemPickupEvent;

import cpw.mods.fml.common.eventhandler.SubscribeEvent;

 

public class WildAnimalsEventHandler

{

 

//Only the Event type parameter is what's important (see below for explanations of some types)

@SubscribeEvent

public void onLivingUpdateEvent(LivingUpdateEvent event)

{

// This event has an Entity variable, access it like this: event.entity;

// and can check if for player with if (event.entity instanceof EntityPlayer)

}

 

@SubscribeEvent

public void onEntityItemPickupEvent(EntityItemPickupEvent event)

{

// check if client side before sending message

if (event.entity.worldObj.isRemote)

{

System.out.println("Yay loot!");

Minecraft.getMinecraft().thePlayer.sendChatMessage("Yay loot!");

}

}

 

@SubscribeEvent

public void onAttackEntityEvent(AttackEntityEvent event)

{

// check if client side before sending message

if (event.entity.worldObj.isRemote) {

System.out.println("Attack!");

Minecraft.getMinecraft().thePlayer.sendChatMessage("Attack!");

}

}

 

@SubscribeEvent

public void onGuiOverlayEvent(RenderGameOverlayEvent event)

{

 

}

}

 

 

 

And the RenderGameOverlayEvent seems to cause the problem.

 

So is it best to do the event registration in the proxies according to the side, or should I use @SideOnly in the event handler to mask out anything not relevant to a side?

 

This actually brings me to my real question about dealing with the client versus server: when do you put things in the proxy versus when do you put them in regular class with @SideOnly annotation?

 

 

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Hi

 

This link might be of interest

http://greyminecraftcoder.blogspot.com.au/2013/11/how-forge-starts-up-your-code.html

 

In my experience you can subscribe the same class to event handlers on both sides, so long as your class doesn't refer to any of the client-side-only vanilla objects.

 

Usually, all my handler does is immediately call another of my classes (depending on which side).  Since all my classes are present on both sides, no crash.

 

-TGG

 

Posted

Hi

 

This link might be of interest

http://greyminecraftcoder.blogspot.com.au/2013/11/how-forge-starts-up-your-code.html

 

In my experience you can subscribe the same class to event handlers on both sides, so long as your class doesn't refer to any of the client-side-only vanilla objects.

 

Usually, all my handler does is immediately call another of my classes (depending on which side).  Since all my classes are present on both sides, no crash.

 

-TGG

 

Thanks, I like your tutorials.

 

I don't understand your statement (in the linked tutorial) that the sided proxy "has NOTHING TO DO with the difference between client-side  and server-side.  That is something totally different."  Can you explain the difference? It seems related to me -- for example subscribing a GUI event handler on the server proxy seems to give me trouble, similar to any other gui method running on the server elsewhere in the code. 

 

For example, what would be the difference between:

a) putting my registerRenderers() in ClientProxy

b) using no proxy and instead use @SideOnly in main class and have two preInit methods (preInitServer and preInitClient) where only the preInitClient registers renderers?

c) using no proxy and instead use one preInit method in which you test FMLcommonHandler.instance().getEffectiveSide() and register renders if on client?

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Hi

 

This link might be of interest

http://greyminecraftcoder.blogspot.com.au/2013/11/how-forge-starts-up-your-code.html

 

In my experience you can subscribe the same class to event handlers on both sides, so long as your class doesn't refer to any of the client-side-only vanilla objects.

 

Usually, all my handler does is immediately call another of my classes (depending on which side).  Since all my classes are present on both sides, no crash.

 

-TGG

 

Thanks, I like your tutorials.

 

I don't understand your statement (in the linked tutorial) that the sided proxy "has NOTHING TO DO with the difference between client-side  and server-side.  That is something totally different."  Can you explain the difference? It seems related to me -- for example subscribing a GUI event handler on the server proxy seems to give me trouble, similar to any other gui method running on the server elsewhere in the code. 

 

For example, what would be the difference between:

a) putting my registerRenderers() in ClientProxy

b) using no proxy and instead use @SideOnly in main class and have two preInit methods (preInitServer and preInitClient) where only the preInitClient registers renderers?

c) using no proxy and instead use one preInit method in which you test FMLcommonHandler.instance().getEffectiveSide() and register renders if on client?

 

Hi

 

What I meant by "the sided proxy has NOTHING TO DO with the difference between client-side and server-side" is that the sided proxy is used to tell the difference between your mod being installed on a client, or your mod being installed on the dedicated server.  It won't tell your code whether it's being called on the "client side", or on the "server side"; you need to use isRemote() for that.

 

For example -

On the client side, you can access Minecraft but not MinecraftServer.  If you do, it might appear to work for a while but it will eventually crash, because although the MinecraftServer class might exist, it is either unused or is in use by a different thread.

 

On the Server side, you can access MinecraftServer but not Minecraft.  If you try, it might crash immediately (if this is a dedicated server), or crash after some time (if this is a normal client).

 

You're right they are kind of related, but only very loosely I think.

 

CombinedClient: both server side objects ok and client side objects ok, can have classes common to both which use isRemote to tell which side they are on

DedicatedServer: server side only objects.  Any classes which contain references to client-side objects will cause immediate crash, even if those references aren't used

 

Without trying it, I think (a) and (b) would be the same, but © wouldn't.  getEffectiveSide is similar to isRemote, i.e. it can't tell your the difference between being installed on the client (which has all vanilla objects) and the dedicatedserver (which is missing half of them).  I suspect getEffectiveSide doesn't return anything meaningful in the preInit method.

 

-TGG

 

 

 

Posted

 

What I meant by "the sided proxy has NOTHING TO DO with the difference between client-side and server-side" is that the sided proxy is used to tell the difference between your mod being installed on a client, or your mod being installed on the dedicated server.  It won't tell your code whether it's being called on the "client side", or on the "server side"; you need to use isRemote() for that.

 

I kinda figured that was what you were getting at -- distiguishing between where it is installed/compiled for versus run-time "happens to be called by".  I think it is still kinda confusing to say "nothing to do with" because you made it sound like it wasn't even same client and server model or something.  But I know what you mean now: there are common classes that can report where they are being run, and there are other classes which only exist on one side or the other. 

 

Without trying it, I think (a) and (b) would be the same, but © wouldn't.  getEffectiveSide is similar to isRemote, i.e. it can't tell your the difference between being installed on the client (which has all vanilla objects) and the dedicatedserver (which is missing half of them).  I suspect getEffectiveSide doesn't return anything meaningful in the preInit method.

 

Okay, one last question.  It seems that you prefer to use proxy for pretty much all the main class events, even if common (you put that in the commonProxy I assume).  I kinda thought about going that route, however is it just a style preference or is there some other advantage to not putting the common code directly in the main class?

 

For example, I do all my entity registering right in the main class, but for the renderers (which care about side) I register them through the proxy.  While I understand there is some logical cleaness in putting all the common stuff in the commonProxy, it just seems like main class is pretty logical home for it too.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Hi,

 

I think what the OP is getting at is that when you use proxies with FML, the ClientProxy methods ONLY run on the client side, but the CommonProxy methods are run on both. So if you have a GuiEvent class, it is easiest and trouble-free to register it in the ClientProxy, whereas if you put that in the CommonProxy or your main class, you will have to check if you are on the client side before registering it if you wish to avoid a crash in the future.

 

There could of course be exceptions to this, such as if you create an instance of your ClientProxy or a static method and call it yourself from some random point in your code, it could very well be called on the server, but using "proxy.someMethod" during the FML events does, I believe, make that distinction for you.

 

Please correct me if I'm wrong, but that has been my experience using proxies and what I have come to understand as their main purpose.

 

EDIT: @jabelar A lot of things are just stylistic preference; for example, I have all my entity registration in a separate Entities class, same for Items and Blocks. You can see my main class here, if you want, but I would just do it however you like: https://github.com/coolAlias/ZeldaSwordSkills-1.6.4/blob/master/src/main/java/zeldaswordskills/ZSSMain.java

Posted

Hi

 

Yeah you got it  :-)

 

I think you're both right about stylistic preferences, I don't know of any reason it has to be done one way or the other.  Personally, I prefer to keep client and server code completely separate, and I try to move as much functionality out of the "mega classes" as I can, by pushing it into smaller classes which I can understand and test more easily.  My EventHandlers etc generally only contain one or two lines of code, because they immediately pass the call to another class.  But that's just my preference and for uncomplicated mods I reckon it doesn't make any difference.

 

-TGG

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

    • I have no idea why it sent twice im really sorry
    • Was launching forge for the first time and it crashed: Processor failed, invalid outputs: /home/frenchy/.local/share/PrismLauncher/libraries/net/minecraft/client/1.20.1-20230612.114412/client-1.20.1-20230612.114412-slim.jar Expected: de86b035d2da0f78940796bb95c39a932ed84834 Actual: a8fb49bc364562847d6e7e6775e3a1b3f6b2bb05 /home/frenchy/.local/share/PrismLauncher/libraries/net/minecraft/client/1.20.1-20230612.114412/client-1.20.1-20230612.114412-extra.jar Expected: 8c5a95cbce940cfdb304376ae9fea47968d02587 Actual: cf941ba69e11f5a9de15d0c319d61854c456a116 No idea why I think it's because I'm on linux or something  
    • Game crashed on launch with:  Processor failed, invalid outputs: /home/user/.local/share/PrismLauncher/libraries/net/minecraft/client/1.20.1-20230612.114412/client-1.20.1-20230612.114412-slim.jar Expected: de86b035d2da0f78940796bb95c39a932ed84834 Actual: a8fb49bc364562847d6e7e6775e3a1b3f6b2bb05 /home/user/.local/share/PrismLauncher/libraries/net/minecraft/client/1.20.1-20230612.114412/client-1.20.1-20230612.114412-extra.jar Expected: 8c5a95cbce940cfdb304376ae9fea47968d02587 Actual: cf941ba69e11f5a9de15d0c319d61854c456a116 No idea why, but im on linux which might matter
    • PixelmonGo est un incroyable serveur Pixelmon disponible grâce à notre launcher en version 1.16.5 Ce serveur accepte les joueurs premiums comme les cracks ! Un gameplay unique vous attend.. Rejoignez nous dès maintenant ! Site: https://pixelmongo.fr/ Launcher: https://pixelmongo.fr/launcher/ Discord: https://discord.gg/pixelmongo Découvrez notre serveur minecraft Pixelmon moddé basé sur un univers mélangeant Minecraft et Pokémon. Plus de 900 Pokémon à capturer ainsi que des fusions unique au serveur, un hôtel des ventes, un monde aventure reproduisant l'aventure de sinnoh, Explorez des donjons de chaque team maléfique au début de votre aventure, accomplissez des quêtes et remportez des récompenses quotidiennes. Revivez vos meilleurs souvenirs Pokémon au sein d'une communauté multijoueur dynamique. Rejoignez le meilleur serveur minecraft pixelmon français des maintenant en téléchargeant notre launcher. Pixelmongo est la référence en serveur pixelmon en France ! Présentation Amenez votre Minecraft dans le monde des Pokémon, ou des Pokémon dans votre monde Minecraft ! Avec Pixelmon, découvrez votre monde Minecraft sous un nouvel angle. Pixelmon est un mod populaire pour Minecraft qui permet aux joueurs d'attraper, d'entraîner et de combattre des Pokémon dans le monde de Minecraft. Développé par un groupe de fans dévoués, le mod ajoute une large gamme de créatures Pokémon au jeu. Il possède des fonctionnalités et des mécanismes uniques qui en font une expérience amusante et engageante pour les joueurs de tous âges. Le mod Pixelmon est disponible pour les mondes Minecraft solo et multijoueur et peut être téléchargé et installé à l'aide de divers lanceurs et modpacks. Une fois installé, les joueurs peuvent explorer le monde et rencontrer des Pokémon dans la nature, se battre avec d'autres entraîneurs et créer leur propre équipe de créatures puissantes. L'une des fonctionnalités clés de Pixelmon est la possibilité de capturer et d'entraîner des Pokémon en utilisant diverses méthodes. Les joueurs peuvent fabriquer des Pokéballs et les utiliser pour capturer des Pokémon sauvages, qui peuvent ensuite être entraînés et améliorés au fil du temps. Chaque Pokémon a des capacités et des mouvements uniques, ce qui rend important pour les joueurs de choisir la bonne équipe de créatures pour chaque combat. Capturez des Pokémons, constituez une équipe, entraînez-les et remportez des combats contre d'autres joueurs ! Dans un univers reprenant les standards du jeu Nintendo original : Dresseurs, centres Pokémon, mais aussi fossiles et matériaux divers. Les Pokémon comme dans le jeu original sont classés par type (Insecte, Ténèbres, Dragon, Électrique, Combat, Feu, Vol, Spectre, Plante, Sol, Glace, Normal, Poison, Psy, Pierre, Acier, Eau), ce qui définira les faiblesses et les spécificités des Pokémons. Par exemple, un Pokémon de type Feu subira deux fois plus de dégâts si l'attaque du Pokémon ennemi est de type Glace. Le mod possède 900 Pokémon différents plus ou moins rares qui apparaîtront en fonction de leur environnement (jour, nuit et biomes). Les Pokémon évoluent en fonction de leur niveau (jusqu'à 100). Plus leur niveau est élevé, plus ils seront forts et auront des attaques plus puissantes. Pour augmenter le niveau de votre Pokémon, et ainsi évoluer, vous devrez combattre d'autres Pokémon et les vaincre. Plus vos adversaires sont forts, plus ils vous rapporteront de l'expérience. Les Pokémons ont également leurs propres statistiques (attaque, défense, vitesse, vitesse d'attaque et vitesse de défense). Ils peuvent également avoir des tailles et des formes différentes, et peuvent occasionnellement vous donner des objets une fois tués. Pour les capturer, vous devrez utiliser des pokéballs, qui selon leur forme seront plus ou moins efficaces. Pixelmon est un mod amusant et engageant pour Minecraft qui ajoute une touche unique et passionnante au jeu. Avec sa large gamme de fonctionnalités et de mécanismes, il offre aux joueurs des possibilités infinies d'exploration et de plaisir, ce qui en fait un choix populaire pour les fans de Minecraft et de Pokemon.  
    • Hi all,  I have the following issue: I'd like to parse some json using gson and rely on the (somewhat new) java record types. This is supported in gson 2.10+. Gson is already a dependency used by minecraft, however it's 2.8.x for 1.19.2 which I'm targeting at the moment. My idea was to include the newer version of the library in my mod and then shadow it so it gets used inside the scope of my mod instead of the older 2.8. This works fine for building the jar: If I decompile my mod.jar, I can see that it's correctly using the shadowed classes. However obviously when using the runClient intellj config, the shadowing doesn't get invoked. Is there any way of invoking shadow when using runClient, or am I on the wrong track and there's a better way of doing this entirely?   Thanks in advance!   Edit: After some further thinking, I've come up with this abomination:   build.gradle // New task for extracting the result of shadowJar into the classes directory // This includes our shadowed gson jar tasks.register("extractShadowJar", Copy) { // Depend on shadowJar so we always use the up to date version of the shadowed content dependsOn shadowJar from(zipTree(shadowJar.archiveFile)) { // filter to copy only our code (and ignore assets, META-INF, etc) // Also copies gson as it gets shadowed into com.oppendev.shadow.gson include "com/**" } duplicatesStrategy(DuplicatesStrategy.INCLUDE) into("$buildDir/classes/java/main") // Extract into the classes directory } // Tell gradle to invoke our new task before executing any java code. This way we ensure that we use the shadowed gson tasks.withType(JavaExec).configureEach { dependsOn(extractShadowJar) } // Shadow config shadowJar { relocate 'com.google.gson', 'com.oppendev.shadow.gson' configurations = [project.configurations.runtimeClasspath] zip64 true dependencies { include(dependency('com.google.code.gson:gson')) } } Is this a reasonable thing to do? Is this completely cursed and I should burn in dev ops hell? Is there a better way to do this? Feel free to grill me in the replies
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

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