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.

×
×
  • Create New...

Important Information

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