Jump to content

[1.8.9] Some help on understanding networking


JimiIT92

Recommended Posts

So i'm trying to add some extended player properties and makes so no unnecessary packets are sends through client/server. But since i've never worked with packets i did not really understand when i should send a packet to the client and when i should send it to the server. By now i send a packet only when something change (for example: the mana value has changed), but if i do this in a tick handler the mod crashes, giving a ClassCastException

java.lang.ClassCastException: net.minecraft.client.entity.EntityPlayerSP cannot be cast to net.minecraft.entity.player.EntityPlayerMP
at com.rpg.player.PlayerProperties.sendToClient(PlayerProperties.java:194)
at com.rpg.player.PlayerProperties.setMana(PlayerProperties.java:113)
at com.rpg.player.PlayerProperties.removeMana(PlayerProperties.java:121)
at com.rpg.player.PlayerProperties.tick(PlayerProperties.java:217)
at com.rpg.events.PlayerTick.onTick(PlayerTick.java:14)
at net.minecraftforge.fml.common.eventhandler.ASMEventHandler_12_PlayerTick_onTick_PlayerTickEvent.invoke(.dynamic)
at net.minecraftforge.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:49)
at net.minecraftforge.fml.common.eventhandler.EventBus.post(EventBus.java:140)
at net.minecraftforge.fml.common.FMLCommonHandler.onPlayerPostTick(FMLCommonHandler.java:357)
at net.minecraft.entity.player.EntityPlayer.onUpdate(EntityPlayer.java:402)
at net.minecraft.client.entity.EntityPlayerSP.onUpdate(EntityPlayerSP.java:163)
at net.minecraft.world.World.updateEntityWithOptionalForce(World.java:2011)
at net.minecraft.world.World.updateEntity(World.java:1976)
at net.minecraft.world.World.updateEntities(World.java:1805)
at net.minecraft.client.Minecraft.runTick(Minecraft.java:2176)
at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:1080)
at net.minecraft.client.Minecraft.run(Minecraft.java:380)
at net.minecraft.client.main.Main.main(Main.java:116)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at net.minecraftforge.gradle.GradleStartCommon.launch(GradleStartCommon.java:97)
at GradleStart.main(GradleStart.java:26)

 

And this are all the classes involved:

 

PlayerProperties

package com.rpg.player;

import com.rpg.RPG;
import com.rpg.messages.EnergyRegenTimer;
import com.rpg.messages.EnergyValue;
import com.rpg.messages.GoldValue;
import com.rpg.messages.ManaRegenTimer;
import com.rpg.messages.ManaValue;
import com.rpg.messages.MaxEnergyValue;
import com.rpg.messages.MaxManaValue;
import com.rpg.messages.PlayerClass;

import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import net.minecraftforge.common.IExtendedEntityProperties;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;

public class PlayerProperties implements IExtendedEntityProperties {

public final static String PLAYER_PROPERTIES = "PlayerProperties";
private EntityPlayer player;

private int mana;
private int maxMana;
private int energy;
private int maxEnergy;
private int gold;
private String playerClass;
private boolean firstJoin;
private int manaRegenTimer;
private int energyRegenTimer;

private int ticks = 0;

public PlayerProperties(EntityPlayer player) {
	this.player = player;
	this.mana = this.maxMana = 100;
	this.energy = this.maxEnergy = 100;
	this.firstJoin = true;
	this.playerClass = "";
	this.manaRegenTimer = 10;
	this.energyRegenTimer = 10;
	this.gold = 0;
}

public static final void register(EntityPlayer player) {
	player.registerExtendedProperties(PLAYER_PROPERTIES, new PlayerProperties(player));
}

public static final PlayerProperties get(EntityPlayer player) {
	return (PlayerProperties) player.getExtendedProperties(PLAYER_PROPERTIES);
}

@Override
public void saveNBTData(NBTTagCompound compound) {
	NBTTagCompound nbt = new NBTTagCompound();

	nbt.setInteger("mana", this.mana);
	nbt.setInteger("maxMana", this.maxMana);
	nbt.setInteger("energy", this.energy);
	nbt.setInteger("maxEnergy", this.maxEnergy);
	nbt.setInteger("gold", this.gold);
	nbt.setString("playerClass", this.playerClass);
	nbt.setBoolean("firstJoin", this.firstJoin);
	nbt.setInteger("manaRegenTimer", this.manaRegenTimer);
	nbt.setInteger("energyRegenTimer", this.energyRegenTimer);

	compound.setTag(PLAYER_PROPERTIES, nbt);
}

@Override
public void loadNBTData(NBTTagCompound compound) {
	NBTTagCompound nbt = (NBTTagCompound) compound.getTag(PLAYER_PROPERTIES);

	this.mana = nbt.getInteger("mana");
	this.maxMana = nbt.getInteger("maxMana");
	this.energy = nbt.getInteger("energy");
	this.maxEnergy = nbt.getInteger("maxEnergy");
	this.gold = nbt.getInteger("gold");
	this.playerClass = nbt.getString("playerClass");
	this.firstJoin = nbt.getBoolean("firstJoin");
	this.manaRegenTimer = nbt.getInteger("manaRegenTimer");
	this.energyRegenTimer = nbt.getInteger("energyRegenTimer");
}

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

public boolean isFirstJoin() {
	return this.firstJoin;
}

public void setJoined() {
	this.firstJoin = false;
}

public int getMana() {
	return this.mana;
}

public void setMana(int amount) {
	this.mana = amount;
	if (this.mana > this.maxMana)
		this.mana = this.maxMana;
	if (this.mana < 0)
		this.mana = 0;
	this.sendToClient(new ManaValue(this.mana));
}

public void addMana(int amount) {
	this.setMana(this.mana + amount);
}

public void removeMana(int amount) {
	this.setMana(this.mana - amount);
}

public int getMaxMana() {
	return this.maxMana;
}

public void setMaxMana(int amount) {
	this.maxMana = amount;
	this.sendToClient(new MaxManaValue(this.maxMana));
}

public int getEnergy() {
	return this.energy;
}

public void setEnergy(int amount) {
	this.energy = amount;
	if (this.energy > this.maxEnergy)
		this.energy = this.maxEnergy;
	if (this.energy < 0)
		this.energy = 0;
	this.sendToClient(new EnergyValue(this.energy));
}

public int getMaxEnergy() {
	return this.maxEnergy;
}

public void setMaxEnergy(int amount) {
	this.maxEnergy = amount;
	this.sendToClient(new MaxEnergyValue(this.maxEnergy));
}

public int getGold() {
	return this.gold;
}

public void setGold(int amount) {
	this.gold = amount;
	if (this.gold < 0)
		this.gold = 0;
	this.sendToClient(new GoldValue(this.gold));
}

public String getPlayerClass() {
	return this.playerClass;
}

public void setPlayerClass(String playerClass) {
	this.playerClass = playerClass;
	this.sendToClient(new PlayerClass(this.playerClass.charAt(0)));
}

public int getManaRegenTimer() {
	return 20 * this.manaRegenTimer;
}

public void setManaRegenTimer(int amount) {
	this.manaRegenTimer = amount;
	this.sendToClient(new ManaRegenTimer(this.manaRegenTimer));
}

public int getEnergyRegenTimer() {
	return 20 * this.energyRegenTimer;
}

public void setEnergyRegenTimer(int amount) {
	this.energyRegenTimer = amount;
	this.sendToClient(new EnergyRegenTimer(this.energyRegenTimer));
}

private void sendToClient(IMessage message) {
	RPG.network.sendTo(message, (EntityPlayerMP) this.player);
}

private void sendToServer(IMessage message) {
	RPG.network.sendToServer(message);
}

public void copy(PlayerProperties props) {
	this.mana = props.getMana();
	this.maxMana = props.getMaxMana();
	this.energy = props.getEnergy();
	this.maxEnergy = props.getMaxEnergy();
	this.gold = props.getGold();
	this.playerClass = props.getPlayerClass();
	this.firstJoin = props.isFirstJoin();
	this.manaRegenTimer = props.getManaRegenTimer();
	this.energyRegenTimer = props.getEnergyRegenTimer();
}

public void tick() {
	this.ticks++;
	if (this.ticks == this.getManaRegenTimer() && this.mana < this.maxMana) {
		this.ticks = 0;
		this.addMana(5);
	}
}

}

 

ManaValue

package com.rpg.messages;

import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;

public class ManaValue implements IMessage{

private int value;

public ManaValue() {
	this.value = 0;
}

public ManaValue(int amount) {
	this.value = amount;
}

@Override
public void fromBytes(ByteBuf buf) {
	this.value = buf.readInt();
}

@Override
public void toBytes(ByteBuf buf) {
	buf.writeInt(this.value);
}

public void setValue(int amount) {
	this.value = amount;
}

public int getValue() {
	return this.value;
}

}

 

ManaHandler

package com.rpg.handler;

import com.rpg.RPG;
import com.rpg.messages.ManaValue;
import com.rpg.player.PlayerProperties;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.IThreadListener;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;

public class ManaHandler implements IMessageHandler<ManaValue, IMessage>{

public ManaHandler() {

}

@Override
public IMessage onMessage(final ManaValue message, MessageContext ctx) {

	IThreadListener thread = RPG.proxy.getListener(ctx);
	EntityPlayer player = RPG.proxy.getPlayer(ctx);
	if(player != null) {
		final PlayerProperties props = PlayerProperties.get(player);
		if(props != null) {
			thread.addScheduledTask(new Runnable() {
				@Override
				public void run() {
					props.setMana(message.getValue());
				}
			});
		}
	}
	return null;
}

}

 

TickHandler

package com.rpg.events;

import com.rpg.player.PlayerProperties;

import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.PlayerTickEvent;

public class PlayerTick {

@SubscribeEvent
public void onTick(PlayerTickEvent event) {
	PlayerProperties props = PlayerProperties.get(event.player);
	if(props != null && event.player.worldObj.isRemote)
		props.tick();
}
}

 

ClientProxy

package com.rpg.proxy;

import com.rpg.RPG;
import com.rpg.events.DimensionChange;
import com.rpg.events.EntityCreation;
import com.rpg.events.PlayerClone;
import com.rpg.events.PlayerJoin;
import com.rpg.events.PlayerRespawn;
import com.rpg.events.PlayerTick;
import com.rpg.gui.GuiOverlay;
import com.rpg.handler.EnergyHandler;
import com.rpg.handler.EnergyRegenHandler;
import com.rpg.handler.GoldHandler;
import com.rpg.handler.ManaHandler;
import com.rpg.handler.ManaRegenHandler;
import com.rpg.handler.MaxEnergyHandler;
import com.rpg.handler.MaxManaHandler;
import com.rpg.handler.PlayerClassHandler;
import com.rpg.messages.EnergyRegenTimer;
import com.rpg.messages.EnergyValue;
import com.rpg.messages.GoldValue;
import com.rpg.messages.ManaRegenTimer;
import com.rpg.messages.ManaValue;
import com.rpg.messages.MaxEnergyValue;
import com.rpg.messages.MaxManaValue;
import com.rpg.messages.PlayerClass;

import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.IThreadListener;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;

public class ClientProxy extends CommonProxy{

public void preInit() {
	RPG.network = NetworkRegistry.INSTANCE.newSimpleChannel(RPG.MODID);
	RPG.network.registerMessage(ManaHandler.class, ManaValue.class, 0, Side.CLIENT);
}

public void init() {
	MinecraftForge.EVENT_BUS.register(new GuiOverlay(Minecraft.getMinecraft()));
}

public IThreadListener getListener(MessageContext ctx) {
	return Minecraft.getMinecraft();
}

public EntityPlayer getPlayer(MessageContext ctx) {
	return Minecraft.getMinecraft().thePlayer;
}

public void registerEvents() {
	MinecraftForge.EVENT_BUS.register(new PlayerTick());
}
}

 

CommonProxy

package com.rpg.proxy;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.IThreadListener;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;

public class CommonProxy {

public void preInit() {}
public void init() {}

public IThreadListener getListener(MessageContext ctx) {
	return (WorldServer) ctx.getServerHandler().playerEntity.worldObj;
}

public EntityPlayer getPlayer(MessageContext ctx) {
	return ctx.getServerHandler().playerEntity;
}

public void registerEvents() {}
}

 

Main Mod File

package com.rpg;

import com.rpg.proxy.CommonProxy;

import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.Mod.Instance;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;

@Mod(modid = RPG.MODID, version = RPG.VERSION, name = RPG.NAME)
public class RPG
{
@SidedProxy(clientSide = "com.rpg.proxy.ClientProxy", serverSide = "com.rpg.proxy.CommonProxy")
public static CommonProxy proxy;
@Instance("rpg")
public static RPG instance;
public static final String NAME = "RPG Mod";
    public static final String MODID = "rpg";
    public static final String VERSION = "1.0";
    
    public static SimpleNetworkWrapper network;
    
    @EventHandler
public void preInit(FMLPreInitializationEvent event) {
    	proxy.preInit();
    }
    
    @EventHandler
    public void init(FMLInitializationEvent event)
    {
    	proxy.init();
    	proxy.registerEvents();
    }
}

 

Let me know if other classes are needed

So i want to understand how can this work? When i should send a packet to the server and when to the client?

Don't blame me if i always ask for your help. I just want to learn to be better :)

Link to comment
Share on other sites

You're only calling

PlayerProperties#tick

on the client side (when

World#isRemote

is

true

). You need to call it on the server instead (when

World#isRemote

is

false

).

 

The server should control all data and send packets to the relevant clients when they need the data for rendering purposes. The client should receive player input (clicks and key presses) and send packets to the server when these should trigger some action.

 

You should convert your

IExtendedEntityProperties

to a capability,

IEEP

has been removed in 1.9+.

 

You should also annotate override methods with

@Override

so you get a compilation error if they don't actually override a super method.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

I've changed the check in the tick handler, but now this happens: the server sets the value to 100 and the bar in game goes to 100, but this error is fired as soon as it does

[11:56:22] [Client thread/FATAL]: Error executing task
java.util.concurrent.ExecutionException: java.lang.ClassCastException: net.minecraft.client.entity.EntityPlayerSP cannot be cast to net.minecraft.entity.player.EntityPlayerMP
at java.util.concurrent.FutureTask.report(Unknown Source) ~[?:1.8.0_92]
at java.util.concurrent.FutureTask.get(Unknown Source) ~[?:1.8.0_92]
at net.minecraft.util.Util.runTask(Util.java:23) [util.class:?]
at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:1070) [Minecraft.class:?]
at net.minecraft.client.Minecraft.run(Minecraft.java:380) [Minecraft.class:?]
at net.minecraft.client.main.Main.main(Main.java:116) [Main.class:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_92]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_92]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_92]
at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_92]
at net.minecraft.launchwrapper.Launch.launch(Launch.java:135) [launchwrapper-1.12.jar:?]
at net.minecraft.launchwrapper.Launch.main(Launch.java:28) [launchwrapper-1.12.jar:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_92]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_92]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_92]
at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_92]
at net.minecraftforge.gradle.GradleStartCommon.launch(GradleStartCommon.java:97) [start/:?]
at GradleStart.main(GradleStart.java:26) [start/:?]
Caused by: java.lang.ClassCastException: net.minecraft.client.entity.EntityPlayerSP cannot be cast to net.minecraft.entity.player.EntityPlayerMP
at com.rpg.player.PlayerProperties.sendToClient(PlayerProperties.java:208) ~[PlayerProperties.class:?]
at com.rpg.player.PlayerProperties.setMana(PlayerProperties.java:118) ~[PlayerProperties.class:?]
at com.rpg.handler.ManaHandler$1.run(ManaHandler.java:30) ~[ManaHandler$1.class:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) ~[?:1.8.0_92]
at java.util.concurrent.FutureTask.run(Unknown Source) ~[?:1.8.0_92]
at net.minecraft.util.Util.runTask(Util.java:22) ~[util.class:?]
... 15 more

 

and also when relogging the bar is resetted :/

Don't blame me if i always ask for your help. I just want to learn to be better :)

Link to comment
Share on other sites

ManaHandler

calls

PlayerProperties#setMana

, which calls

sendToClient

regardless of which side it was called from. Only call

sendToClient

on the server.

 

Your

ClientProxy#getPlayer

and

getListener

methods are incorrect because they don't account for the logical side (client thread or server thread) that they're being called from and only return the client player and listener. The

MessageContext#side

field tells you which logical side the message was received on.

 

This page explains sides in more detail.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Ok, so i've changed the proxy methods to this

public IThreadListener getListener(MessageContext ctx) {
	return ctx.side == Side.CLIENT ? Minecraft.getMinecraft() : super.getListener(ctx);
}

public EntityPlayer getPlayer(MessageContext ctx) {
	return ctx.side == Side.CLIENT ? Minecraft.getMinecraft().thePlayer : super.getPlayer(ctx);
}

 

but i did not udnerstand where i should call the sendToClient method. I think that this is incorrect and it will loop, so where should i call that method?

package com.rpg.handler;

import com.rpg.RPG;
import com.rpg.messages.ManaValue;
import com.rpg.player.PlayerProperties;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.IThreadListener;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;

public class ManaHandler implements IMessageHandler<ManaValue, IMessage>{

public ManaHandler() {

}

@Override
public IMessage onMessage(final ManaValue message, MessageContext ctx) {

	IThreadListener thread = RPG.proxy.getListener(ctx);
	EntityPlayer player = RPG.proxy.getPlayer(ctx);
	if(player != null) {
		final PlayerProperties props = PlayerProperties.get(player);
		if(props != null) {
			thread.addScheduledTask(new Runnable() {
				@Override
				public void run() {
					props.setMana(message.getValue());
					props.sendToClient(new ManaValue(props.getMana()));
				}
			});
		}
	}
	return null;
}

}

 

EDIT: i've change the addMana function to this

public void addMana(int amount) {
	this.setMana(this.mana + amount);
	this.sendToClient(new ManaValue(this.getMana()));
}

 

now the bar actually updates but it still reset once the player log out

 

Don't blame me if i always ask for your help. I just want to learn to be better :)

Link to comment
Share on other sites

ManaHandler

is called when the client receives a

ManaValue

message from the server.

PlayerProperties#sendToClient

sends a

ManaValue

message from the server to the client.

 

PlayerProperties#sendToClient

must be called from

PlayerProperties#setMana

, but only on the server side (when

World#isRemote

is

false

).

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

I've done the class to sendToClient in the tick method (since this is called only from the tickHandler when world.isRemote is false).

public void tick() {
	this.ticks++;
	if (this.ticks == this.getManaRegenTimer() && this.mana < this.maxMana) {
		this.ticks = 0;
		this.addMana(5);
		this.sendToClient(new ManaValue(this.getMana()));
	}
}

 

In game the bar updates correctly but still when logs out and then re-login the bar goes to default value (95/100)

 

EDIT: in the PlayerJoinEvent i've printed the mana value and it is 100, while the bar displays 95

 

@SubscribeEvent
public void onPlayerJoin(PlayerLoggedInEvent event) {
	PlayerProperties props = PlayerProperties.get(event.player);
	if(props != null) {
		System.out.println(props.getMana());
		if(props.isFirstJoin()) {
			props.setJoined();
		}
	}
}

 

This event is registered as well

Don't blame me if i always ask for your help. I just want to learn to be better :)

Link to comment
Share on other sites

PlayerLoggedInEvent

is only fired on the server.

 

The client doesn't save any data, so you need to send the player's current mana value to their client when they log in.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Tried doing this

package com.rpg.events;

import com.rpg.messages.ManaValue;
import com.rpg.player.PlayerProperties;

import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;

public class PlayerJoin {

@SubscribeEvent
public void onPlayerJoin(PlayerLoggedInEvent event) {
	PlayerProperties props = PlayerProperties.get(event.player);
	if(props != null) {
		System.out.println(props.getMana());
		props.sendToClient(new ManaValue(props.getMana()));
		if(props.isFirstJoin()) {
			props.setJoined();
		}
	}
}
}

 

The print return 100 but the bar is still at 95

Don't blame me if i always ask for your help. I just want to learn to be better :)

Link to comment
Share on other sites

Set a breakpoint in

ManaHandler

, does the client player exist when message sent from the

PlayerLoggedInEvent

handler is received?

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Yes, the player exist in ManaHandler (i put a breakpoint at the start of the onMessage method. If the player does not exist then the null check will be true and nothing will happen). So the onMessage method is running but looking at the properties that this method will get i see that the mana value is 95 (while in the event is printed as 100). So i guess that client and server handles different values, wich is not good. How can i sync them?

Don't blame me if i always ask for your help. I just want to learn to be better :)

Link to comment
Share on other sites

The function to change the mana value is called only in the ManaHandler. What i do is this

public int getMana() {
	return this.mana;
}

public void setMana(int amount) {
	this.mana = amount;
	if (this.mana > this.maxMana)
		this.mana = this.maxMana;
	if (this.mana < 0)
		this.mana = 0;
}

public void addMana(int amount) {
	this.sendToServer(new ManaValue(this.mana + amount));
}

public void removeMana(int amount) {
	this.sendToServer(new ManaValue(this.mana - amount));
}

 

Every time i want to change the value (by adding or subtracting something) i send a packet on the server with the new amount of mana, then in the ManaHandler the setMana function is called to actually set the new value. What i miss is from server to client what should i send, because if i send the same message i think it will always call the setMana function (as it will return constantly in the handler) :/

Don't blame me if i always ask for your help. I just want to learn to be better :)

Link to comment
Share on other sites

No, that's completely backwards. NEVER send values to the server - the server is the one that should be sending values to the client. Why are you controlling mana values from the client?

 

Also, it'd be simpler to send the packet from #setMana which I assume is the centralized method for actually modifying mana values.

 

Finally, your #addMana and #removeMana methods are very weird - you don't actually modify the mana value, you just send a packet?

Link to comment
Share on other sites

Yes, i send only a packet holding the new value, than in the handler the setMana function is called, setting the mana to the new value by doing this

props.setMana(message.getValue());

 

But i assume this is wrong due to you response. So i should only send in the message the amount of mana to add/subtract, then in the handler calcualte the new mana amount (with controls and stuff) and only then call the setMana function to set the mana to the new value and send a packet to the client? Basically should i do this in the PlayerProperties

public void setMana(int amount) {
	this.mana = amount;
}

public void addMana(int amount) {
	this.sendToServer(new ManaValue(amount));
}

public void removeMana(int amount) {
	this.sendToServer(new ManaValue(-1 * amount));
}

 

and this in the handler?

@Override
public IMessage onMessage(final ManaValue message, final MessageContext ctx) {

	IThreadListener thread = RPG.proxy.getListener(ctx);
	EntityPlayer player = RPG.proxy.getPlayer(ctx);
	if(player != null) {
		final PlayerProperties props = PlayerProperties.get(player);
		if(props != null) {
			thread.addScheduledTask(new Runnable() {
				@Override
				public void run() {
					int mana = props.getMana() + message.getValue();
					if (mana > props.getMaxMana())
						mana = props.getMaxMana();
					if (mana < 0)
						mana = 0;
					props.setMana(mana);
					//packet
				}
			});
		}
	}
	return null;
}

Don't blame me if i always ask for your help. I just want to learn to be better :)

Link to comment
Share on other sites

No, you shouldn't be sending ANY data at all to the server... the server should already know about needing to add or subtract mana as the server is the only place that should ever happen.

 

Basically all the client should ever do is display the current value of the mana. If you have a key press responsible for activating magic spells or whatever, the answer is not to have the client change the mana value but to send a packet to the server saying 'hey player A wants to activate magic spell B, is that okay?' and the server goes through all the logic of determining if the player can do that, which involves checking and then modifying the current mana value and ultimately sending a packet back to the client with the new current mana value.

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • They were already updated, and just to double check I even did a cleanup and fresh update from that same page. I'm quite sure drivers are not the problem here. 
    • i tried downloading the drivers but it says no AMD graphics hardware has been detected    
    • Update your AMD/ATI drivers - get the drivers from their website - do not update via system  
    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
  • Topics

×
×
  • Create New...

Important Information

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