Jump to content

[SOLVED] Syncing IExtendedProperties to client using EntityJoinWorldEvent


Kwibble

Recommended Posts

So I have an IMessage, MessageClientPlayerInfo, that needs to be sent to the client when the player logs in so that I can determine whether or not to display on overlay (a boolean stored in the player info). On the client, the packet sends fine and all is well. The problem is when I run the server, and then try to join. I get an error saying that the player instance I was using was wrong. That was all well and good though because I was using

Minecraft.getMinecraft().thePlayer;

The crash made sense.

 

But now I am confused as how to get a hold of the player. If I pass the players username into the packet and use:

MinecraftServer.getServer().getConfigurationManager().getPlayerForUsername(message.playerName);

It also crashes. I assume this is because the client has no knowledge whatsoever of the server stuff.

Then of course there is always:

ctx.getServerHandler().playerEntity;

Which results in a crash because one cannot NetHandlerPlayClient to NetHandlerPlayServer.

 

So what am I supposed to do to send this packet? I guess there is always the fact that this is the wrong event, but if so, why? I am so confuzzled I think I broke something.

 

Any help is appreciated, thanks.

We all stuff up sometimes... But I seem to be at the bottom of that pot.

Link to comment
Share on other sites

Hi

 

I don't really understand from your question who is sending the packet and who is receiving it.

 

The client always knows who the player is, Minecraft.getMinecraft().thePlayer 

When a packet arrives at the server, it knows which client it received the packet from and hence also the player for that client.

If you need to send a packet to the client from the server, the server will already know who the client is without having to read it out of a message.

 

Perhaps you could explain in a bit more detail what packets you are planning to send back and forth, and how they are triggered.

 

-TGG

Link to comment
Share on other sites

* facepalms * I didn't explain very well, and I don't think you quite get it due to that. Sorry.

 

Basically, the server sends a packet to the client when the client logs in. This packet contains all the values from a IExtendedEntityProperties to the client (also known as sending IExtendedEntityProperties to the client). And to retrieve the clients current version of those properties, I need an instance of the player. The real problem lies in this:

The server knows nothing about the client's classes E.g. Minecraft. The client also doesn't know anything about the Server's classes. Which then leads to the question: WHERE THE HELL IS THE SHARED PLAYER?!?!?! That, or how do you get the client's player when on the server, without using server classes.

 

If that is still confusing, have my packet code. That might help you.

package com.kwibble.dendri.network.message;

import com.kwibble.dendri.entity.player.PlayerInformation;
import com.kwibble.dendri.item.ItemDendrikBelt;
import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
import io.netty.buffer.ByteBuf;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.server.MinecraftServer;

/**
* Created by Kwibble on 19/06/14.
*/
public class MessageClientPlayerInfo implements IMessage
{
private String playerName;
private boolean isOverlayMinimized, shouldDisplayOverlay;
private Item currentDendrikBelt;

public MessageClientPlayerInfo(){}

public MessageClientPlayerInfo(PlayerInformation playerinfo, String playerName)
{
	this.playerName = playerName;
	this.shouldDisplayOverlay = playerinfo.getShouldDisplayOverlay();
	this.isOverlayMinimized = playerinfo.getIsOverlayMinimized();
	this.currentDendrikBelt = playerinfo.getCurrentDendrikBelt();
}

@Override
public void fromBytes(ByteBuf buf)
{
	this.playerName = ByteBufUtils.readUTF8String(buf);
	this.shouldDisplayOverlay = buf.readBoolean();
	this.isOverlayMinimized = buf.readBoolean();
	this.currentDendrikBelt = ByteBufUtils.readItemStack(buf).getItem();
}

@Override
public void toBytes(ByteBuf buf)
{
	ByteBufUtils.writeUTF8String(buf, this.playerName);
	buf.writeBoolean(this.shouldDisplayOverlay);
	buf.writeBoolean(this.isOverlayMinimized);
	ByteBufUtils.writeItemStack(buf, new ItemStack(this.currentDendrikBelt, 1));
}

public static class Handler implements IMessageHandler<MessageClientPlayerInfo, IMessage>
{
	@Override
	public IMessage onMessage(MessageClientPlayerInfo message, MessageContext ctx)
	{
		System.out.println("Client test receive: " + message.shouldDisplayOverlay);
		System.out.println("Client test receive: " + message.isOverlayMinimized);
		System.out.println("Client test receive: " + message.currentDendrikBelt);
		try
		{
			EntityPlayer player = Minecraft.getMinecraft().thePlayer;
			PlayerInformation playerinfo = PlayerInformation.forPlayer(player);
			playerinfo.setShouldDisplayOverlay(message.shouldDisplayOverlay);
			playerinfo.setIsOverlayMinimized(message.isOverlayMinimized);
			playerinfo.setCurrentDendrikBelt(message.currentDendrikBelt);
		} catch (NullPointerException e)
		{
			e.printStackTrace();
		}
		return null;
	}
}
}

We all stuff up sometimes... But I seem to be at the bottom of that pot.

Link to comment
Share on other sites

Hi

 

In this case you can get the player from the event when the client logs in.  Your server receives information somehow that a client has logged in. 

If this is an event, the player will be given to you.

For example

public PlayerLoggedInEvent(EntityPlayer player)

 

If this is a packet that your client sends to the server, the server knows from the packet information which client it came from.

 

At a pinch, you can get to players on the server side as described here

http://greyminecraftcoder.blogspot.com.au/2013/10/server-side-class-linkage-map.html

But that shouldn't be necessary.

 

-TGG

 

Link to comment
Share on other sites

I'm sorry, but you are missing the problem. Entirely. I shall now point you to this bit of the code:

public static class Handler implements IMessageHandler<MessageClientPlayerInfo, IMessage>
{
	@Override
	public IMessage onMessage(MessageClientPlayerInfo message, MessageContext ctx)
	{
		System.out.println("Client test receive: " + message.shouldDisplayOverlay);
		System.out.println("Client test receive: " + message.isOverlayMinimized);
		System.out.println("Client test receive: " + message.currentDendrikBelt);
		try
		{
			EntityPlayer player = Minecraft.getMinecraft().thePlayer;
			PlayerInformation playerinfo = PlayerInformation.forPlayer(player);
			playerinfo.setShouldDisplayOverlay(message.shouldDisplayOverlay);
			playerinfo.setIsOverlayMinimized(message.isOverlayMinimized);
			playerinfo.setCurrentDendrikBelt(message.currentDendrikBelt);
		} catch (NullPointerException e)
		{
			e.printStackTrace();
		}
		return null;
	}
}

Specifically were it says Minecraft.getMinecraft().thePlayer;

Now, this works perfectly fine when running the mod as the CombinedClient only. Whereas the server crashes. And the server crashes because the server does not contain the classes for anything client only. E.g. the Minecraft class. Also GUIs and any renderer. They are client side classes and so the server doesn't have them.

 

So how do I get the player I am sending the packet to I guess you could say instead of using Minecraft.getMinecraft().thePlayer; I need a player instance that works both sides.

We all stuff up sometimes... But I seem to be at the bottom of that pot.

Link to comment
Share on other sites

Hi

 

>If this is a packet that your client sends to the server, the server knows from the packet information which client it came from.

 

The information you need is in the MessageContext ctx, for example

  public IMessage onMessage(MessageClientPlayerInfo message, MessageContext ctx)
  {
    switch (ctx.side) {
      case CLIENT: {
        EntityClientPlayerMP entityClientPlayerMP = Minecraft.getMinecraft().thePlayer;
      }
      case SERVER: {
        EntityPlayerMP entityPlayerMP = ctx.getServerHandler().playerEntity;
      }
      default:
        assert false : "Invalid side in TestMsgHandler: " + ctx.side;
    }

 

Is that what you need?

 

-TGG

Link to comment
Share on other sites

No that is absolutely NOT what I need. Take a look at what the server does if I use that:

---- Minecraft Crash Report ----
// Don't do that.

Time: 6/22/14 1:12 PM
Description: Exception in server tick loop

cpw.mods.fml.common.LoaderException: java.lang.NoClassDefFoundError: net/minecraft/client/entity/EntityClientPlayerMP
at cpw.mods.fml.common.LoadController.transition(LoadController.java:162)
at cpw.mods.fml.common.Loader.preinitializeMods(Loader.java:514)
at cpw.mods.fml.server.FMLServerHandler.beginServerLoading(FMLServerHandler.java:88)
at cpw.mods.fml.common.FMLCommonHandler.onServerStart(FMLCommonHandler.java:313)
at net.minecraft.server.dedicated.DedicatedServer.startServer(DedicatedServer.java:117)
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:442)
at net.minecraft.server.MinecraftServer$2.run(MinecraftServer.java:746)
Caused by: java.lang.NoClassDefFoundError: net/minecraft/client/entity/EntityClientPlayerMP
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2446)
at java.lang.Class.getConstructor0(Class.java:2756)
at java.lang.Class.newInstance0(Class.java:328)
at java.lang.Class.newInstance(Class.java:310)
at cpw.mods.fml.common.network.simpleimpl.SimpleChannelHandlerWrapper.<init>(SimpleChannelHandlerWrapper.java:22)
at cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper.getHandlerWrapper(SimpleNetworkWrapper.java:129)
at cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper.addClientHandlerAfter(SimpleNetworkWrapper.java:123)
at cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper.registerMessage(SimpleNetworkWrapper.java:111)
at com.kwibble.dendri.network.DendriNetwork.registerNetwork(DendriNetwork.java:23)
at com.kwibble.dendri.ModuleDendri.on(ModuleDendri.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at cpw.mods.fml.common.FMLModContainer.handleModStateEvent(FMLModContainer.java:513)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.google.common.eventbus.EventHandler.handleEvent(EventHandler.java:74)
at com.google.common.eventbus.SynchronizedEventHandler.handleEvent(SynchronizedEventHandler.java:47)
at com.google.common.eventbus.EventBus.dispatch(EventBus.java:314)
at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:296)
at com.google.common.eventbus.EventBus.post(EventBus.java:267)
at cpw.mods.fml.common.LoadController.sendEventToModContainer(LoadController.java:208)
at cpw.mods.fml.common.LoadController.propogateStateMessage(LoadController.java:187)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.google.common.eventbus.EventHandler.handleEvent(EventHandler.java:74)
at com.google.common.eventbus.SynchronizedEventHandler.handleEvent(SynchronizedEventHandler.java:47)
at com.google.common.eventbus.EventBus.dispatch(EventBus.java:314)
at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:296)
at com.google.common.eventbus.EventBus.post(EventBus.java:267)
at cpw.mods.fml.common.LoadController.distributeStateMessage(LoadController.java:118)
at cpw.mods.fml.common.Loader.preinitializeMods(Loader.java:512)
... 5 more
Caused by: java.lang.ClassNotFoundException: net.minecraft.client.entity.EntityClientPlayerMP
at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
... 43 more
Caused by: java.lang.RuntimeException: Attempted to load class net/minecraft/client/entity/EntityClientPlayerMP for invalid side SERVER
at cpw.mods.fml.common.asm.transformers.SideTransformer.transform(SideTransformer.java:50)
at net.minecraft.launchwrapper.LaunchClassLoader.runTransformers(LaunchClassLoader.java:276)
at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:174)
... 45 more


A detailed walkthrough of the error, its code path and all known details is as follows:
---------------------------------------------------------------------------------------

-- System Details --
Details:
Minecraft Version: 1.7.2
Operating System: Mac OS X (x86_64) version 10.8.5
Java Version: 1.6.0_65, Apple Inc.
Java VM Version: Java HotSpot(TM) 64-Bit Server VM (mixed mode), Apple Inc.
Memory: 992198536 bytes (946 MB) / 1065025536 bytes (1015 MB) up to 1065025536 bytes (1015 MB)
JVM Flags: 3 total; -Xincgc -Xmx1024M -Xms1024M
AABB Pool Size: 0 (0 bytes; 0 MB) allocated, 0 (0 bytes; 0 MB) used
IntCache: cache: 0, tcache: 0, allocated: 0, tallocated: 0
FML: MCP v9.03 FML v7.2.211.1121 Minecraft Forge 10.12.2.1121 4 mods loaded, 4 mods active
mcp{9.03} [Minecraft Coder Pack] (minecraft.jar) Unloaded->Constructed->Pre-initialized
FML{7.2.211.1121} [Forge Mod Loader] (forgeSrc-1.7.2-10.12.2.1121.jar) Unloaded->Constructed->Pre-initialized
Forge{10.12.2.1121} [Minecraft Forge] (forgeSrc-1.7.2-10.12.2.1121.jar) Unloaded->Constructed->Pre-initialized
dendri{1.7.2_0.0.1} [Dendri] (ModuleDendri) Unloaded->Constructed->Errored
Profiler Position: N/A (disabled)
Is Modded: Definitely; Server brand changed to 'fml,forge'
Type: Dedicated Server (map_server.txt)

We all stuff up sometimes... But I seem to be at the bottom of that pot.

Link to comment
Share on other sites

ah yeah, mental blank, sorry.  Try this instead.

 

    switch (ctx.side) {
      case CLIENT: {
        EntityPlayer entityPlayer = Minecraft.getMinecraft().thePlayer;
      }
      case SERVER: {
        EntityPlayer entityPlayer = ctx.getServerHandler().playerEntity;
      }
      default:
        assert false : "Invalid side in TestMsgHandler: " + ctx.side;
    }

 

 

If that doesn't work due to the Minecraft.getMinecraft(), try creating your own "get the player from this context" method in your proxy class

 

i.e.

CommonProxy::
  public EntityPlayer getPlayerFromMessageContext( MessageContext ctx);

CombinedClient::
  @Override
  public EntityPlayer getPlayerFromMessageContext( MessageContext ctx)
  {
    switch (ctx.side) {
      case CLIENT: {
        EntityPlayer entityClientPlayerMP = Minecraft.getMinecraft().thePlayer;
      }
      case SERVER: {
        EntityPlayer entityPlayerMP = ctx.getServerHandler().playerEntity;
      }
      default:
        assert false : "Invalid side in TestMsgHandler: " + ctx.side;
    }

DedicatedServer::  (or alternatively - just place into CommonProxy and let CombinedClient override it)
  @Override
  public EntityPlayer getPlayerFromMessageContext( MessageContext ctx)
  {
    switch (ctx.side) {
      case CLIENT: {
         assert false : "Message for CLIENT received on dedicated server";
      }
      case SERVER: {
        EntityPlayer entityPlayerMP = ctx.getServerHandler().playerEntity;
      }
      default:
        assert false : "Invalid side in TestMsgHandler: " + ctx.side;
    }

 

-TGG

Link to comment
Share on other sites

I've been working with Kwibble on a project, and this is our biggest hurdle as of the moment.

 

@TGG, neither of those proposed solutions would work. Because the side that receives the packet (in this case in particular, at least) is always the client, ctx.side will never have a SERVER case.

Link to comment
Share on other sites

Hi Malkuthe

 

I think we're going round in circles a bit here... :)

 

Let me try to recap what the problem is.

 

1) The server receives some sort of event or notification or Message that a player has logged on

2) It then finds the information for that player, bundles it up into a Message, and sends that to the client.

3) The client gets the Message, reads out the relevant fields, and writes it into the PlayerInformation class.

 

It seems you have two issues, then?

In step 1- how does your server know which player has logged on?

In step 3 - if you register this class on a dedicated server side, Minecraft doesn't like it, and even if you check the side, it still doesn't like it because some of the client classes don't exist.

 

The step 1 problem solution depends on which event, notification, message etc that your server is using to tell when a player has logged on.

The step 3 problem you can fix either by not registering your SimpleNetworkWrapper on the server side and making sure none of your server side code creates or calls SimpleNetworkWrapper, or alternatively using the proxy methods I described in my last post.

 

-TGG

 

Link to comment
Share on other sites

Thanks TGG! Your proxy method worked - only problems seems to be that now my packet in my item isn't being sent to the server... :/ Well. That is another problem, but not the first! Thank you very much sir! Kudos and giant chocolate covered coconuts for you!

We all stuff up sometimes... But I seem to be at the bottom of that pot.

Link to comment
Share on other sites

That we did. I apologize for not explaining it well enough in the first place, I had been talking to Malkuthe about it for a while and I was used to him already knowing some things :P

We all stuff up sometimes... But I seem to be at the bottom of that pot.

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



×
×
  • Create New...

Important Information

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