All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.minestom.server.advancements.AdvancementTab Maven / Gradle / Ivy

There is a newer version: 7320437640
Show newest version
package net.minestom.server.advancements;

import net.minestom.server.Viewable;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.AdvancementsPacket;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * Represents a tab which can be shared between multiple players. Created using {@link AdvancementManager#createTab(String, AdvancementRoot)}.
 * 

* Each tab requires a root advancement and all succeeding advancements need to have a parent in the tab. * You can create a new advancement using {@link #createAdvancement(String, Advancement, Advancement)}. *

* Be sure to use {@link #addViewer(Player)} and {@link #removeViewer(Player)} to control which players can see the tab. * (all viewers will see the same tab, with the same amount of validated advancements etc... so shared). */ public class AdvancementTab implements Viewable { private static final Map> PLAYER_TAB_MAP = new HashMap<>(); private final Set viewers = new HashSet<>(); private final AdvancementRoot root; // Advancement -> its parent private final Map advancementMap = new HashMap<>(); // the packet used to clear the tab (used to remove it and to update an advancement) // will never change (since the root identifier is always the same) protected final AdvancementsPacket removePacket; protected AdvancementTab(@NotNull String rootIdentifier, @NotNull AdvancementRoot root) { this.root = root; cacheAdvancement(rootIdentifier, root, null); this.removePacket = new AdvancementsPacket(false, List.of(), List.of(rootIdentifier), List.of()); } /** * Gets all the tabs of a viewer. * * @param player the player to get the tabs from * @return all the advancement tabs that the player sees, can be null * if the player doesn't see anything */ @Nullable public static Set getTabs(@NotNull Player player) { return PLAYER_TAB_MAP.getOrDefault(player.getUuid(), null); } /** * Gets the root advancement of this tab. * * @return the root advancement */ @NotNull public AdvancementRoot getRoot() { return root; } /** * Creates and add an advancement into this tab. * * @param identifier the unique identifier * @param advancement the advancement to add * @param parent the parent of this advancement, it cannot be null */ public void createAdvancement(@NotNull String identifier, @NotNull Advancement advancement, @NotNull Advancement parent) { Check.stateCondition(!advancementMap.containsKey(parent), "You tried to set a parent which doesn't exist or isn't registered"); cacheAdvancement(identifier, advancement, parent); if (!getViewers().isEmpty()) { sendPacketToViewers(advancement.getUpdatePacket()); } } /** * Builds the packet which build the whole advancement tab. * * @return the packet adding this advancement tab and all its advancements */ protected @NotNull AdvancementsPacket createPacket() { List mappings = new ArrayList<>(); List progressMappings = new ArrayList<>(); for (Advancement advancement : advancementMap.keySet()) { mappings.add(advancement.toMapping()); progressMappings.add(advancement.toProgressMapping()); } return new AdvancementsPacket(false, mappings, List.of(), progressMappings); } /** * Caches an advancement. * * @param identifier the identifier of the advancement * @param advancement the advancement * @param parent the parent of this advancement, only null for the root advancement */ private void cacheAdvancement(@NotNull String identifier, @NotNull Advancement advancement, @Nullable Advancement parent) { Check.stateCondition(advancement.getTab() != null, "You tried to add an advancement already linked to a tab"); advancement.setTab(this); advancement.setIdentifier(identifier); advancement.setParent(parent); advancement.updateCriteria(); this.advancementMap.put(advancement, parent); } @Override public synchronized boolean addViewer(@NotNull Player player) { final boolean result = viewers.add(player); if (!result) return false; // Send the tab to the player player.sendPacket(createPacket()); addPlayer(player); return true; } @Override public synchronized boolean removeViewer(@NotNull Player player) { if (!isViewer(player)) { return false; } // Remove the tab if (!player.isRemoved()) player.sendPacket(removePacket); removePlayer(player); return viewers.remove(player); } @NotNull @Override public Set getViewers() { return viewers; } /** * Adds the tab to the player set. * * @param player the player */ private void addPlayer(@NotNull Player player) { Set tabs = PLAYER_TAB_MAP.computeIfAbsent(player.getUuid(), p -> new CopyOnWriteArraySet<>()); tabs.add(this); } /** * Removes the tab from the player set. * * @param player the player */ private void removePlayer(@NotNull Player player) { final UUID uuid = player.getUuid(); if (!PLAYER_TAB_MAP.containsKey(uuid)) { return; } Set tabs = PLAYER_TAB_MAP.get(uuid); tabs.remove(this); if (tabs.isEmpty()) { PLAYER_TAB_MAP.remove(uuid); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy