Jump to content

Recommended Posts

Posted

I'm still learning and having difficulty understanding the client / server relationship. I don't expect someone to solve this problem for me but rather just point me in the right direction. My goal is to learn. Thank you for your patience and I apologize in advance for being long-winded and/or daft! :)

 

The basic concept of the mod I'm working on (To teach myself) is that the player can look at a list of all entity items in the game and mark any of them. When the player encounters that item on the ground, s/he will not pick it up if it is marked. I've got it working in single player, but when I go to test in in multiplayer, it isn't doing what I want. The player that started the server is the "master", so that all players in the game are prevented from picking up the blocks that the "master" player has marked.

 

The unwanted items are stored as an ArrayList of the type UniqueIdentifier. That ArrayList is just defined in my base mod class:

 

@Mod(modid = DoNotWant.MODID, version = DoNotWant.VERSION)
public class DoNotWant
{
    public static final String MODID = "donotwant";
    public static final String VERSION = "0.1";
    public ArrayList unwanted;

...

 

In the client side preInit():

 

public void preInit() {
super.preInit();
DoNotWant.instance.unwanted = new ArrayList();
MinecraftForge.EVENT_BUS.register(new EntityItemPickup());
FMLCommonHandler.instance().bus().register(new KeyInputHandler());
KeyBindings.init();
}

 

I then have a GUI implemented from the base class thusly:

 

@Override
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
   if (ID == GuiBlockManager.GUI_ID) {
      return new GuiBlockManager();
   }
   return null;
}

 

From that GUI, when the player clicks a button representing a particular block, I get the block's unique identifier and add it to the ArrayList:

 

DoNotWant.instance.unwanted.add(item.getUniqueIdentifier());

 

And finally I subscribe to the entityItemPickupEvent:

 

private UniqueIdentifier ident;
protected Minecraft mc = Minecraft.getMinecraft();

@SubscribeEvent
public void entityItemPickup(EntityItemPickupEvent event) {
ident = GameRegistry.findUniqueIdentifierFor(event.item.getEntityItem().getItem());
if (DoNotWant.instance.unwanted.indexOf(ident) != -1) {
	event.setCanceled(true);
}
}

 

Is there another place I can define the ArrayList so that each client has a unique instance of it? I have a feeling it isn't that simple. I considered keeping track of the unwanted items in an ArrayList where each player was a key, and the value was a list of UniqueIdentifiers for that player, but I'm not sure if that is the way I should do it.

 

When I call mc.thePlayer.getUniqueID() within the entityItemPickup event handler, I always get the UUID of the "master" player, even when the event is triggered from the guest player's client. What's up with that?

Posted

How is using Minecraft.getMinecraft() not crashing your server? Or are you not running it on a server?

 

In your event handling class, you have:

protected Minecraft mc = Minecraft.getMinecraft();

That WILL crash any server your mod runs on, because that is a CLIENT side only class; Item pickup event happens on the server for sure, I don't recall if it is also called on the client, but you cannot use client-side only classes in that context.

 

Similarly, you cannot register your KeyBindings or KeyInputHandler or any other CLIENT-based code in a common context such as preInit - those should be handled via your proxy, specifically in your ClientProxy. It looks like you did that correctly, but then you are only registering your pickup event on the client side, when it should be registered on the server (or both sides, but really you only care about it on the server).

 

If you want to store a separate list for each player, then do so. A simple way is to use a Map<EntityPlayer, Set<Item>> - a Set because it can only contain one of each, whereas a List could have 20+ of the same Item. Depends on your goal.

 

A better way, of course, is to store the collection of unwanted items in each player's IExtendedEntityProperties - this way the unwanted items can be saved, loaded, etc., and are cleanly managed on a per-player basis.

Posted

Thanks so much for your time and help. I will explore IExtendedEntityProperties more. That is something I came across in my searching as a possible area to explore.

 

How is using Minecraft.getMinecraft() not crashing your server? Or are you not running it on a server?

 

I didn't show enough of my code in regard to the preInit() method. In my main mod class, I have:

 

@SidedProxy(clientSide="net.analogweapon.donotwant.ClientOnlyProxy", serverSide="net.analogweapon.donotwant.DedicatedServerProxy")
public static CommonProxy proxy;

 

And that preInit() method is in ClientOnlyProxy.class:

 

public class ClientOnlyProxy extends CommonProxy {

public void preInit() {
	super.preInit();
	DoNotWant.instance.unwanted = new Unwanted();
	MinecraftForge.EVENT_BUS.register(new EntityItemPickup());
	FMLCommonHandler.instance().bus().register(new KeyInputHandler());
	KeyBindings.init();
}
...

 

So I think that means the entityItemPickup event I'm subscribing to is on the client side? That's what I assumed, so that is why I'm confused about the output of Minecraft.getMinecraft().thePlayer.getUniqueID() in the that event: It is always the UUID of the player hosting the game, even when triggered by a guest player. (I'm testing by building the mod and loading in two clients, logging in with a different account on each, opening to LAN from one, and joining with the other).

 

public class EntityItemPickup {

protected Minecraft mc = Minecraft.getMinecraft();

@SubscribeEvent
public void entityItemPickup(EntityItemPickupEvent event) {
	System.out.println(mc.thePlayer.getUniqueID());
}

}

 

This is where I'm still a little unclear: I read a lot about code that is "running on the server" vs code that is "running on the client". How can I tell which context I'm in? Is it that any code that is initiated from the client side proxy is running on the client only?

Posted

You can tell which context you are in in one of several ways:

1. Experience ;)

2. If the class or method has @SideOnly, it's pretty obvious

3. By checking if the world object (from an entity, method, or wherever else) is remote - if world.isRemote is true, that means the code is currently running on the client.

4. By using an actual Logger to output messages to the console, such as `LogManager.getLogger(ModInfo.ID)` - this will note which thread (server or client) called the log.

 

There are more, but those are the main ones, with #3 being the most common. Note that many methods are called on both sides, which is fine.

 

The proxy system helps to segregate code in a fashion - there's a good write-up on it somewhere around these forums; if I find it later, I'll post a link, but suffice it to say that the main use is in the ClientProxy isolating client-side only calls (Render registrations, KeyBindings, and the like) from the rest of the code so they don't crash your server.

 

Unless an Event class has the @SideOnly(Side.CLIENT) annotation, you should NOT register it in the ClientProxy, but instead somewhere that is common to both the server and the client. This is because the code needs to run on the server, but you are preventing* that from happening.

 

So what you are seeing is the output from YOUR client's event handler on YOUR client every time an item is picked up, but really you want to see the output on the server*.

 

* Since you are running on LAN, however, I'm pretty sure that it still counts as single-player as far as using the integrated server instead of dedicated server, and the integrated server, being part of the client .jar, still makes calls to the ClientProxy (anyone feel free to correct me if I'm wrong, but that's what I've surmised from various tests over my time modding). That being the case, the server event is firing, but the server is running in the client host's game instance, and Minecraft.getMinecraft().thePlayer in that context will always be the host (usually it would crash, but single-player is 'special').

 

Anyway, that's my best crack at an explanation. Hopefully all my premises are correct :P

Posted

Recently a lot of peps ask same question, so I just paste this:

http://www.minecraftforge.net/forum/index.php/topic,33918.msg178740.html#msg178740

Hope first three points shed some light on things.

 

As to events: Using:

MinecraftForge.EVENT_BUS.register(new SomeClass());

Will grab all @SubscribeEvent methods in that SomeClass new instance and add them to Forge's BUS.

Logically - if #register is ran by some proxy (server or client, which will be called only if mod is ran by Client.jar of Dedicated.jar), it will be registered on one side.

Given that - you CAN have client-only events. Also note that there are some events that MUST be client-only (rendering events and stuff).

 

Clarification: Registering event is per-game, not per-thread. Only check you can perform is if game it Client.jar or Dedicated.jar.

If you want to have some event actually check logical side - you do it inside event with world.isRemote.

1.7.10 is no longer supported by forge, you are on your own.

Posted

Thanks so much for your time and help. I will explore IExtendedEntityProperties more. That is something I came across in my searching as a possible area to explore.

 

For IExtendedEntityProperties, check out coolAlias' tutorial: http://www.minecraftforum.net/forums/mapping-and-modding/mapping-and-modding-tutorials/1571567-forge-1-6-4-1-8-eventhandler-and

 

I would recommend that as well for storing the information for the reasons already stated (surprised you didn't link this yourself coolAlias, haha).

www.YouTube.com/WeiseGamer

www.twitter.com/WeiseGamer

Posted

For IExtendedEntityProperties, check out coolAlias' tutorial: http://www.minecraftforum.net/forums/mapping-and-modding/mapping-and-modding-tutorials/1571567-forge-1-6-4-1-8-eventhandler-and

 

I would recommend that as well for storing the information for the reasons already stated (surprised you didn't link this yourself coolAlias, haha).

That's what's sort of funny: I had that article bookmarked, and after talking here, I went back to it and dove in. It wasn't until I was pretty far through it that I realized coolAlias was the author. Haha.

 

Now that I'm starting to get IExtendedEntityProperties going, I can see that it's definitely the best way to go for what I'm working on.

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.