Novârch Posted May 8, 2020 Share Posted May 8, 2020 I'm trying to make a simple GUI that I'm eventually going to turn into a countdown timer, but the text in it doesn't update when it should, I suspect it isn't synced. Here's the code for the GUI's class: Spoiler public class GUICounter extends AbstractGui { public static final Minecraft mc = Minecraft.getInstance(); public void render() { if(mc == null) return; LazyOptional<IStand> power = mc.player.getCapability(JojoProvider.STAND, null); IStand props = power.orElse(new IStandCapability()); EntityStandBase stand = JojoLibs.getStand(props.getStandID(), mc.world); String text = "String"; if(props.getStandID() == JojoLibs.StandID.madeInHeaven) text = String.valueOf(((EntityMadeInHeaven)stand).getHeaventickr()); drawString(mc.fontRenderer, text, 4, 4, 0xFFFFFF); } } I call the render method in RenderGameOverlayEvent.Post in my main class. For more context here's the mod's git repo. Quote It's sad how much time mods spend saying "x is no longer supported on this forum. Please update to a modern version of Minecraft to receive support". Link to comment Share on other sites More sharing options...
Novârch Posted May 8, 2020 Author Share Posted May 8, 2020 Problem seems to be in how I'm getting the capability, tried printing out the same value as I should be displaying and it was just 0. Can someone explain to me why with this code the capability doesn't update? Spoiler LazyOptional<IStand> power = Minecraft.getInstance().player.getCapability(JojoProvider.STAND, null); IStand props = power.orElse(new IStandCapability()); Quote It's sad how much time mods spend saying "x is no longer supported on this forum. Please update to a modern version of Minecraft to receive support". Link to comment Share on other sites More sharing options...
Novârch Posted May 8, 2020 Author Share Posted May 8, 2020 Bump. Quote It's sad how much time mods spend saying "x is no longer supported on this forum. Please update to a modern version of Minecraft to receive support". Link to comment Share on other sites More sharing options...
Choonster Posted May 8, 2020 Share Posted May 8, 2020 Capabilities aren't synced automatically, you need to sync them yourself. It doesn't look like you're doing this. 3 hours ago, Novârch said: LazyOptional<IStand> power = Minecraft.getInstance().player.getCapability(JojoProvider.STAND, null); IStand props = power.orElse(new IStandCapability()); You probably don't want to use LazyOptional#orElse like that, if the capability isn't present you should either do nothing (if it's expected to not be present sometimes); or throw an error (if it should always be present). You generally don't want to carry on performing the action on a new instance that's not stored anywhere or used by anything. Use LazyOptional#ifPresent to run code only when the capability is present, or LazyOptional#orElseThrow to throw an error when it's not present. Quote 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 More sharing options...
Novârch Posted May 9, 2020 Author Share Posted May 9, 2020 14 hours ago, Choonster said: You probably don't want to use LazyOptional#orElse like that, if the capability isn't present you should either do nothing (if it's expected to not be present sometimes); or throw an error (if it should always be present). You generally don't want to carry on performing the action on a new instance that's not stored anywhere or used by anything. Use LazyOptional#ifPresent to run code only when the capability is present, or LazyOptional#orElseThrow to throw an error when it's not present. Thanks! I've switched to this: Spoiler LazyOptional<IStand> power = Minecraft.getInstance().player.getCapability(JojoProvider.STAND, null); IStand props = power.orElseThrow(() -> new IllegalArgumentException("Capability cannot be empty!")); 14 hours ago, Choonster said: Capabilities aren't synced automatically, you need to sync them yourself. It doesn't look like you're doing this. I've created two packets, an update packet and an update request packet, this is their code: Spoiler Update packet: public class SyncStandCapability { private INBT data; public SyncStandCapability() {} public SyncStandCapability(IStand props) { this.data = new CompoundNBT(); this.data = JojoProvider.STAND.getStorage().writeNBT(JojoProvider.STAND, props, null); } public void encode(PacketBuffer buffer) { buffer.writeCompoundTag((CompoundNBT) data); } public static SyncStandCapability decode(PacketBuffer buffer) { SyncStandCapability msg = new SyncStandCapability(); msg.data = buffer.readCompoundTag(); return msg; } public static void handle(SyncStandCapability message, Supplier<NetworkEvent.Context> ctx) { if(ctx.get().getDirection() == NetworkDirection.PLAY_TO_CLIENT) { ctx.get().enqueueWork(() -> { PlayerEntity player = StevesBizarreSurvival.PROXY.getPlayer(); assert player != null; IStand props = JojoProvider.get(player); assert props != null; JojoProvider.STAND.getStorage().readNBT(JojoProvider.STAND, props, null, message.data); }); } ctx.get().setPacketHandled(true); } } Spoiler Request update packet: public class RequestSyncStandCapability { private int entityId = 0; private INBT data; public RequestSyncStandCapability() {} public void encode(PacketBuffer buffer) {} public static RequestSyncStandCapability decode(PacketBuffer buffer) { RequestSyncStandCapability msg = new RequestSyncStandCapability(); return msg; } public static void handle(RequestSyncStandCapability message, final Supplier<NetworkEvent.Context> ctx) { if(ctx.get().getDirection() == NetworkDirection.PLAY_TO_SERVER) { ctx.get().enqueueWork(() -> { PlayerEntity player = ctx.get().getSender(); assert player != null; IStand props = JojoProvider.get(player); assert props != null; StevesBizarreSurvival.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), new SyncStandCapability(props)); }); } ctx.get().setPacketHandled(true); } } I've tried sending them before and after declaring the value of props(the capability), but it does nothing. What am I doing wrong? Quote It's sad how much time mods spend saying "x is no longer supported on this forum. Please update to a modern version of Minecraft to receive support". Link to comment Share on other sites More sharing options...
Choonster Posted May 9, 2020 Share Posted May 9, 2020 The server should be handling all of the game logic, including when to send packets to the clients. The client shouldn't be requesting a sync, it should mostly just be responsible for notifying the server of player input and displaying/rendering the data that the server tells it to. The capability handler class (IStandCapability) should send the sync packet to the client whenever its data changes, and probably when the player logs in as well. This is assuming that the player that the capability is attached to is the only one who needs this data on the client. Don't just write your capability to NBT and send that in the packet, only send the data that the client needs for display purposes. I don't know exactly why your current implementation doesn't work, but if you do things properly it should be easier to figure out what (if anything) still isn't working. On a related note, IStandCapability isn't a good class name; the I prefix is usually reserved for interfaces. If you have an interface IFoo with a single default implementation, it's common to name that class Foo. Quote 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 More sharing options...
Novârch Posted May 9, 2020 Author Share Posted May 9, 2020 1 hour ago, Choonster said: On a related note, IStandCapability isn't a good class name; the I prefix is usually reserved for interfaces. If you have an interface IFoo with a single default implementation, it's common to name that class Foo. You're right, that name was horrible, I changed it to StandCapability. 1 hour ago, Choonster said: and probably when the player logs in as well. Figured that one out, code looks like this: Spoiler @SubscribeEvent public void playerJoinWorld(EntityJoinWorldEvent event) { if(event.getEntity() instanceof PlayerEntity) { PlayerEntity player = (PlayerEntity) event.getEntity(); IStand props = JojoProvider.get(player); if(!player.world.isRemote) { INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), new SyncStandCapability(props)); } } } 1 hour ago, Choonster said: The capability handler class (IStandCapability) should send the sync packet to the client whenever its data changes I've run into a problem here , as you can see above I'm sending the update packet using this method: INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), new SyncStandCapability(props)) , but I run into some trouble using that in the class you're referring to as I can't get the player, using Minecraft#player would give me the client player, which I can't use, what PacketTarget would be most suitable for use in this class? Quote It's sad how much time mods spend saying "x is no longer supported on this forum. Please update to a modern version of Minecraft to receive support". Link to comment Share on other sites More sharing options...
Choonster Posted May 9, 2020 Share Posted May 9, 2020 1 hour ago, Novârch said: I've run into a problem here , as you can see above I'm sending the update packet using this method: INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), new SyncStandCapability(props)) , but I run into some trouble using that in the class you're referring to as I can't get the player, using Minecraft#player would give me the client player, which I can't use, what PacketTarget would be most suitable for use in this class? Store a reference to the player in the StandCapability class, then send to that player (on the server). Quote 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 More sharing options...
Recommended Posts
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.