Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix client visual desync if cooldown events are cancelled #11892

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Doc94
Copy link
Contributor

@Doc94 Doc94 commented Jan 3, 2025

This PR aims to fix a visual desync when a cooldown is cancelled, currently if you cancel the event the client still think the cooldown is running show in hotbar the effect for cooldown, them this PR add a call in the server instance of cooldown for call the onCooldownEnded behaviour for notice client about the change (still show the effect but like 1 tick... rather than the supposed time) also this make a minor change for not call super and call the same methods in the server instance where already call the super methods if need.

PD: Not sure if is intended but based in how vanilla works not sure in what cases the PlayerItemGroupCooldownEvent can run, because PlayerItemCooldownEvent is called first and then just tell now call the event again for the group.

Testing Code
I found this because i wanna use the cooldown but wanna fire in another moment rather than the use.. then i set the component and cancel the use cooldown for call later when need using the Bukkit method.

public final class TestPlugin extends JavaPlugin implements Listener {

    private NamespacedKey KEY_COOLDOWN;

    @Override
    public void onEnable() {
        this.getServer().getPluginManager().registerEvents(this, this);

        this.getServer().getCommandMap().register("fallback", new BukkitCommand("test", "cool test command", "<>", List.of("test-alias")) {
            @Override
            public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
                if (sender instanceof Player player) {
                    ItemStack itemStack = new ItemStack(Material.FISHING_ROD);
                    itemStack.setData(DataComponentTypes.USE_COOLDOWN, UseCooldown.useCooldown(2).cooldownGroup(KEY_COOLDOWN).build());
                    player.getInventory().addItem(itemStack);
                }
                return true;
            }
        });
    }

    @EventHandler
    public void onCooldown(PlayerItemGroupCooldownEvent event){
        final Player player = event.getPlayer();
        if (KEY_COOLDOWN.equals(event.getCooldownGroup())) {
            event.setCancelled(true);
        }
    }
}

Behaviour Pre-PR
https://github.com/user-attachments/assets/5df5d056-884f-4ceb-89ef-394e9331eb90

Behaviour Post-PR
https://github.com/user-attachments/assets/0f05bbaf-ffab-4b97-ae1a-19e1012f4ff2

@Doc94 Doc94 requested a review from a team as a code owner January 3, 2025 14:33
Copy link
Contributor

@lynxplay lynxplay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change has the unfortunate side effect of potentially breaking existing cooldown state on the client.
We do not have the ability to tell a client to start a cooldown in the past, so the only thing we can really do here is resend the current cooldown as a new cooldown, which will be visually different but better than completely dropping an existing cooldown and not noticable if all cooldowns are cancelled.

(untested, but maybe smth like https://pastes.dev/TIuMoOQZEY)

@Doc94
Copy link
Contributor Author

Doc94 commented Jan 4, 2025

i make the changes with the same code or the original (where i call the cooldown later) works like the same by the moment.

@electronicboy
Copy link
Member

I was pretty apprehensive around sending stuff to the client as now you introduce latency into the mix

@Doc94
Copy link
Contributor Author

Doc94 commented Jan 4, 2025

I was pretty apprehensive around sending stuff to the client as now you introduce latency into the mix

latency?

well for me is like the same than just set another cooldown, this is an alternative for avoid make a thing like change cooldown based in when need more or less time in the item for avoid the visual desync.

@kennytv kennytv added the type: bug Something doesn't work as it was intended to. label Jan 5, 2025
@lynxplay
Copy link
Contributor

lynxplay commented Jan 6, 2025

We could I guess also only send an update if there is no cool down right now? Implying that the client doesn't have a cool down? A server initialized cool down would not require a resync.

@Doc94
Copy link
Contributor Author

Doc94 commented Jan 6, 2025

We could I guess also only send an update if there is no cool down right now? Implying that the client doesn't have a cool down? A server initialized cool down would not require a resync.

you check if exists in cooldown? not sure... i make a test like

if (this.isOnCooldown(item)) {
                System.out.println("addCooldown::isOnCooldown true");
                this.onCooldownStarted(cooldownGroup, this.getCurrentCooldown(cooldownGroup));
            } else {
                System.out.println("addCooldown::isOnCooldown false");
            }

and with the same code items like goat horn not has the cooldown but throw the visual desync because not use the cooldown component use the intrument duration for handle this and sure client know this too then need resend unless wanna make a case per case for this edge cases... but i prefer send the packet in all cases becauses is like... in the end vanilla send the packet all the time for any cooldown call

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug Something doesn't work as it was intended to.
Projects
Status: Changes required
Development

Successfully merging this pull request may close these issues.

4 participants