/* * This file is part of LanternServer, licensed under the MIT License (MIT). * * Copyright (c) LanternPowered <https://www.lanternpowered.org> * Copyright (c) SpongePowered <https://www.spongepowered.org> * Copyright (c) contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the Software), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.lanternpowered.server.entity.living.player.tab; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableList; import org.lanternpowered.server.entity.living.player.LanternPlayer; import org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayOutTabListEntries; import org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayOutTabListHeaderAndFooter; import org.spongepowered.api.entity.living.player.tab.TabList; import org.spongepowered.api.entity.living.player.tab.TabListEntry; import org.spongepowered.api.text.Text; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nullable; public class LanternTabList implements TabList { private final LanternPlayer player; private final Map<UUID, LanternTabListEntry> tabListEntries = new ConcurrentHashMap<>(); private Optional<Text> header = Optional.empty(); private Optional<Text> footer = Optional.empty(); public LanternTabList(LanternPlayer player) { this.player = player; } /** * Initializes the {@link TabList} for the player and sends * the initial entries as a bulk. * * @param entries the entries */ public void init(List<LanternTabListEntry> entries) { if (entries.isEmpty()) { return; } List<MessagePlayOutTabListEntries.Entry> messageEntries = new ArrayList<>(); entries.forEach(e -> { checkArgument(e.getList() == this, "Tab list entry targets the wrong tab list!"); this.tabListEntries.put(e.getProfile().getUniqueId(), e); e.getGlobalEntry().addEntry(e); messageEntries.add(new MessagePlayOutTabListEntries.Entry.Add(e.getProfile(), e.getGameMode(), e.getDisplayName().orElse(null), e.getLatency())); }); this.player.getConnection().send(new MessagePlayOutTabListEntries(messageEntries)); if (this.footer.isPresent() || this.header.isPresent()) { this.sendHeaderAndFooterUpdate(); } } private void sendHeaderAndFooterUpdate() { this.player.getConnection().send(new MessagePlayOutTabListHeaderAndFooter(this.header.orElse(null), this.footer.orElse(null))); } public void clear() { this.tabListEntries.values().forEach(entry -> entry.getGlobalEntry().removeEntry(entry)); } @Override public LanternPlayer getPlayer() { return this.player; } @Override public Optional<Text> getHeader() { return this.header; } @Override public LanternTabList setHeader(@Nullable Text header) { this.header = Optional.ofNullable(header); this.sendHeaderAndFooterUpdate(); return this; } @Override public Optional<Text> getFooter() { return this.footer; } @Override public LanternTabList setFooter(@Nullable Text footer) { this.footer = Optional.ofNullable(footer); this.sendHeaderAndFooterUpdate(); return this; } @Override public LanternTabList setHeaderAndFooter(@Nullable Text header, @Nullable Text footer) { this.header = Optional.ofNullable(header); this.footer = Optional.ofNullable(footer); this.sendHeaderAndFooterUpdate(); return this; } @Override public Collection<TabListEntry> getEntries() { return ImmutableList.copyOf(this.tabListEntries.values()); } @Override public Optional<TabListEntry> getEntry(UUID uniqueId) { return Optional.ofNullable(this.tabListEntries.get(checkNotNull(uniqueId, "uniqueId"))); } @Override public TabList addEntry(TabListEntry entry) throws IllegalArgumentException { checkNotNull(entry, "entry"); UUID uniqueId = entry.getProfile().getUniqueId(); checkArgument(entry.getList() == this, "The tab list entries #getList() list does not match to this list."); checkArgument(!this.tabListEntries.containsKey(uniqueId), "There is already a tab list entry assigned with the unique id: " + uniqueId.toString()); this.tabListEntries.put(uniqueId, (LanternTabListEntry) entry); this.player.getConnection().send(new MessagePlayOutTabListEntries(Collections.singletonList(new MessagePlayOutTabListEntries.Entry.Add( entry.getProfile(), entry.getGameMode(), entry.getDisplayName().orElse(null), entry.getLatency())))); LanternTabListEntry entry0 = (LanternTabListEntry) entry; entry0.attached = true; entry0.getGlobalEntry().addEntry(entry0); return this; } Optional<TabListEntry> removeRawEntry(UUID uniqueId) { LanternTabListEntry entry = this.tabListEntries.remove(checkNotNull(uniqueId, "uniqueId")); if (entry != null) { entry.attached = false; return Optional.of(entry); } return Optional.empty(); } @Override public Optional<TabListEntry> removeEntry(UUID uniqueId) { final Optional<TabListEntry> entry = this.removeRawEntry(uniqueId); entry.ifPresent(entry0 -> { this.player.getConnection().send(new MessagePlayOutTabListEntries(Collections.singletonList( new MessagePlayOutTabListEntries.Entry.Remove(entry0.getProfile())))); ((LanternTabListEntry) entry0).getGlobalEntry().removeEntry((LanternTabListEntry) entry0); }); return entry; } }