Jump to content

How to get capacity and draw on HUD


Zemelua
 Share

Recommended Posts

Minecraft#player is the client side player, you can get it's capability. However note that capability data is not synced to the client by default.

You need to make a custom packet and use it to send over the capability data. You need to send it as follows:

  • Whenever PlayerLoggedInEvent, PlayerRespawnEvent or PlayerChangeDimensionEvent is fired.
  • Whenever the data is changed.
Link to comment
Share on other sites

 

I've read the docs and coded with reference to the existing mod code, but there are many things I don't understand. What should I put in with () of sendToClient of DepressionModPacketHandler? Also, I don't know what to do with encode, decode, and handle of PlayerMentalCapabilityMessage.

 

public class DepressionModPacketHandler {
	private static final String PROTOCOL_VERSION = "1";  //プロトコルのバージョンを宣言
	public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(  //INSTANCEに=の右側以下をぶち込む
			new ResourceLocation(DepressionMod.MOD_ID, "main"),
			() -> PROTOCOL_VERSION,  //プロトコルのバージョンをぶち込む
			PROTOCOL_VERSION::equals,  //クライアントのバージョンとPROTOCOL_VERSIONを比較?
			PROTOCOL_VERSION::equals);  //サーバーのバージョンとPROTOCOL_VERSIONを比較?

	//パケットの登録
	public static void packetRegister() {
		INSTANCE.registerMessage(
				0,  //パケットの識別子
				PlayerMentalCapabilityMessage.class,  //実際のパケットクラス
				PlayerMentalCapabilityMessage::encode,  //エンコード
				PlayerMentalCapabilityMessage::decode,  //デコード
				PlayerMentalCapabilityMessage::handle);  //メッセージ自体の処理
	}

	public static void sendToClient(Object message, PlayerEntity player) {
		INSTANCE.send(PacketDistributor.PLAYER.with(null), new PlayerMentalCapabilityMessage());
	}
}
package depressionmod.network;

import java.util.function.Supplier;

import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkEvent;

public class PlayerMentalCapabilityMessage {
	public static void encode(PlayerMentalCapabilityMessage message, PacketBuffer buf) {

	}

	public static PlayerMentalCapabilityMessage decode(PacketBuffer buf) {
		return null;

	}

	public static void handle(PlayerMentalCapabilityMessage msg, Supplier<NetworkEvent.Context> ctx) {

	}
}

 

Link to comment
Share on other sites

INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), new PlayerMentalCapabilityMessage());

When I searched for the code of the existing mod, I found the above sentence. Even if I change this ServerPlayerEntity to PlayerEntity, an error is displayed.

Link to comment
Share on other sites

public class PlayerMentalCapabilityMessage {
	private final int currentMental;

	public PlayerMentalCapabilityMessage(int currentMental) {
		this.currentMental = currentMental;
	}

	public static void encode(PlayerMentalCapabilityMessage message, PacketBuffer buf) {
		buf.writeInt(message.currentMental);
	}

	public static PlayerMentalCapabilityMessage decode(PacketBuffer buf) {
		int currentMental = buf.readInt();
		return new PlayerMentalCapabilityMessage(currentMental);

	}

	public static void handle(PlayerMentalCapabilityMessage msg, Supplier<NetworkEvent.Context> ctx) {
		//Player player = Minecraft.pla
		ctx.get().enqueueWork(() -> {
			PlayerMental playerMental = (PlayerMental) PlayerEntity.getCapability(PlayerMentalCapabilityRegistry.PLAYER_MENTAL_CAPABILITY);
		});
	}
}

 

I wrote the code with reference to the existing mod, but I still don't know what to do with the contents of the handle. I'm sorry to have taken the trouble, but if possible, I would like a sample code and its explanation.

Link to comment
Share on other sites

public class PlayerMentalCapabilityMessage {
	ClientPlayerEntity player = Minecraft.getInstance().player;
	LazyOptional<PlayerMentalInterface> playermentalinterface = player.getCapability(PlayerMentalCapabilityRegistry.PLAYER_MENTAL_CAPABILITY);
	int currentMental = ((PlayerMentalInterface) playermentalinterface).getMental();

	public PlayerMentalCapabilityMessage(int currentMental) {
		this.currentMental = currentMental;
	}

	public static void encode(PlayerMentalCapabilityMessage message, PacketBuffer buf) {
		buf.writeInt(message.currentMental);
	}

	public static PlayerMentalCapabilityMessage decode(PacketBuffer buf) {
		int currentMental = buf.readInt();
		return new PlayerMentalCapabilityMessage(currentMental);

	}

	public static void handle(PlayerMentalCapabilityMessage msg, Supplier<NetworkEvent.Context> ctx) {
		ctx.get().enqueueWork(() -> {
			
		});
	}
}

Is it like this? I'm still not sure about Context.setPacketHandled () so please tell me more.

Link to comment
Share on other sites

Handle is called when the client has received the packet, so there should be where you sync the data (what you've done in the previous post is correct), which you should get the client player and its capability to sync in here.

Also: 

56 minutes ago, poopoodice said:

You can use dist executor to make sure you are on the right side

You can get the context from the supplier (given in the second parameter of handle(...), then call Context#setPacketHandled)

Edited by poopoodice
Link to comment
Share on other sites

	public static void handle(PlayerMentalCapabilityMessage msg, Supplier<NetworkEvent.Context> ctx) {
		ctx.get().enqueueWork(() -> {

			

		});
		ctx.get().setPacketHandled(true);
	}

Is this all right?

public static void handle(MyMessage msg, Supplier<NetworkEvent.Context> ctx) {
    ctx.get().enqueueWork(() -> {
        // Work that needs to be threadsafe (most work)
        EntityPlayerMP sender = ctx.get().getSender(); // the client that sent this packet
        // do stuff
    });
    ctx.get().setPacketHandled(true);
}

This is what the forge docs say, but if I'm right, EntityPlayerMP sender = ctx.get (). GetSender (); is for sending from client to server. I don't know how to send from server to client instead.

public class MentalOverlayHander {
	public static final ResourceLocation MENTALICON = new ResourceLocation("depressionmod:textures/gui/overlay.png");

	private final Minecraft mc = Minecraft.getInstance();
	public int _currentMental;

	@SubscribeEvent
	public void onPreRenderOverlay(RenderGameOverlayEvent.Post event) {
		if (event.getType() == ElementType.ALL && mc.playerController.gameIsSurvivalOrAdventure()) {
			int scaledWidth = this.mc.getMainWindow().getScaledWidth();
			int scaledHeight = this.mc.getMainWindow().getScaledHeight();
			int left_height = ForgeIngameGui.left_height;
			int left = scaledWidth / 2 - 91;
			int top = scaledHeight - left_height;
			int level = _currentMental;

			RenderSystem.enableBlend();
			RenderSystem.enableAlphaTest();
			RenderSystem.color4f(1F, 1F, 1F, 1F);
			mc.getTextureManager().bindTexture(MENTALICON);
			for (int i = 0; i < 10; ++i) {  //iが10未満のとき繰り返す。iは繰り返しごとに1増える。
				int idx = i * 2 + 1;
				if (idx < level) {   //iがMPより小さいとき普通の薬を描画。
					//mc.getTextureManager().bindTexture(MENTALICON);
					mc.ingameGUI.blit(left, top, 0, 0, 9, 9);
				}
				else if (idx == level) {  //iがMPと同じとき半分の薬を描画。
					//mc.getTextureManager().bindTexture(MENTALICON);
					mc.ingameGUI.blit(left, top, 9, 0, 9, 9);
				}
				else if (idx > level) {  //iがMPより大きいとき黒の薬を描画。
					//mc.getTextureManager().bindTexture(MENTALICON);
					mc.ingameGUI.blit(left, top, 18, 0, 9, 9);
				}
				left += 8;  //アイコンを描画する位置を右に一つ分ずらす
				
			}
			RenderSystem.disableBlend();
			mc.getTextureManager().bindTexture(AbstractGui.GUI_ICONS_LOCATION);
			
	        }
	}
}

I want to put the currentMental value of PlayerMentalCapabilityMessage in _currentMental of MentalOverlayHander.

Link to comment
Share on other sites

That's right.

That me briefly explain the situation here:

You want to sync the mental value of the player on server to client, and you had sent a packet that contains the value, in order to use it and render images on the screen.
To get the value when rendering the screen, you are going to access the capability of the client player, therefore you need to assign the value from the packet to the client player's capability.

 

So: (make sure you do this on client using dist executor!)

MyCap cap = Minecraft.getInstance().player.getCapability(....);

cap.setMental(valuefromserver);

 

where cap is the client player' capability, and valuefromserver is the mental value got from the server player's capability that you want to assign(Sync) to the client.

 

Then you can use the same way above to access the value stored in the capability of the client player to render the images.

 

Also make sure you only send the packet when there's data change.

Edited by poopoodice
Link to comment
Share on other sites

I'm sorry, I still don't have enough knowledge and understanding about Dist Executor. I tried searching, but I created a clientproxy class and what happens when the data is changed there (in this case,
MyCap cap = Minecraft.getInstance (). player.getCapability (....);

cap.setMental (valuefromserver);
Is it correct to recognize that it executes this code?

 

nothing. I may have found the appropriate sample code. With that as a reference, I will think for a moment.

Edited by Zemelua
Link to comment
Share on other sites

public class PlayerMentalCapabilityMessage {
	ClientPlayerEntity player = Minecraft.getInstance().player;  //getInstance().playerをplayerにぶち込む
	LazyOptional<PlayerMentalInterface> playerMentalInterface = player.getCapability(PlayerMentalCapabilityRegistry.PLAYER_MENTAL_CAPABILITY);
		//playerからキャパビリティを取得してplayerMentalInterfaceにぶち込む
	int currentMental = ((PlayerMentalInterface) playerMentalInterface).getMental();  //playerMentalInterfaceからmentalの値を取得してcurrentMentalにぶち込む

	public PlayerMentalCapabilityMessage(int currentMental) {
		this.currentMental = currentMental;
	}

	public static void encode(PlayerMentalCapabilityMessage message, PacketBuffer buf) {
		buf.writeInt(message.currentMental);
	}

	public static PlayerMentalCapabilityMessage decode(PacketBuffer buf) {
		int currentMental = buf.readInt();
		return new PlayerMentalCapabilityMessage(currentMental);

	}

	public static void handle(PlayerMentalCapabilityMessage message, Supplier<NetworkEvent.Context> ctx) {
		ctx.get().enqueueWork(() -> {
			DistExecutor.safeRunWhenOn(Dist.CLIENT, () -> Handle.handleClient(message.currentMental));
		});
		ctx.get().setPacketHandled(true);
	}

	public static class Handle {
		public static DistExecutor.SafeRunnable handleClient(int currentMental) {
			return new DistExecutor.SafeRunnable() {
				@Override
				public void run() {
					LazyOptional<PlayerMentalInterface> cap = Minecraft.getInstance().player.getCapability(PlayerMentalCapabilityRegistry.PLAYER_MENTAL_CAPABILITY);
					((PlayerMentalInterface) cap).setMental(currentMental);
					//MinecraftForge.EVENT_BUS.post(new DietModEvents.UpdatePlayerSizeEvent((PlayerEntity) player));
					/*Entity player = Minecraft.getInstance().world.getEntityByID(playerEntityID);
					if (!(player instanceof PlayerEntity)) return;
					player.getCapability(ScaleProvider.SCALE_CAP).orElseThrow(IllegalArgumentException::new).setScale(scale);
					MinecraftForge.EVENT_BUS.post(new DietModEvents.UpdatePlayerSizeEvent((PlayerEntity) player));
					*/
				}
			};
		}
	}
}

I wrote the code with reference to https://forums.minecraftforge.net/topic/89515-solved1161client-works-but-server-crashes-at-packet-handler, but what role does safeRunWhenOn have? I don't really understand it, so please let me know.

Link to comment
Share on other sites

If you look into Minecraft.java, you will notice that it has an annotation:

@OnlyIn(Dist.CLIENT)

and according to forge doc:

Annotating a method or field with the @OnlyIn(Dist) annotation indicates to the loader that the respective member should be completely stripped out of the definition not on the specified physical side. Usually, these are only seen when browsing through the decompiled Minecraft code, indicating methods that the Mojang obfuscator stripped out. There is little to no reason for using this annotation directly. Only use it if you are overriding a vanilla method that already has @OnlyIn defined. In most other cases where you need to dispatch behavior based on physical sides, use DistExecutor or a check on FMLEnvironment.dist instead.

 

In other word, Minecraft.java does not exist on server side! You know what will happen when you have an non-existence reference.

Link to comment
Share on other sites

    public static void handle(PlayerMentalCapabilityMessage message, Supplier<NetworkEvent.Context> ctx) {
        ctx.get().enqueueWork(() -> {
            DistExecutor.safeRunWhenOn(Dist.CLIENT, () -> Handle.handleClient(message.currentMental));
        });
        ctx.get().setPacketHandled(true);
    }

    public static class Handle {
        public static DistExecutor.SafeRunnable handleClient(int currentMental) {
            return new DistExecutor.SafeRunnable() {
                @Override
                public void run() {
                    LazyOptional<PlayerMentalInterface> cap = Minecraft.getInstance().player.getCapability(PlayerMentalCapabilityRegistry.PLAYER_MENTAL_CAPABILITY);
                    cap.orElseThrow(IllegalArgumentException::new).setMental(currentMental);
                }
            };
        }
    }
}

Is this right?

Link to comment
Share on other sites

Thanks to everyone, I was able to achieve what I wanted to do. Thank you very much. I'm not good at English, so it's often difficult to understand even after reading the tutorial, but actually speaking in text here makes it somewhat easier to understand.

public class DepressionModPacketHandler {
	private static final String PROTOCOL_VERSION = "1";  //プロトコルのバージョンを宣言
	public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(  //INSTANCEに=の右側以下をぶち込む
			new ResourceLocation(DepressionMod.MOD_ID, "main"),
			() -> PROTOCOL_VERSION,  //プロトコルのバージョンをぶち込む
			PROTOCOL_VERSION::equals,  //クライアントのバージョンとPROTOCOL_VERSIONを比較?
			PROTOCOL_VERSION::equals);  //サーバーのバージョンとPROTOCOL_VERSIONを比較?

	//パケットの登録
	public static void packetRegister() {
		INSTANCE.registerMessage(
				0,  //パケットの識別子
				PlayerMentalCapabilityMessage.class,  //実際のパケットクラス
				PlayerMentalCapabilityMessage::encode,  //エンコード
				PlayerMentalCapabilityMessage::decode,  //デコード
				PlayerMentalCapabilityMessage::handle);  //メッセージ自体の処理
	}

	public static void sendToClient(Object message, PlayerEntity player) {

		INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), message);
	}
}
public class PlayerMentalCapabilityMessage {
	ClientPlayerEntity player = Minecraft.getInstance().player;  //getInstance().playerをplayerにぶち込む
	LazyOptional<PlayerMentalInterface> playerMentalInterface = player.getCapability(PlayerMentalCapabilityRegistry.PLAYER_MENTAL_CAPABILITY);
		//playerからキャパビリティを取得してplayerMentalInterfaceにぶち込む
	int currentMental = ((PlayerMentalInterface) playerMentalInterface).getMental();  //playerMentalInterfaceからmentalの値を取得してcurrentMentalにぶち込む

	public PlayerMentalCapabilityMessage(int currentMental) {
		this.currentMental = currentMental;
	}

	public static void encode(PlayerMentalCapabilityMessage message, PacketBuffer buf) {
		buf.writeInt(message.currentMental);
	}

	public static PlayerMentalCapabilityMessage decode(PacketBuffer buf) {
		int currentMental = buf.readInt();
		return new PlayerMentalCapabilityMessage(currentMental);

	}

	public static void handle(PlayerMentalCapabilityMessage message, Supplier<NetworkEvent.Context> ctx) {
		ctx.get().enqueueWork(() -> {
			DistExecutor.safeRunWhenOn(Dist.CLIENT, () -> Handle.handleClient(message.currentMental));
		});
		ctx.get().setPacketHandled(true);
	}

	public static class Handle {
		public static DistExecutor.SafeRunnable handleClient(int currentMental) {
			return new DistExecutor.SafeRunnable() {
				@Override
				public void run() {
					LazyOptional<PlayerMentalInterface> cap = Minecraft.getInstance().player.getCapability(PlayerMentalCapabilityRegistry.PLAYER_MENTAL_CAPABILITY);
					cap.orElseThrow(IllegalArgumentException::new).setMental(currentMental);
				}
			};
		}
	}
}
public class MentalOverlayHander {
	public static final ResourceLocation MENTALICON = new ResourceLocation("depressionmod:textures/gui/overlay.png");

	private final Minecraft mc = Minecraft.getInstance();

	@SubscribeEvent
	public void onPreRenderOverlay(RenderGameOverlayEvent.Post event) {
		if (event.getType() == ElementType.ALL && mc.playerController.gameIsSurvivalOrAdventure()) {
			int scaledWidth = this.mc.getMainWindow().getScaledWidth();
			int scaledHeight = this.mc.getMainWindow().getScaledHeight();
			int left_height = ForgeIngameGui.left_height;
			int left = scaledWidth / 2 - 91;
			int top = scaledHeight - left_height;

			LazyOptional<PlayerMentalInterface> cap = Minecraft.getInstance().player.getCapability(PlayerMentalCapabilityRegistry.PLAYER_MENTAL_CAPABILITY);
			int level =cap.orElseThrow(IllegalArgumentException::new).getMental();
			//int level = currentMental; //((PlayerMentalInterface) PlayerMentalCapabilityRegistry.PLAYER_MENTAL_CAPABILITY).getMental();

			RenderSystem.enableBlend();
			RenderSystem.enableAlphaTest();
			RenderSystem.color4f(1F, 1F, 1F, 1F);
			mc.getTextureManager().bindTexture(MENTALICON);
			for (int i = 0; i < 10; ++i) {  //iが10未満のとき繰り返す。iは繰り返しごとに1増える。
				int idx = i * 2 + 1;
				if (idx < level) {   //iがMPより小さいとき普通の薬を描画。
					//mc.getTextureManager().bindTexture(MENTALICON);
					mc.ingameGUI.blit(left, top, 0, 0, 9, 9);
				}
				else if (idx == level) {  //iがMPと同じとき半分の薬を描画。
					//mc.getTextureManager().bindTexture(MENTALICON);
					mc.ingameGUI.blit(left, top, 9, 0, 9, 9);
				}
				else if (idx > level) {  //iがMPより大きいとき黒の薬を描画。
					//mc.getTextureManager().bindTexture(MENTALICON);
					mc.ingameGUI.blit(left, top, 18, 0, 9, 9);
				}
				left += 8;  //アイコンを描画する位置を右に一つ分ずらす

			}
			RenderSystem.disableBlend();
			mc.getTextureManager().bindTexture(AbstractGui.GUI_ICONS_LOCATION);

	        }
	}
}

151265158_(31).thumb.png.fc0d935736ed9219d5730256253ddb70.png

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

 Share



×
×
  • Create New...

Important Information

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