Posted February 13, 20187 yr Hi all! I have a question about player capabilities in 1.12.2... I'm trying to use a player capability to store the last time one of my items was used by the player to effect a cooldown period that is tied to the player, not the itemstack. Basically, "You are only allowed to use any instance of this item every X minutes." The functionality is working as expected, the problem I'm having is keeping the last used time in sync with the client for display purposes. I've built a custom sync packet to update the last used value on the client, and I send the packet during PlayerLoggedInEvent, PlayerChangedDimensionEvent and PlayerEvent.Clone when isWasDeath() is true. The sync packet is also working as expected, arriving and updating the client. The problem I'm encountering looks to be related to the order that events fire surrounding player death. Here is the result of some logging: [10:34:01] [Server thread/INFO]: bmwalter68 fell from a high place [10:34:01] [main/INFO]: [CHAT] bmwalter68 fell from a high place [10:34:02] [Server thread/INFO] [transporterng]: [SERVER] new EvacuationCooldown(EntityPlayer) [10:34:02] [Server thread/INFO] [transporterng]: [SERVER] onAttachCapabilities [10:34:02] [Server thread/INFO] [transporterng]: [SERVER] onPlayerClone: oldCooldown=EvacuationCooldown{lastUse=1518536021113, player=EntityPlayerMP['bmwalter68'/139, l='Overworld', x=-237.43, y=63.00, z=-206.25]} newCooldown=EvacuationCooldown{lastUse=0, player=EntityPlayerMP['bmwalter68'/1268, l='Overworld', x=-221.50, y=64.00, z=-86.50]} [10:34:02] [Server thread/INFO] [transporterng]: [SERVER] EvacuationCooldown:setLastUse(1518536021113) player=EntityPlayerMP['bmwalter68'/1268, l='Overworld', x=-221.50, y=64.00, z=-86.50] [10:34:02] [Server thread/INFO] [transporterng]: [SERVER] EvacuationCooldown:updateClient(1518536021113) player=EntityPlayerMP['bmwalter68'/1268, l='Overworld', x=-221.50, y=64.00, z=-86.50] [10:34:02] [Server thread/INFO] [transporterng]: [SERVER] onPlayerClone: client updated [10:34:02] [main/INFO] [transporterng]: [CLIENT] EvacuationCooldown:setLastUse(1518536021113) player=EntityPlayerSP['bmwalter68'/139, l='MpServer', x=-237.43, y=63.00, z=-206.25] [10:34:02] [main/INFO] [transporterng]: [CLIENT] new EvacuationCooldown(EntityPlayer) [10:34:02] [main/INFO] [transporterng]: [CLIENT] onAttachCapabilities The event handler code for PlayerEvent.Clone: @SubscribeEvent public static void onPlayerCloneEvent(PlayerEvent.Clone event) { if (!event.isWasDeath()) { return; } IEvacuationCooldown oldCooldown = event.getOriginal().getCapability(EVACUATION_COOLDOWN, null); IEvacuationCooldown newCooldown = event.getEntityPlayer().getCapability(EVACUATION_COOLDOWN, null); if (oldCooldown != null && newCooldown != null) { newCooldown.setLastUse(oldCooldown.getLastUse()); newCooldown.updateClient(); } } It looks like the client gets updated properly and then a new capability instance is attached, effectively replacing the value just updated via the packet. Am I missing something obvious here, or is this just simply a timing issue I need to account for? Edited February 14, 20187 yr by bmwalter68 Mark as solved
February 13, 20187 yr Author Following up my own post... I have this working, though I'm not sure I'm in love with the solution. Instead of pushing updates from server to client in PlayerChangedDimensionEvent and PlayerEvent.Clone, I added another CLIENT => SERVER packet which requests a capability update and added it to the AttachCapabilitiesEvent on the client side: @SubscribeEvent public static void onAttachCapabilitiesEvent(AttachCapabilitiesEvent<Entity> event) { if (event.getObject() instanceof EntityPlayer) { EntityPlayer player = (EntityPlayer)event.getObject(); event.addCapability(new ResourceLocation(Reference.MODID, "evacuation_cooldown"), new Provider(new EvacuationCooldown(player))); if (player.getEntityWorld().isRemote) { PacketHandler.instance.sendToServer(new RequestEvacuateCooldownUpdateMessage()); } } } This handles both the player changing dimensions and updating the client after death. PlayerEvent.Clone still needs to handle copying the data on the server side, but doesn't update the client: @SubscribeEvent public static void onPlayerCloneEvent(PlayerEvent.Clone event) { if (!event.isWasDeath()) { return; } IEvacuationCooldown oldCooldown = event.getOriginal().getCapability(EVACUATION_COOLDOWN, null); IEvacuationCooldown newCooldown = event.getEntityPlayer().getCapability(EVACUATION_COOLDOWN, null); if (oldCooldown != null && newCooldown != null) { newCooldown.setLastUse(oldCooldown.getLastUse()); } } This currently works, but for some reason this seems like too many hoops to be jumping through. Does anyone have a better solution?
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.