Jump to content

[1.7.10] Changing Player Model - Multiplayer issue with Models Showing Up


Thornack

Recommended Posts

Hi Everyone,

 

So I have a working method for changing the players model. I have a key binding event that allows for a player HUD element to be clicked on (it gets the client player and changes a couple of variables inside this players IEEP instance(on Client side) and frees up the mouse so that the player can click on the hud button). My event that changes the players model is triggered when the client player clicks a button in his HUD. This HUD button gets the client player and changes a variable inside this players IEEP that is used by my event to conditionally trigger changing the model. depending on which booleans are true and what the values are of my variables the players model changes to a different one.

 

When I am on Single Player, everything works perfectly the models change I can scroll through the models I want, they render properly etc etc.

 

When I am on Multiplayer and one player is in the world that player can see his/her own model just fine and can change it to be whatever they want just as in single player

 

The problem arises when a second or third or any additional players join the server, from the perspective of one player looking at another when the second player changes his/her model nothing happens and you see default steve, when I change my model the second player disappears and becomes invisible and my model shows up but his model renders on top of mine (but not exactly) as it is always the same model (my default model with ID=25) no matter what he selects (but I think I know why). The weird bit is that when the other player moves or changes direction and I stay still. I can see his model animate, turn, move legs, arms, etc... and when I do damage to the other player his model changes texture to display the hurt texture (that reddish tinge).

 

I realize this isnt a simple bug and am working to solve the issue but I am pretty sure its due to the following code

 

@SubscribeEvent
public void onRenderPlayerPre(RenderPlayerEvent.Pre pre) {

	CustomIEEPClass cIEEP = CustomIEEPClass.get(this.mc.thePlayer); // Client Side Player
	if (cIEEP == null) {
		return;
	}

	   	
	if(cIEEP.isInBattle == true){
		pre.setCanceled(true); // this stops the player from rendering
		float modelYOffset = -1.625F;
		CustomIEEPClass playerProperties = CustomIEEPClass.get(pre.entityPlayer);
		int modelId = playerProperties.getModelId();	//default model is model with ID = 25 this is the model that always renders on top of your model in multiplayer when additional players join world
		Render renderCustomModel = PlayerRenderingRegistry.getRendererByModelId(modelId); //get the chosen models renderer using its id

		renderCustomModel.doRender(pre.entity, 0F, modelYOffset, 0F, 0F, 0.0625F);
		}

}

 

Now I think I know why I am always getting the default model rendering on top of my players model when an additional player changes models no matter what model he changes into, it is because my players IEEP instance has no way of knowing currently which model ID the other player chose and as such with the way this is currently set up I get the default model rendering on top of mine.

 

This shouldnt happen though, I want the additional players model to render at their position and not my players position. So I have a couple of questions,

 

Does anyone know why the other players default Steve model gets cancelled when I change my model?

 

Does anyone know why their new model renders at my players position?

 

Does anyone have any ideas as to how to provide a structure for ensuring the correct models rendering for each player? Id assume using a packet system and somehow storing my model id for each player somehow and updating all players with the packet within a range to have the correct models render. But im not sure

Link to comment
Share on other sites

While I don't know the answer to all of those questions, one thing is for certain - you need to store the current model ID in the player's SERVER-side IEEP, then have that send out a packet to all other players (on the client) letting them know what that player's current model is.

 

The trouble is that players don't have any way to know what another player's client-side status is, thus the need to relay that information to the server first, then back to all client players.

 

As for the models overlapping and that kind of thing, I'm not really sure, but you may want to try keeping a list of players and their current model IDs on each client (synchronized from the server, of course, whenever one of their IEEPs changes) - this way when your client rendering code is called, it can find the correct model for the player being rendered.

Link to comment
Share on other sites

CustomIEEPClass cIEEP = CustomIEEPClass.get(this.mc.thePlayer);

 

Never, ever, ever use one object to define behaviour of all (while you want each to have different obviously).

By that I mean you are making all players use you own client-player. This is reason why your movement causes all player models to move with your movements (arms, legs, etc). use player-specific variable (from event).

 

As to synchronizing - as said before, you need to tell other client to change value for your player.

CLIENT -> clicks button -> button sends message to servr to change model of player -> server changes model value on server-sided IEEP -> server sends changes value to ALL (including clicking player) players that needs update (see player that sent button-click) -> packets are sent, clients are updated.

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

Link to comment
Share on other sites

Welp, this needs to be said. You are now (with your mod) entering area of what I would call "dynamic" data tracking.

 

To make example: There is a SERVER and two CLIENTs. One client joins server and changes it's model, server updates IEEP value to some model. Now second player logs in - he doesn't know about other player's value. You need to tell him.

Few facts:

- Client only loads Entities that are in visible range (that is 60-256 blocks in "edge" cases). This means that if one player is further than some players visible range he doesn't have it's Entity constructed, thus you can't just send stuff.

- Following previous fact - you need to updat value dynamically - when player starts tracking other player.

 

To do that use:

PlayerEvent.StartTracking

This event is launched (server-side only) when one player "sees" some other entity, you can check if that entity is EntityPlayer and update it's values (send packet from server to client with update - your model for example).

EDIT (important)

Next thing with packeting is:

EntityTracker

 

When player click button to chenge value of his model (I am following what i wrote previously) packet from client is sent to server, server-side IEEP's model vallue is changed. Now, you need to send updates to all that need that value, to do that you will use:

EntityTracker et = ((WorldServer) player.worldObj).getEntityTracker(); // player is the one that sent change to his model
// now you will make that so all other players that are "tracking" player that changed his model will get update
et.func_151248_b(player, YourPacketHandler.getInstance().getPacketFrom(new PacketWithModelupdate()));
// Method above sends packet to player and all other players that require update.

 

Private note: This above is tight shit, it's good to know it. 8)

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

Link to comment
Share on other sites

Changing this

CustomIEEPClass cIEEP = CustomIEEPClass.get(pre.entityPlayer);

 

to

 

CustomIEEPClass cIEEP = CustomIEEPClass.get(pre.entityPlayer);

 

fixed the using one object to define all behaviour issue I believe, at least it did fix the other players model rendering on top of mine haha so thats great, Ya I  was wondering about the dynamic updating and how to do that thanks for the event, ill definitely use that.

 

 

Link to comment
Share on other sites

I have a question, my packet handler class does not have the .getInstance() and .getPacketFrom methods. Instead I send my packets in the following way

 

PacketOverlord.sendToServer(new Packet());

 

where I have the following methods in my handler, should I create a get instance method and a getPacketFrom method?

 

/**
* Contains instance of SimpleNetworkWrapper and provides wrapper methods for
* sending packets.
*/
public class PacketOverlord {
private static byte packetId = 0;

private static final SimpleNetworkWrapper dispatcher = NetworkRegistry.INSTANCE
		.newSimpleChannel(CustomMod.CHANNEL);

/**
 * Register all packets and handlers here - this should be called during
 * {@link FMLPreInitializationEvent}
 */
public static final void preInit() {
	registerMessage(Packet.class);
	}

/**
 * Register an {@link AbstractMessageOverlord} to the correct side
 */
private static final <T extends AbstractMessageOverlord<T> & IMessageHandler<T, IMessage>> void registerMessage(
		Class<T> clazz) {
	if (AbstractMessageOverlord.AbstractClientMessage.class.isAssignableFrom(clazz)) {
		PacketOverlord.dispatcher.registerMessage(clazz, clazz,
				packetId++, Side.CLIENT);
	} else if (AbstractMessageOverlord.AbstractServerMessage.class
			.isAssignableFrom(clazz)) {
		PacketOverlord.dispatcher.registerMessage(clazz, clazz,
				packetId++, Side.SERVER);
	} else {
		PacketOverlord.dispatcher.registerMessage(clazz, clazz, packetId,
				Side.CLIENT);
		PacketOverlord.dispatcher.registerMessage(clazz, clazz,
				packetId++, Side.SERVER);
	}
}

public static final void sendTo(IMessage message, EntityPlayerMP player) {
	PacketOverlord.dispatcher.sendTo(message, player);
}

public static void sendToAll(IMessage message) {
	PacketOverlord.dispatcher.sendToAll(message);
}

public static final void sendToAllAround(IMessage message,
		NetworkRegistry.TargetPoint point) {
	PacketOverlord.dispatcher.sendToAllAround(message, point);
}

public static final void sendToAllAround(IMessage message, int dimension,
		double x, double y, double z, double range) {
	PacketOverlord.sendToAllAround(message,
			new NetworkRegistry.TargetPoint(dimension, x, y, z, range));
}

public static final void sendToAllAround(IMessage message,
		EntityPlayer player, double range) {
	PacketOverlord.sendToAllAround(message,
			player.worldObj.provider.dimensionId, player.posX, player.posY,
			player.posZ, range);
}

public static final void sendToDimension(IMessage message, int dimensionId) {
	PacketOverlord.dispatcher.sendToDimension(message, dimensionId);
}

public static final void sendToServer(IMessage message) {
	PacketOverlord.dispatcher.sendToServer(message);
}
}

Link to comment
Share on other sites

I guess the reason why I am asking is because I already have a method of sending a packet to all players around me using

 

public static final void sendToAllAround(IMessage message, EntityPlayer player, double range) {

PacketOverlord.sendToAllAround(message,player.worldObj.provider.dimensionId, player.posX, player.posY,player.posZ, range);

}

Link to comment
Share on other sites

No, you don't need it - what he was doing there is transforming his custom packet class into a vanilla packet and sending it through the vanilla network (via EntityTracker's method). Pretty slick, but not needed if you don't already have it (I could swear there was some built in code somewhere that was able to do the above for your packets, but I'm not finding it quickly...).

 

What you can do instead is make a method to send to a collection of players, then send to the set of players returned by EntityTracker:

Set<EntityPlayer> players = ((WorldServer) player.worldObj).getEntityTracker().getTrackingPlayers(entityBeingTracked));
PacketDispatcher.sendToPlayers(new YourPacket(), players);

Link to comment
Share on other sites

So far I have the following part down,

 

keyboard button pressed -> sends msg that btn was pressed to server, in the process method of that packet: I update a boolean (that is in my IEEP class) on server side and send a packet to client to update the boolean client side and then free up the mouse to make the HUD element clickable. On Hud element click ->  send msg that it was clicked to server, in that packets process method: I update another boolean (that is in my IEEP class) on server side and send a packet to client to update the boolean client side. Once boolean has been updated on both sides inside my onRender.pre event I run a check for if the correct booleans are true and then cancel the players render, get the model id, get a renderer from model id and render my new model.

 

Im stuck at the next part using the PlayerEvent.StartTracking to check if that entity is EntityPlayer and update it's values. I know how to check if it is EntityPlayer and my event fires only when I "see" a player (by that i mean it fires all the time if I am near enough to a player) but what I dont know how to do is send an update to update all players around using the system I have already in place for handling packets.

 

when server-side IEEP's model vallue is changed.Im not sure how to send updates to all that need that value using the  EntityTracker stuff. my IEEP properties class looks like this

 

(I had to delete a lot of stuff from this class that isnt relevant to this problem but the class does compile and does work perfectly (disclaimer in case someone notices something stupidly funky and tells me to "Learn Java") Anyway this is the relevant code.

 


private final EntityPlayer player;
public boolean isInBattle = false;
public boolean isModelChanged = false;
public boolean openBattleHUD = false;
public boolean isPlayerInThirdPersonView = false;
public boolean battleKeyPressed = false;
public boolean wasAttacked = false;

public int modelId = 25;	//the id of the model the player should render as

public static final int ModelId_Watcher = 31;

public BattlePlayerProperties(EntityPlayer player) {
	this.player = player;
	this.player.getDataWatcher().addObject(ModelId_Watcher,modelId);
}

/**
 * Used to register these extended properties for the player during EntityConstructing event
 */
public static final void register(EntityPlayer player) {
	player.registerExtendedProperties("BattleMobExtendedPlayerHelper", new BattlePlayerProperties(player));
}

/**
 * Returns BattleMobExtendedPlayerHelper properties for player
 */
public static final BattlePlayerProperties get(EntityPlayer player) {
	return (BattlePlayerProperties) player.getExtendedProperties("BattleMobExtendedPlayerHelper");
}

/**
 * Copies additional player data from the given BattleMobExtendedPlayerHelper instance
 * Avoids NBT disk I/O overhead when cloning a player after respawn
 */
public void copy(BattlePlayerProperties props) {
}

@Override
public final void saveNBTData(NBTTagCompound compound) {
	NBTTagCompound properties = new NBTTagCompound();
	properties.setInteger("ModelId", modelId);
	compound.setTag("BattleMobExtendedPlayerHelper", properties);
}

@Override
public final void loadNBTData(NBTTagCompound compound) {
	NBTTagCompound properties = (NBTTagCompound) compound.getTag("BattleMobExtendedPlayerHelper");
	player.getDataWatcher().updateObject(ModelId_Watcher, properties.getInteger("ModelId"));
	}

@Override
public void init(Entity entity, World world) {}

public void setModelId(int modelId){
	this.modelId = modelId;
	this.player.getDataWatcher().updateObject(ModelId_Watcher, this.modelId);
}

public int getModelId(){
	return this.player.getDataWatcher().getWatchableObjectInt(ModelId_Watcher);
}

}

 

My event where I change my model

@SubscribeEvent
public void onRenderPlayerPre(RenderPlayerEvent.Pre pre) {

	BattlePlayerProperties battlePlayerProperties = BattlePlayerProperties.get(pre.entityPlayer); // Client Side Player
	if (battlePlayerProperties == null) {
		return;
	}
	if(battlePlayerProperties.isInBattle == true || battlePlayerProperties.isMorphed == true ){
		pre.setCanceled(true); // this stops the player from rendering
		float modelYOffset = -1.625F;
		BattlePlayerProperties playerProperties = BattlePlayerProperties.get(pre.entityPlayer);
		int modelId = playerProperties.getModelId();	//default 25
		Render renderModel = PlayerRenderingRegistry.getRendererByModelId(modelId);
		System.out.println("rendering player" + pre.entityPlayer); 
		renderModel.doRender(pre.entity, 0F, modelYOffset, 0F, 0F, 0.0625F);
		}

}

At this point I am sure my client and server values for my booleans are synced up.The problem is that if(battlePlayerProperties.isInBattle == true || battlePlayerProperties.isMorphed == true){} <-- These are never true for other players because the client has no idea that these have changed for these players when I "see" them. This is where I am stuck, I am not sure how to do the updating bit. Do I need to store the instances of other players in each players IEEP and use packets to update the values of the model id in each instance??

 

Link to comment
Share on other sites

No, you don't need it - what he was doing there is transforming his custom packet class into a vanilla packet and sending it through the vanilla network (via EntityTracker's method). Pretty slick, but not needed if you don't already have it (I could swear there was some built in code somewhere that was able to do the above for your packets, but I'm not finding it quickly...).

 

What you can do instead is make a method to send to a collection of players, then send to the set of players returned by EntityTracker:

Set<EntityPlayer> players = ((WorldServer) player.worldObj).getEntityTracker().getTrackingPlayers(entityBeingTracked));
PacketDispatcher.sendToPlayers(new YourPacket(), players);

 

do you mean something like

 

public static final void sendToPlayers(IMessage message, Set<EntityPlayer> player) {

PacketOverlord.dispatcher.sendTo(message, (EntityPlayerMP) player);

}

Link to comment
Share on other sites

No, you don't need it - what he was doing there is transforming his custom packet class into a vanilla packet and sending it through the vanilla network (via EntityTracker's method). Pretty slick, but not needed if you don't already have it (I could swear there was some built in code somewhere that was able to do the above for your packets, but I'm not finding it quickly...).

 

What you can do instead is make a method to send to a collection of players, then send to the set of players returned by EntityTracker:

Set<EntityPlayer> players = ((WorldServer) player.worldObj).getEntityTracker().getTrackingPlayers(entityBeingTracked));
PacketDispatcher.sendToPlayers(new YourPacket(), players);

 

do you mean something like

 

public static final void sendToPlayers(IMessage message, Set<EntityPlayer> player) {

PacketOverlord.dispatcher.sendTo(message, (EntityPlayerMP) player);

}

A Set is a type of Collection, so you would need a for each syntax:

public static final void sendToPlayers(IMessage message, Set<EntityPlayer> players) {
for(EntityPlayer player : players) {
PacketOverlord.dispatcher.sendTo(message, (EntityPlayerMP) player);
}
}

 

EDIT in reply to your question about the player not knowing the values of other players: you should be able to send the IEEP values for each player to each other when they begin tracking each other. That's what we've been discussing so far.

 

I haven't personally used PlayerEvent.StartTracking before, so I cannot confirm if it works 100% as advertised, but it should fire each time a player starts to track an entity, not constantly while tracking an entity. At least that's how I would assume it works.

 

If that's not how it works, another option would be as you suggested: keep a list / map of each player with their associated model/state values that is updated any time any player changes their status, and keep that list updated on each client so they are aware of every other player's state.

Link to comment
Share on other sites

Read my posts very carefully, you might have missed something.

 

In your proveious post (one with #sendToPlayers) you can't cast Set of something to something. You need to use for each loop and send to all in Set.

 

Tell me what works: (in this format: 1.1 ; 1.2 ; 1.3 ; 2.2;  2.3 ; etc)

 

Situation 1:

There is Server and 2 Clients, Client ONE and TWO are logged in and see themselves, Client ONE clicks button, changes model:

- Server IEEP is updated

- On Client ONE, the IEEP ONE is updated.

- On CLient TWO, the IEEP ONE is updated.

 

Situation 2:

There is Server and 2 Clients, Client ONE and TWO are logged in and DON'T see themselves. Client ONE clicks button, changes model:

- Server IEEP is updated

- On Client ONE, the IEEP ONE is updated

- When Client TWO starts seeing Client ONE, he gets update about his model

 

Situation 3:

There is Server and 2 Clients, Client ONE and TWO are logged in and DON'T see themselves. Client ONE AND TWO changes their models and suddenly "meet" (see themselves):

- Both server IEEPs are updated

- Client ONE has his model and Client TWO has his model (own entity)

- Client ONE sees correct model of TWO, Client TWO sees correct model of ONE

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

Link to comment
Share on other sites

Haha Ya thanks, I noticed that after I posted it and fixed it to use the for loop

 

So The packet seems to send but there is a problem.

 

Situation 1:

There is Server and 2 Clients, Client ONE and TWO are logged in and see themselves, Client ONE clicks button, changes model:

- Server IEEP is updated

- On Client ONE, the IEEP ONE is updated and model changes but then after a few seconds the model changes back to original steve model. Im just setting up debug statements now

- on Client Two, nothing shows up model change isnt seen at all.

 

My event

@SubscribeEvent(priority=EventPriority.NORMAL)
public void onRenderPre(PlayerEvent.StartTracking event) {
	if (event.entityPlayer != null && event.entityPlayer instanceof EntityPlayer ){

		EntityTracker et = ((WorldServer) event.entityPlayer.worldObj).getEntityTracker(); // player is the one that sent change to his model
		Set<EntityPlayer> players = ((WorldServer) event.entityPlayer.worldObj).getEntityTracker().getTrackingPlayers(EntityPlayer);
		System.out.println("found player" + players);// I find players when there is two or more, when it is just me I get "found player []" printed to consol
		if(players!=null){
		PacketOverlord.sendToPlayers(new PacketUpdateModel(), players); // crashes
		}
	}
}

 

The packet:  this packet is sent from the server to client to update values client side in its process method. I send this packet from the process method of my other packet that I send from client to server upon button click that notifies server of button click.


public class PacketUpdateIsMorphed  extends AbstractClientMessage<PacketUpdateIsMorphed> {

boolean isMorphed;
int modelID;

public PacketUpdateIsMorphed() {}
public PacketUpdateIsMorphed(boolean isMorphed, int modelID) {
	System.out.println("Updating is Morphed after Btn Press Sending a Packet");
	this.isMorphed = isMorphed;
	this.modelID = modelID;

}

@Override
protected void read(PacketBuffer buffer) throws IOException {
	isMorphed = buffer.readBoolean();
	modelID = buffer.readInt();
	}

@Override
protected void write(PacketBuffer buffer) throws IOException {
	buffer.writeBoolean(isMorphed);
	buffer.writeInt(modelID);
	}

@Override
public void process(EntityPlayer player, Side side) {

   if(player.worldObj.isRemote){ //player is only the client side player here using if(!player.worldObj.isRemote) does not work nothing is called
BattlePlayerProperties battlePlayerProperties = BattlePlayerProperties.get(player);
    battlePlayerProperties.isMorphed = isMorphed;
    battlePlayerProperties.modelId = modelID; 
  	}
   }
   }

 

Link to comment
Share on other sites

This is what you are doing: (joke alert)

 

9912ppo.gif

 

In short - you are not understanding the fact that one SERVER has many CLIENTS connected and one CLIENT has many PLAYERS (which are other Clients on same server). EDIT: Also what I've wrote before - Some client not always have other client's player constructed - ONLY when they see them (start tracking).

 

If there are 2 Clients on Server, then there is:

Server IEEP for ONE

Server IEEp for two

Client ONE IEEP for Client ONE (himself)

Client ONE IEEP for Client TWO (and all other clients)

Client TWO IEEP for Client TWO (himself)

Client TWO IEEP for Client ONE (and all other clients)

 

Client tells server to change server stuff, and server tells all clients to changes stuff about one specific client.

 

You need to send entityId (player) inside packet that updates client stuff (from server to client) and use that entityId to change IEEP of specific player.

 

If you need more explanations and few nice tricks - call my Skype: ernio333    (online in ~14 hours from now)

 

Also: There is a BIG WALL between rendering and data-handling - don't EVER use rendering events (player rendering) to send packets or calculate stuff, you just use booleans in IEEP of given player that were previously set.

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

Link to comment
Share on other sites

I think the problem is in the packet. I put a  System.out.println("isMorphed " + isMorphed); line inside the process method and when the process method is called after the packet is sent from my PlayerEvent.StartTracking event, the isMorphed boolean is set to be false for Client 1 since I presume due to Client 2 not morphing he updates Client 1 so that he also doesnt morph (which has the effect of changing the model back to the original. 

 

@Override
public void process(EntityPlayer player, Side side) {

   if(player.worldObj.isRemote){ //player is only the client side player here using if(!player.worldObj.isRemote) does not work nothing is called
BattlePlayerProperties battlePlayerProperties = BattlePlayerProperties.get(player);
    battlePlayerProperties.isMorphed = isMorphed;
   System.out.println("isMorphed " + isMorphed);
    battlePlayerProperties.modelId = modelID; 
  	}

 

I placed the same line into the packets constructor and isMorphed is true on the server side which is what it should be

public PacketUpdateIsMorphed(boolean isMorphed, int modelID) {
  
	System.out.println("Updating is Morphed after Btn Press Sending a Packet");
	this.isMorphed = isMorphed;
                System.out.println("isMorphed " + isMorphed);
	this.modelID = modelID;

}

Link to comment
Share on other sites

Yes I read the post and I kind of understand and am trying to fix, ok so lets start with the event, are you saying that in my event I shouldnt send the packet? is that what you were referring to when you said

 

Also: There is a BIG WALL between rendering and data-handling - don't EVER use rendering events (player rendering) to send packets or calculate stuff, you just use booleans in IEEP of given player that were previously set.[/Quote]

 

second, are you saying for my packet I should get the id of each player in the set that I get from Set<EntityPlayer> players = ((WorldServer) event.entityPlayer.worldObj).getEntityTracker().getTrackingPlayers(event.entityPlayer); and then pass their id to the packet and inside the packets processing method I should update use this id to get the instance of the player that I want to update that players IEEP and there set the model id?

Link to comment
Share on other sites

Yes I read the post and I kind of understand and am trying to fix, ok so lets start with the event, are you saying that in my event I shouldnt send the packet? is that what you were referring to when you said

 

Also: There is a BIG WALL between rendering and data-handling - don't EVER use rendering events (player rendering) to send packets or calculate stuff, you just use booleans in IEEP of given player that were previously set.[/Quote]

 

Yes you shouldn't. Rendering events are called A LOT (FPS-dependent) and sending packet in FPS-time will make you send with ~60FPS about 25 times (depending on ping).

Point is - the client will send packet per FPS until it gets response packet that will change value (and that might even take SECONDS with lags - so you would send more and more and moreeeeee...)

 

As to secong "discovery" - no, you don't want to get Id's of OTHER player, but the id of player who changes model.

There is player "YOU" and X number of OTHER players.

YOU change model (click btn), packet goes to server, server changes server-side IEEP for YOU and sends packet to update their data about YOUR EntityPlayer's IEEP (not theirs, YOURS). Following that, when server sends packets to X OTHER players you need to pack entityId of player who needs to be updater (which is YOU, since you changed model). Then on OTHER's clients, they use Id (which refers to YOU) to update YOUR IEEP model data.

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

Link to comment
Share on other sites

ok, so starting with the event I have the following (I removed the packet)

 

public class EventPlayerModelDataUpdate {
@SubscribeEvent(priority=EventPriority.NORMAL)
public void onTracking(PlayerEvent.StartTracking event) {
	if (event.entityPlayer != null && event.entityPlayer instanceof EntityPlayer ){
		EntityTracker et = ((WorldServer) event.entityPlayer.worldObj).getEntityTracker(); // player is the one that sent change to his model
		Set<EntityPlayer> players = ((WorldServer) event.entityPlayer.worldObj).getEntityTracker().getTrackingPlayers(event.entityPlayer);
		}
}
}

What am I using this event for, As in how do I go on the sevrer "oh my client counterpart requested a model change so I changed his model (<-I do part this already) then lets send a packet to the players I can "see" so that they can update their client" Im not sure where the packet should be sent from and how to structure this givent he information you have shared

Link to comment
Share on other sites

currently this packet is sent from Client to server when I change my model. This packet then updates the server values for my IEEP class and then sends a packet to the client in its process method so that the client version is updated. (i think this is Client 1 going -> request change -> server processes change -> updates client counterpart. Thats it. No external players are updated here. I presume what I should do instead here is I should send the packet to update all players that I see including myself correct? And I presume the event is how I do that correct? Im just not sure how

public class PacketMorphBtnPressed extends AbstractServerMessage<PacketMorphBtnPressed> {
private boolean isMorphed = false;	
public PacketMorphBtnPressed() {}
public PacketMorphBtnPressed(boolean isMorphed) {
	System.out.println("Updating MorphBtnPress Sending a Packet");
	this.isMorphed = isMorphed;			
}

@Override
protected void read(PacketBuffer buffer) throws IOException {
	isMorphed = buffer.readBoolean();
}

@Override
protected void write(PacketBuffer buffer) throws IOException {
	buffer.writeBoolean(isMorphed);			
}

@Override
public void process(EntityPlayer player, Side side) {

   if(!player.worldObj.isRemote && isMorphed == true){
BattlePlayerProperties battlePlayerProperties = BattlePlayerProperties.get(player);// server side player and his battle properties
 battlePlayerProperties.isMorphed = isMorphed;
 int modelID = battlePlayerProperties.getModelId();
     PacketOverlord.sendTo(new PacketUpdateIsMorphed(battlePlayerProperties.isMorphed, modelID),(EntityPlayerMP) player);
 }
   }}

Link to comment
Share on other sites

This event is when player start to see other entity, which might be player. In that moment the "event.target" is the player (other) that showed up for you (your client). So what you need is to get data about the "target" and send this data to "player" (you).

 

Above is case of dynamic update.

 

Second case is when you change model and someone actually SEES you - they won't suddenly call StartTracking, because they are alredy tracking you (see you). In that moment, you will need to use the EntityTracker (to find WHO tracks you).

 

 

Basically whe you change model, the server should get everyone who sees you and send packet that will update them about you.

But if someone is NOT tracking you at current time, but will start soon, they will call StartTracking event - that is where you update data about tracked entity directly.

 

Note that you also need to understand the fact - when two players start to track each other, they both call StartTracking, and both will get data about the other guy.

 

That's it, if you don't understand, read everything again, if still not - AGAIN. There is literally everything you need, and why I am saying that - I am out for ~14hours (as told before), call me after if you want more help. :D And rly - there IS EVERYTHING what needs to be said on this topic.

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

Link to comment
Share on other sites

This event is when player start to see other entity, which might be player. In that moment the "event.target" is the player (other) that showed up for you (your client). So what you need is to get data about the "target" and send this data to "player" (you).

[/Quote]

 

Doesn't this involve sending a Packet inside the event? To accomplish the getting data about the target stuff?

Link to comment
Share on other sites

I think I understand the "theoretical portion of what needs to happen here" but the actual practical bit I am fuzzy on. Player clicks btn - sends request to server - server processes request - changes server IEEP for player - sends packet to client players counterpart and updates this client players IEEP to sync up the IEEP. I know how to do that and this works.

 

Here is where I am stuck, I know I have to go My player clicks btn - send request to server - server processes request - changes server IEEP for my player - find who tracks my player - send update packet to these players to update them about me

 

1) where do I ->  (find who tracks my player - send update packet to these players to update them about me). Do I do this inside my packet that sends request to server notifying server of button press? Because this packet does processing on the server side (would that be where I would do the find who tracks my player - send update packet to these players to update them about me) would I do this inside its process method by doing

 

@Override
public void process(EntityPlayer player, Side side) {

   if(!player.worldObj.isRemote && isMorphed == true){
BattlePlayerProperties battlePlayerProperties = BattlePlayerProperties.get(player);// server side player and his battle properties
 battlePlayerProperties.isMorphed = isMorphed;
 int modelID = battlePlayerProperties.getModelId();
     PacketOverlord.sendTo(new PacketUpdateIsMorphed(battlePlayerProperties.isMorphed, modelID),(EntityPlayerMP) player);

// Would I do the find who tracks my player - send update packet to these players to update them about me here ??
     Set<EntityPlayer> players = ((WorldServer) player.worldObj).getEntityTracker().getTrackingPlayers(player);
     PacketOverlord.sendToPlayers(new PacketUpdateClientPlayersAroundMe(battlePlayerProperties.isMorphed, modelID, player), players);
 }
   }}

 

Then inside my PacketUpdateClientPlayersAroundMe would I do the following?


public class PacketUpdateClientPlayersAroundMe  extends AbstractServerMessage<PacketUpdateClientPlayersAroundMe > {
boolean isMorphed;
int modelID;
EntityPlayer player;	 
public PacketUpdateClientPlayersAroundMe() {}
public PacketUpdateClientPlayersAroundMe(boolean isMorphed, int modelID, EntityPlayer player) {
	System.out.println("Updating Client Players Sending a Packet");
	this.isMorphed = isMorphed;
	this.player = player;
	this.modelID = modelID;

}

@Override
protected void read(PacketBuffer buffer) throws IOException {
	isMorphed = buffer.readBoolean();
	modelID = buffer.readInt();
	}

@Override
protected void write(PacketBuffer buffer) throws IOException {
	buffer.writeBoolean(isMorphed);
	buffer.writeInt(modelID);
	}

@Override
public void process(EntityPlayer player, Side side) {

   if(player.worldObj.isRemote){ //player is only the client side player here using if(!player.worldObj.isRemote) does not work nothing is called
BattlePlayerProperties battlePlayerProperties = BattlePlayerProperties.get(this.player);
    battlePlayerProperties.isMorphed = isMorphed;
    battlePlayerProperties.modelId = modelID;
  	}
   }
   }

 

2) for Dynamic Updating -> in the PlayerEvent.StartTracking event I know I have to get the data from the player that shows up (the player that I start tracking) when the event is called. and I know I have to send this data to my player (me). Im not sure how to do that. Wouldn't this involve sending a packet from the event?

Link to comment
Share on other sites

In your 'update players around me' packet, you need to send the original player's entityId so that the other players, when they receive the packet, can update the information for THAT player, otherwise you are just setting their own data to whatever the other player's is.

 

So, in your packet:

public YourPacket(EntityPlayer playerWhoChanged) {
this.entityId = playerWhoChanged.getEntityId();
this.isMorphed = YourIEEP.get(playerWhoChanged).isMorphed;
}

// obviously taking liberties with the method parameters here
public process(Message msg, EntityPlayer player) {
EntityPlayer playerWhoChanged = player.worldObj.getEntityById(msg.entityId);
YourIEEP.get(player).setOtherPlayerInfo(playerWhoChanged, msg.isMorphed);
}

Each player needs to know the status of the other player, and you cannot do that unless you have the information for that other player when updating the current one. Does that make sense?

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.