Add .editorconfig & reformat

This commit is contained in:
VytskaLT committed 2022-03-16 15:18:15 +02:00
1 parent d185424979
commit 24ad7bb99f
74 files changed
+3462 -3454

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
root = true
[*]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = off
+2 -2
View File
@@ -1,3 +1,3 @@
plugins {
id("net.megavex.scoreboardlibrary.publish-conventions")
}
id("net.megavex.scoreboardlibrary.publish-conventions")
}
@@ -2,9 +2,9 @@ package net.megavex.scoreboardlibrary.api;
public final class ScoreboardLibrary {
// Concat is used to trick package relocations
public static final String NAMESPACE = "net.vytska".concat("lt.scoreboardlibrary");
// Concat is used to trick package relocations
public static final String NAMESPACE = "net.vytska".concat("lt.scoreboardlibrary");
private ScoreboardLibrary() {
}
private ScoreboardLibrary() {
}
}
@@ -16,89 +16,89 @@ import java.util.Locale;
public interface ScoreboardManager extends Closeable, HasScoreboardManager {
/**
* Gets the ScoreboardManager for a plugin
*
* @param plugin Plugin
* @return ScoreboardManager
*/
static ScoreboardManager scoreboardManager(JavaPlugin plugin) {
return ScoreboardManagerProvider.instance().scoreboardManager(plugin);
}
/**
* Gets the ScoreboardManager for a plugin
*
* @param plugin Plugin
* @return ScoreboardManager
*/
static ScoreboardManager scoreboardManager(JavaPlugin plugin) {
return ScoreboardManagerProvider.instance().scoreboardManager(plugin);
}
@Override
default @NotNull ScoreboardManager scoreboardManager() {
return this;
}
@Override
default @NotNull ScoreboardManager scoreboardManager() {
return this;
}
/**
* Gets the Plugin owner of this ScoreboardManager
*
* @return Plugin owner
*/
@NotNull Plugin plugin();
/**
* Gets the Plugin owner of this ScoreboardManager
*
* @return Plugin owner
*/
@NotNull Plugin plugin();
/**
* Creates a {@link Sidebar}
*
* @param maxLines Max sidebar lines
* @return Sidebar
*/
default @NotNull Sidebar sidebar(int maxLines) {
return sidebar(maxLines, null);
}
/**
* Creates a {@link Sidebar}
*
* @param maxLines Max sidebar lines
* @return Sidebar
*/
default @NotNull Sidebar sidebar(int maxLines) {
return sidebar(maxLines, null);
}
/**
* Creates a {@link Sidebar}
*
* @param maxLines Max sidebar lines
* @param locale Locale which will be used for translating {@link net.kyori.adventure.text.TranslatableComponent}s
* or null if the locale should depend on the player
* @return Sidebar
*/
default @NotNull Sidebar sidebar(int maxLines, @Nullable Locale locale) {
return sidebar(maxLines, ComponentTranslator.GLOBAL, locale);
}
/**
* Creates a {@link Sidebar}
*
* @param maxLines Max sidebar lines
* @param locale Locale which will be used for translating {@link net.kyori.adventure.text.TranslatableComponent}s
* or null if the locale should depend on the player
* @return Sidebar
*/
default @NotNull Sidebar sidebar(int maxLines, @Nullable Locale locale) {
return sidebar(maxLines, ComponentTranslator.GLOBAL, locale);
}
/**
* Creates a {@link Sidebar}
*
* @param maxLines Max sidebar lines
* @param componentTranslator Component translator
* @param locale Locale which will be used for translating {@link net.kyori.adventure.text.TranslatableComponent}s
* or null if the locale should depend on the player
* @return Sidebar
*/
@NotNull Sidebar sidebar(int maxLines, @NotNull ComponentTranslator componentTranslator, @Nullable Locale locale);
/**
* Creates a {@link Sidebar}
*
* @param maxLines Max sidebar lines
* @param componentTranslator Component translator
* @param locale Locale which will be used for translating {@link net.kyori.adventure.text.TranslatableComponent}s
* or null if the locale should depend on the player
* @return Sidebar
*/
@NotNull Sidebar sidebar(int maxLines, @NotNull ComponentTranslator componentTranslator, @Nullable Locale locale);
/**
* Gets the sidebars associated with this ScoreboardManager
*
* @return Sidebars
*/
@NotNull Collection<Sidebar> sidebars();
/**
* Gets the sidebars associated with this ScoreboardManager
*
* @return Sidebars
*/
@NotNull Collection<Sidebar> sidebars();
/**
* Creates a {@link TeamManager} with the global component translator
*
* @return TeamManager
*/
default @NotNull TeamManager teamManager() {
return teamManager(ComponentTranslator.GLOBAL);
}
/**
* Creates a {@link TeamManager} with the global component translator
*
* @return TeamManager
*/
default @NotNull TeamManager teamManager() {
return teamManager(ComponentTranslator.GLOBAL);
}
/**
* Creates a {@link TeamManager}
*
* @param componentTranslator Component translator
* @return TeamManager
*/
@NotNull TeamManager teamManager(@NotNull ComponentTranslator componentTranslator);
/**
* Creates a {@link TeamManager}
*
* @param componentTranslator Component translator
* @return TeamManager
*/
@NotNull TeamManager teamManager(@NotNull ComponentTranslator componentTranslator);
/**
* Gets the team managers associated with this {@link JavaPlugin}
*
* @return Team Managers
*/
Collection<TeamManager> teamManagers();
/**
* Gets the team managers associated with this {@link JavaPlugin}
*
* @return Team Managers
*/
Collection<TeamManager> teamManagers();
}
@@ -1,7 +1,7 @@
package net.megavex.scoreboardlibrary.api.interfaces;
public interface Closeable {
void close();
void close();
boolean closed();
boolean closed();
}
@@ -8,8 +8,8 @@ import java.util.Locale;
public interface ComponentTranslator {
ComponentTranslator GLOBAL = GlobalTranslator::render;
ComponentTranslator NONE = (component, locale) -> component;
ComponentTranslator GLOBAL = GlobalTranslator::render;
ComponentTranslator NONE = (component, locale) -> component;
@NotNull Component translate(@NotNull Component component, @NotNull Locale locale);
@NotNull Component translate(@NotNull Component component, @NotNull Locale locale);
}
@@ -4,5 +4,5 @@ import net.megavex.scoreboardlibrary.api.ScoreboardManager;
import org.jetbrains.annotations.NotNull;
public interface HasScoreboardManager {
@NotNull ScoreboardManager scoreboardManager();
@NotNull ScoreboardManager scoreboardManager();
}
@@ -6,21 +6,21 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collection;
public interface Players {
@NotNull Collection<Player> players();
@NotNull Collection<Player> players();
boolean addPlayer(@NotNull Player player);
boolean addPlayer(@NotNull Player player);
boolean removePlayer(@NotNull Player player);
boolean removePlayer(@NotNull Player player);
default void addPlayers(@NotNull Collection<Player> players) {
for (Player player : players) {
addPlayer(player);
}
default void addPlayers(@NotNull Collection<Player> players) {
for (Player player : players) {
addPlayer(player);
}
}
default void removePlayers(@NotNull Collection<Player> players) {
for (Player player : players) {
removePlayer(player);
}
default void removePlayers(@NotNull Collection<Player> players) {
for (Player player : players) {
removePlayer(player);
}
}
}
@@ -17,162 +17,162 @@ import static net.kyori.adventure.text.Component.empty;
public class AbstractSidebar implements HasScoreboardManager, Closeable {
private static final SidebarLine emptyLine = SidebarLine.staticLine(empty());
protected final Sidebar sidebar;
private SidebarLine[] lines;
private static final SidebarLine emptyLine = SidebarLine.staticLine(empty());
protected final Sidebar sidebar;
private SidebarLine[] lines;
public AbstractSidebar(@NotNull Sidebar sidebar) {
this.sidebar = sidebar;
this.lines = new SidebarLine[sidebar.maxLines()];
public AbstractSidebar(@NotNull Sidebar sidebar) {
this.sidebar = sidebar;
this.lines = new SidebarLine[sidebar.maxLines()];
}
public final @NotNull Sidebar sidebar() {
return sidebar;
}
protected void onClosed() {
}
/**
* Updates a line
*
* @param lineSupplier Line to update
*/
protected final void updateLine(@NotNull SidebarLine lineSupplier) {
checkClosed();
Preconditions.checkNotNull(lineSupplier);
Preconditions.checkArgument(!lineSupplier.lineStatic());
sidebar.line(lineSupplier.line(), lineSupplier.computeValue());
}
/**
* Unregisters a line
*
* @param line Line to unregister
* @return Unregistered line
*/
protected final @Nullable SidebarLine unregisterLine(int line) {
SidebarLine lineSupplier = lines[line];
if (lineSupplier == null) {
return null;
}
public final @NotNull Sidebar sidebar() {
return sidebar;
lines[line] = null;
sidebar.line(line, null);
return lineSupplier;
}
/**
* Registers a static line for this AbstractSidebar
*
* @param line Line to register
* @param value Static value
*/
protected final @NotNull SidebarLine registerStaticLine(int line, @NotNull Component value) {
SidebarLine sidebarLine = SidebarLine.staticLine(value);
registerLine(line, sidebarLine);
return sidebarLine;
}
/**
* Registers a line for this AbstractSidebar
*
* @param line Line to register
* @param supplier Supplier
* @return The created LineSupplier
*/
protected final SidebarLine registerLine(int line, @NotNull Supplier<Component> supplier) {
checkClosed();
Preconditions.checkNotNull(supplier);
return registerLine(line, new SidebarLine() {
@Override
public boolean lineStatic() {
return false;
}
@Override
public int line() {
return line;
}
@Override
public Component computeValue() {
return supplier.get();
}
});
}
/**
* Registers a line for this AbstractSidebar
*
* @param line Line to register
* @param supplier Supplier
* @return The same LineSupplier for convenience
*/
protected final <S extends SidebarLine> S registerLine(int line, @NotNull S supplier) {
checkClosed();
Objects.requireNonNull(supplier);
SidebarUtilities.checkLineBounds(line);
if (lines[line] != null) {
throw new IllegalStateException("Line " + line + " is already registered");
}
protected void onClosed() {
lines[line] = Objects.requireNonNull(supplier, "LineSupplier cannot be null");
sidebar.line(line, supplier.computeValue());
return supplier;
}
/**
* Registers an empty line for this AbstractSidebar
*
* @param line Line to register
*/
protected final void registerEmptyLine(int line) {
registerLine(line, emptyLine);
}
/**
* Gets the supplier for a line
*
* @param line Line
* @return Supplier of line
*/
@Nullable
protected SidebarLine getLine(int line) {
checkClosed();
return lines[line];
}
@Override
public final @NotNull ScoreboardManager scoreboardManager() {
return sidebar.scoreboardManager();
}
protected final void checkClosed() {
Preconditions.checkState(!sidebar.closed(), "Sidebar is closed");
}
/**
* Closes this AbstractSidebar
*/
@Override
public final void close() {
if (!sidebar.closed()) {
sidebar.close();
lines = null;
onClosed();
}
}
/**
* Updates a line
*
* @param lineSupplier Line to update
*/
protected final void updateLine(@NotNull SidebarLine lineSupplier) {
checkClosed();
Preconditions.checkNotNull(lineSupplier);
Preconditions.checkArgument(!lineSupplier.lineStatic());
sidebar.line(lineSupplier.line(), lineSupplier.computeValue());
}
@Override
public boolean closed() {
return sidebar.closed();
}
/**
* Unregisters a line
*
* @param line Line to unregister
* @return Unregistered line
*/
protected final @Nullable SidebarLine unregisterLine(int line) {
SidebarLine lineSupplier = lines[line];
if (lineSupplier == null) {
return null;
}
lines[line] = null;
sidebar.line(line, null);
return lineSupplier;
}
/**
* Registers a static line for this AbstractSidebar
*
* @param line Line to register
* @param value Static value
*/
protected final @NotNull SidebarLine registerStaticLine(int line, @NotNull Component value) {
SidebarLine sidebarLine = SidebarLine.staticLine(value);
registerLine(line, sidebarLine);
return sidebarLine;
}
/**
* Registers a line for this AbstractSidebar
*
* @param line Line to register
* @param supplier Supplier
* @return The created LineSupplier
*/
protected final SidebarLine registerLine(int line, @NotNull Supplier<Component> supplier) {
checkClosed();
Preconditions.checkNotNull(supplier);
return registerLine(line, new SidebarLine() {
@Override
public boolean lineStatic() {
return false;
}
@Override
public int line() {
return line;
}
@Override
public Component computeValue() {
return supplier.get();
}
});
}
/**
* Registers a line for this AbstractSidebar
*
* @param line Line to register
* @param supplier Supplier
* @return The same LineSupplier for convenience
*/
protected final <S extends SidebarLine> S registerLine(int line, @NotNull S supplier) {
checkClosed();
Objects.requireNonNull(supplier);
SidebarUtilities.checkLineBounds(line);
if (lines[line] != null) {
throw new IllegalStateException("Line " + line + " is already registered");
}
lines[line] = Objects.requireNonNull(supplier, "LineSupplier cannot be null");
sidebar.line(line, supplier.computeValue());
return supplier;
}
/**
* Registers an empty line for this AbstractSidebar
*
* @param line Line to register
*/
protected final void registerEmptyLine(int line) {
registerLine(line, emptyLine);
}
/**
* Gets the supplier for a line
*
* @param line Line
* @return Supplier of line
*/
@Nullable
protected SidebarLine getLine(int line) {
checkClosed();
return lines[line];
}
@Override
public final @NotNull ScoreboardManager scoreboardManager() {
return sidebar.scoreboardManager();
}
protected final void checkClosed() {
Preconditions.checkState(!sidebar.closed(), "Sidebar is closed");
}
/**
* Closes this AbstractSidebar
*/
@Override
public final void close() {
if (!sidebar.closed()) {
sidebar.close();
lines = null;
onClosed();
}
}
@Override
public boolean closed() {
return sidebar.closed();
}
@Override
public int hashCode() {
return sidebar.hashCode();
}
@Override
public int hashCode() {
return sidebar.hashCode();
}
}
@@ -15,78 +15,78 @@ import java.util.Locale;
*/
public interface Sidebar extends HasScoreboardManager, Closeable, Players {
// Constants
// Constants
byte MAX_LINES = 15;
byte MAX_LINES = 15;
// Main
// Main
/**
* Gets the {@link ComponentTranslator} of this Sidebar
*
* @return Component translator
*/
@NotNull ComponentTranslator componentTranslator();
/**
* Gets the {@link ComponentTranslator} of this Sidebar
*
* @return Component translator
*/
@NotNull ComponentTranslator componentTranslator();
/**
* Gets the max amount of lines this sidebar can have
*
* @return Max line amount
*/
byte maxLines();
/**
* Gets the max amount of lines this sidebar can have
*
* @return Max line amount
*/
byte maxLines();
/**
* Gets the {@link Locale} which is used to translate {@link net.kyori.adventure.text.TranslatableComponent}s
*
* @return Locale
*/
@Nullable Locale locale();
/**
* Gets the {@link Locale} which is used to translate {@link net.kyori.adventure.text.TranslatableComponent}s
*
* @return Locale
*/
@Nullable Locale locale();
// Visibility
// Visibility
/**
* Returns the visibility of this Sidebar
*
* @return Visibility
*/
boolean visible();
/**
* Returns the visibility of this Sidebar
*
* @return Visibility
*/
boolean visible();
/**
* Changes the visibility of this Sidebar
*
* @param visible New visibility of this sidebar
*/
void visible(boolean visible);
/**
* Changes the visibility of this Sidebar
*
* @param visible New visibility of this sidebar
*/
void visible(boolean visible);
// Lines
// Lines
/**
* Sets a line's value
*
* @param line Line
* @param value Value
*/
void line(int line, Component value);
/**
* Sets a line's value
*
* @param line Line
* @param value Value
*/
void line(int line, Component value);
/**
* Gets a line's value
*
* @param line Line
* @return Value of line
*/
@Nullable Component line(int line);
/**
* Gets a line's value
*
* @param line Line
* @return Value of line
*/
@Nullable Component line(int line);
/**
* Returns the current title
*
* @return Title
*/
@NotNull Component title();
/**
* Returns the current title
*
* @return Title
*/
@NotNull Component title();
/**
* Sets the title
*
* @param title Title
*/
void title(@NotNull Component title);
/**
* Sets the title
*
* @param title Title
*/
void title(@NotNull Component title);
}
@@ -2,23 +2,23 @@ package net.megavex.scoreboardlibrary.api.sidebar.line;
public abstract class AbstractSidebarLine implements SidebarLine {
protected final byte line;
protected final byte line;
public AbstractSidebarLine(int line) {
this((byte) line);
}
public AbstractSidebarLine(int line) {
this((byte) line);
}
public AbstractSidebarLine(byte line) {
this.line = line;
}
public AbstractSidebarLine(byte line) {
this.line = line;
}
@Override
public final boolean lineStatic() {
return false;
}
@Override
public final boolean lineStatic() {
return false;
}
@Override
public final int line() {
return line;
}
@Override
public final int line() {
return line;
}
}
@@ -5,23 +5,23 @@ import org.jetbrains.annotations.NotNull;
public interface SidebarLine {
static @NotNull SidebarLine staticLine(@NotNull Component component) {
return new StaticLine(component);
}
static @NotNull SidebarLine staticLine(@NotNull Component component) {
return new StaticLine(component);
}
default boolean lineStatic() {
return true;
}
default boolean lineStatic() {
return true;
}
/**
* Gets the line index
*
* @return Line index
* @throws UnsupportedOperationException If this is a static line
*/
default int line() {
throw new UnsupportedOperationException();
}
/**
* Gets the line index
*
* @return Line index
* @throws UnsupportedOperationException If this is a static line
*/
default int line() {
throw new UnsupportedOperationException();
}
Component computeValue();
Component computeValue();
}
@@ -6,12 +6,12 @@ import java.util.Objects;
record StaticLine(Component value) implements SidebarLine {
StaticLine(Component value) {
this.value = Objects.requireNonNull(value, "value");
}
StaticLine(Component value) {
this.value = Objects.requireNonNull(value, "value");
}
@Override
public Component computeValue() {
return value;
}
@Override
public Component computeValue() {
return value;
}
}
@@ -9,36 +9,36 @@ import org.jetbrains.annotations.NotNull;
*/
public interface ScoreboardTeam extends Closeable {
/**
* Gets the TeamManager of this Team
*
* @return TeamManager
*/
@NotNull TeamManager teamManager();
/**
* Gets the TeamManager of this Team
*
* @return TeamManager
*/
@NotNull TeamManager teamManager();
@NotNull TeamInfo globalInfo();
@NotNull TeamInfo globalInfo();
/**
* Gets the name of this team
*
* @return Name
*/
@NotNull String name();
/**
* Gets the name of this team
*
* @return Name
*/
@NotNull String name();
/**
* Gets the {@link TeamInfo} of a Player
*
* @param player Player
* @return {@link TeamInfo} of Player
*/
@NotNull TeamInfo teamInfo(Player player);
/**
* Gets the {@link TeamInfo} of a Player
*
* @param player Player
* @return {@link TeamInfo} of Player
*/
@NotNull TeamInfo teamInfo(Player player);
/**
* Changes a Player's visible {@link TeamInfo}
*
* @param player Player
* @param teamInfo New {@link TeamInfo} of Player
* @return new team info of player.
*/
@NotNull TeamInfo teamInfo(Player player, TeamInfo teamInfo);
/**
* Changes a Player's visible {@link TeamInfo}
*
* @param player Player
* @param teamInfo New {@link TeamInfo} of Player
* @return new team info of player.
*/
@NotNull TeamInfo teamInfo(Player player, TeamInfo teamInfo);
}
@@ -12,176 +12,176 @@ import java.util.Collection;
public interface TeamInfo {
/**
* Creates an empty {@link TeamInfo}
*
* @return TeamInfo
*/
static @NotNull TeamInfo teamInfo() {
return teamInfo(null);
}
/**
* Creates an empty {@link TeamInfo}
*
* @return TeamInfo
*/
static @NotNull TeamInfo teamInfo() {
return teamInfo(null);
}
/**
* Creates a {@link TeamInfo} with specified entries
*
* @param entries Entries the TeamInfo should have
* @return TeamInfo
*/
static @NotNull TeamInfo teamInfo(@Nullable Collection<String> entries) {
return ScoreboardManagerProvider.instance().teamInfo(entries);
}
/**
* Creates a {@link TeamInfo} with specified entries
*
* @param entries Entries the TeamInfo should have
* @return TeamInfo
*/
static @NotNull TeamInfo teamInfo(@Nullable Collection<String> entries) {
return ScoreboardManagerProvider.instance().teamInfo(entries);
}
// Main
// Main
/**
* Gets the Team which is assigned to this TeamInfo
*
* @return Assigned Team
* @throws IllegalStateException If not assigned
*/
ScoreboardTeam team();
/**
* Gets the Team which is assigned to this TeamInfo
*
* @return Assigned Team
* @throws IllegalStateException If not assigned
*/
ScoreboardTeam team();
/**
* Returns whether this TeamInfo is assigned to a Team
*
* @return If assigned
*/
boolean isAssigned();
/**
* Returns whether this TeamInfo is assigned to a Team
*
* @return If assigned
*/
boolean isAssigned();
/**
* Unassigns TeamInfo info from the currently assigned Team
*/
void unassign();
/**
* Unassigns TeamInfo info from the currently assigned Team
*/
void unassign();
/**
* Returns the name of the assigned Team
*
* @return Name of Team
*/
@Nullable
default String name() {
return team() == null ? null : team().name();
}
/**
* Returns the name of the assigned Team
*
* @return Name of Team
*/
@Nullable
default String name() {
return team() == null ? null : team().name();
}
// Entries
// Entries
@NotNull Collection<String> entries();
@NotNull Collection<String> entries();
/**
* Adds an entry
*
* @param entry Entry to add
* @return Whether the entry was added
*/
boolean addEntry(@NotNull String entry);
/**
* Adds an entry
*
* @param entry Entry to add
* @return Whether the entry was added
*/
boolean addEntry(@NotNull String entry);
/**
* Removes an entry
*
* @param entry Entry to remove
* @return Whether the entry was removed
*/
boolean removeEntry(@NotNull String entry);
/**
* Removes an entry
*
* @param entry Entry to remove
* @return Whether the entry was removed
*/
boolean removeEntry(@NotNull String entry);
// Properties
// Properties
@NotNull Component displayName();
@NotNull Component displayName();
/**
* Sets the display name
*
* @param displayName Display name
*/
void displayName(@NotNull Component displayName);
/**
* Sets the display name
*
* @param displayName Display name
*/
void displayName(@NotNull Component displayName);
@NotNull Component prefix();
@NotNull Component prefix();
/**
* Sets the prefix
*
* @param prefix Prefix
*/
void prefix(@NotNull Component prefix);
/**
* Sets the prefix
*
* @param prefix Prefix
*/
void prefix(@NotNull Component prefix);
@NotNull Component suffix();
@NotNull Component suffix();
/**
* Sets the suffix
*
* @param suffix Suffix
*/
void suffix(@NotNull Component suffix);
/**
* Sets the suffix
*
* @param suffix Suffix
*/
void suffix(@NotNull Component suffix);
default boolean friendlyFire() {
return false;
}
default boolean friendlyFire() {
return false;
}
/**
* Sets whether friendly fire is allowed
*
* @param allowFriendlyFire whether friendly fire is allowed
*/
void friendlyFire(boolean allowFriendlyFire);
/**
* Sets whether friendly fire is allowed
*
* @param allowFriendlyFire whether friendly fire is allowed
*/
void friendlyFire(boolean allowFriendlyFire);
default boolean canSeeFriendlyInvisibles() {
return false;
}
default boolean canSeeFriendlyInvisibles() {
return false;
}
/**
* Sets whether players can see friendly invisibles
*
* @param canSeeFriendlyInvisibles whether players can see friendly invisibles
*/
void canSeeFriendlyInvisibles(boolean canSeeFriendlyInvisibles);
/**
* Sets whether players can see friendly invisibles
*
* @param canSeeFriendlyInvisibles whether players can see friendly invisibles
*/
void canSeeFriendlyInvisibles(boolean canSeeFriendlyInvisibles);
default @NotNull NameTagVisibility nameTagVisibility() {
return NameTagVisibility.ALWAYS;
}
default @NotNull NameTagVisibility nameTagVisibility() {
return NameTagVisibility.ALWAYS;
}
/**
* Sets the {@link NameTagVisibility}
*
* @param nameTagVisibility Name tag visibility rule
*/
void nameTagVisibility(@NotNull NameTagVisibility nameTagVisibility);
/**
* Sets the {@link NameTagVisibility}
*
* @param nameTagVisibility Name tag visibility rule
*/
void nameTagVisibility(@NotNull NameTagVisibility nameTagVisibility);
/**
* Gets the {@link CollisionRule}. This will be ignored on 1.8 since in this version teams don't support this
*
* @return Collision rule
*/
default @NotNull CollisionRule collisionRule() {
return CollisionRule.ALWAYS;
}
/**
* Gets the {@link CollisionRule}. This will be ignored on 1.8 since in this version teams don't support this
*
* @return Collision rule
*/
default @NotNull CollisionRule collisionRule() {
return CollisionRule.ALWAYS;
}
/**
* Sets the {@link CollisionRule}
*
* @param collisionRule Collision rule
*/
void collisionRule(@NotNull CollisionRule collisionRule);
/**
* Sets the {@link CollisionRule}
*
* @param collisionRule Collision rule
*/
void collisionRule(@NotNull CollisionRule collisionRule);
/**
* Gets the {@link NamedTextColor} of the player. This will be ignored on 1.8 since in this version teams don't support this
*
* @return Color
*/
@Nullable
default NamedTextColor playerColor() {
return null;
}
/**
* Gets the {@link NamedTextColor} of the player. This will be ignored on 1.8 since in this version teams don't support this
*
* @return Color
*/
@Nullable
default NamedTextColor playerColor() {
return null;
}
/**
* Sets the {@link NamedTextColor}
*
* @param color Color
*/
void playerColor(@Nullable NamedTextColor color);
/**
* Sets the {@link NamedTextColor}
*
* @param color Color
*/
void playerColor(@Nullable NamedTextColor color);
// Options
// Options
default void unpackOptions(int options) {
friendlyFire((options & 1) > 0);
canSeeFriendlyInvisibles((options & 2) > 0);
}
default void unpackOptions(int options) {
friendlyFire((options & 1) > 0);
canSeeFriendlyInvisibles((options & 2) > 0);
}
}
@@ -14,78 +14,78 @@ import java.util.Objects;
*/
public class TeamInfoBuilder {
private Component displayName, prefix, suffix;
private boolean allowFriendlyFire, canSeeFriendlyInvisibles;
private NameTagVisibility nameTagVisibility;
private CollisionRule collisionRule;
private NamedTextColor playerColor;
private Collection<String> entries;
private Component displayName, prefix, suffix;
private boolean allowFriendlyFire, canSeeFriendlyInvisibles;
private NameTagVisibility nameTagVisibility;
private CollisionRule collisionRule;
private NamedTextColor playerColor;
private Collection<String> entries;
public TeamInfo build() {
TeamInfo teamInfo = ScoreboardManagerProvider.instance().teamInfo(entries);
teamInfo.displayName(displayName);
teamInfo.prefix(prefix);
teamInfo.suffix(suffix);
teamInfo.friendlyFire(allowFriendlyFire);
teamInfo.canSeeFriendlyInvisibles(canSeeFriendlyInvisibles);
teamInfo.nameTagVisibility(nameTagVisibility == null ? NameTagVisibility.ALWAYS : nameTagVisibility);
teamInfo.collisionRule(collisionRule == null ? CollisionRule.ALWAYS : collisionRule);
teamInfo.playerColor(playerColor);
return teamInfo;
}
public TeamInfo build() {
TeamInfo teamInfo = ScoreboardManagerProvider.instance().teamInfo(entries);
teamInfo.displayName(displayName);
teamInfo.prefix(prefix);
teamInfo.suffix(suffix);
teamInfo.friendlyFire(allowFriendlyFire);
teamInfo.canSeeFriendlyInvisibles(canSeeFriendlyInvisibles);
teamInfo.nameTagVisibility(nameTagVisibility == null ? NameTagVisibility.ALWAYS : nameTagVisibility);
teamInfo.collisionRule(collisionRule == null ? CollisionRule.ALWAYS : collisionRule);
teamInfo.playerColor(playerColor);
return teamInfo;
}
public TeamInfoBuilder entries(Collection<String> entries) {
this.entries = entries;
return this;
}
public TeamInfoBuilder entries(Collection<String> entries) {
this.entries = entries;
return this;
}
public TeamInfoBuilder addEntry(String entry) {
Objects.requireNonNull(entries).add(entry);
return this;
}
public TeamInfoBuilder addEntry(String entry) {
Objects.requireNonNull(entries).add(entry);
return this;
}
public TeamInfoBuilder removeEntry(String entry) {
Objects.requireNonNull(entries).remove(entry);
return this;
}
public TeamInfoBuilder removeEntry(String entry) {
Objects.requireNonNull(entries).remove(entry);
return this;
}
public TeamInfoBuilder displayName(Component displayName) {
this.displayName = displayName;
return this;
}
public TeamInfoBuilder displayName(Component displayName) {
this.displayName = displayName;
return this;
}
public TeamInfoBuilder prefix(Component prefix) {
this.prefix = prefix;
return this;
}
public TeamInfoBuilder prefix(Component prefix) {
this.prefix = prefix;
return this;
}
public TeamInfoBuilder suffix(Component suffix) {
this.suffix = suffix;
return this;
}
public TeamInfoBuilder suffix(Component suffix) {
this.suffix = suffix;
return this;
}
public TeamInfoBuilder allowFriendlyFire(boolean allowFriendlyFire) {
this.allowFriendlyFire = allowFriendlyFire;
return this;
}
public TeamInfoBuilder allowFriendlyFire(boolean allowFriendlyFire) {
this.allowFriendlyFire = allowFriendlyFire;
return this;
}
public TeamInfoBuilder canSeeFriendlyInvisibles(boolean canSeeFriendlyInvisibles) {
this.canSeeFriendlyInvisibles = canSeeFriendlyInvisibles;
return this;
}
public TeamInfoBuilder canSeeFriendlyInvisibles(boolean canSeeFriendlyInvisibles) {
this.canSeeFriendlyInvisibles = canSeeFriendlyInvisibles;
return this;
}
public TeamInfoBuilder nameTagVisibility(NameTagVisibility nameTagVisibility) {
this.nameTagVisibility = nameTagVisibility;
return this;
}
public TeamInfoBuilder nameTagVisibility(NameTagVisibility nameTagVisibility) {
this.nameTagVisibility = nameTagVisibility;
return this;
}
public TeamInfoBuilder collisionRule(CollisionRule collisionRule) {
this.collisionRule = collisionRule;
return this;
}
public TeamInfoBuilder collisionRule(CollisionRule collisionRule) {
this.collisionRule = collisionRule;
return this;
}
public TeamInfoBuilder playerColor(NamedTextColor playerColor) {
this.playerColor = playerColor;
return this;
}
public TeamInfoBuilder playerColor(NamedTextColor playerColor) {
this.playerColor = playerColor;
return this;
}
}
@@ -17,103 +17,103 @@ import java.util.function.Function;
*/
public interface TeamManager extends Closeable, HasScoreboardManager, Players {
@NotNull ComponentTranslator componentTranslator();
@NotNull ComponentTranslator componentTranslator();
// Teams
// Teams
/**
* Returns an unmodifiable set of teams in this team manager
*
* @return Teams
*/
@NotNull Collection<ScoreboardTeam> teams();
/**
* Returns an unmodifiable set of teams in this team manager
*
* @return Teams
*/
@NotNull Collection<ScoreboardTeam> teams();
/**
* Returns team based on its name
*
* @param name Name of team
* @return Team with this name
*/
@Nullable ScoreboardTeam team(@NotNull String name);
/**
* Returns team based on its name
*
* @param name Name of team
* @return Team with this name
*/
@Nullable ScoreboardTeam team(@NotNull String name);
/**
* Returns whether a team by the name exists
*
* @param name Name of team
* @return Whether a team by the name exists
*/
boolean teamExists(@NotNull String name);
/**
* Returns whether a team by the name exists
*
* @param name Name of team
* @return Whether a team by the name exists
*/
boolean teamExists(@NotNull String name);
/**
* Returns team based on its name. If it doesn't already exist, creates it
*
* @param name Name of team.
* @return Team with this name, null if not found
*/
default @NotNull ScoreboardTeam createIfAbsent(@NotNull String name) {
return createIfAbsent(name, null);
}
/**
* Returns team based on its name. If it doesn't already exist, creates it
*
* @param name Name of team.
* @return Team with this name, null if not found
*/
default @NotNull ScoreboardTeam createIfAbsent(@NotNull String name) {
return createIfAbsent(name, null);
}
/**
* Returns a team based on its name. If it doesn't already exist, it creates it
*
* @param name Name of team
* @param teamInfoFunction A function that provides team info's for each player
* @return Team with this name
*/
@NotNull ScoreboardTeam createIfAbsent(@NotNull String name, @Nullable BiFunction<Player, ScoreboardTeam, TeamInfo> teamInfoFunction);
/**
* Returns a team based on its name. If it doesn't already exist, it creates it
*
* @param name Name of team
* @param teamInfoFunction A function that provides team info's for each player
* @return Team with this name
*/
@NotNull ScoreboardTeam createIfAbsent(@NotNull String name, @Nullable BiFunction<Player, ScoreboardTeam, TeamInfo> teamInfoFunction);
// Players
// Players
/**
* Adds a player to this TeamManager
*
* @param player Player to add to TeamManager
* @return Whether the player was added
*/
default boolean addPlayer(@NotNull Player player) {
return addPlayer(player, null);
}
/**
* Adds a player to this TeamManager
*
* @param player Player to add to TeamManager
* @return Whether the player was added
*/
default boolean addPlayer(@NotNull Player player) {
return addPlayer(player, null);
}
/**
* Adds a player to this TeamManager
*
* @param player Player to add
* @param teamInfoFunction A function that returns the {@link TeamInfo} that the player should have
* @return Whether the player was added
*/
boolean addPlayer(@NotNull Player player, @Nullable Function<ScoreboardTeam, TeamInfo> teamInfoFunction);
/**
* Adds a player to this TeamManager
*
* @param player Player to add
* @param teamInfoFunction A function that returns the {@link TeamInfo} that the player should have
* @return Whether the player was added
*/
boolean addPlayer(@NotNull Player player, @Nullable Function<ScoreboardTeam, TeamInfo> teamInfoFunction);
/**
* Adds a player to this TeamManager
*
* @param players Players to add
*/
default void addPlayers(@NotNull Collection<Player> players) {
addPlayers(players, null);
}
/**
* Adds a player to this TeamManager
*
* @param players Players to add
*/
default void addPlayers(@NotNull Collection<Player> players) {
addPlayers(players, null);
}
/**
* Adds a list of players to this TeamManager
*
* @param players Players to add
* @param teamInfoFunction A function that returns the {@link TeamInfo} that the player should have
* @return A collection of players that have been added
*/
@NotNull Collection<Player> addPlayers(@NotNull Collection<Player> players, @Nullable Function<ScoreboardTeam, TeamInfo> teamInfoFunction);
/**
* Adds a list of players to this TeamManager
*
* @param players Players to add
* @param teamInfoFunction A function that returns the {@link TeamInfo} that the player should have
* @return A collection of players that have been added
*/
@NotNull Collection<Player> addPlayers(@NotNull Collection<Player> players, @Nullable Function<ScoreboardTeam, TeamInfo> teamInfoFunction);
/**
* Removes a player from this TeamManager
*
* @param player Player to remove
* @return If the player was removed
*/
boolean removePlayer(@NotNull Player player);
/**
* Removes a player from this TeamManager
*
* @param player Player to remove
* @return If the player was removed
*/
boolean removePlayer(@NotNull Player player);
/**
* Removes a list of players from this TeamManager
*
* @param players Player to remove
*/
void removePlayers(@NotNull Collection<Player> players);
/**
* Removes a list of players from this TeamManager
*
* @param players Player to remove
*/
void removePlayers(@NotNull Collection<Player> players);
}
@@ -3,30 +3,30 @@ package net.megavex.scoreboardlibrary.api.team.enums;
import org.jetbrains.annotations.ApiStatus;
public enum CollisionRule {
ALWAYS("always"),
NEVER("never"),
PUSH_OTHER_TEAMS("pushOtherTeams"),
PUSH_OWN_TEAM("pushOwnTeam");
ALWAYS("always"),
NEVER("never"),
PUSH_OTHER_TEAMS("pushOtherTeams"),
PUSH_OWN_TEAM("pushOwnTeam");
private static final CollisionRule[] values = values();
private final String key;
private static final CollisionRule[] values = values();
private final String key;
CollisionRule(String key) {
this.key = key;
}
CollisionRule(String key) {
this.key = key;
}
@ApiStatus.Internal
public static CollisionRule of(byte id) {
return values[id];
}
@ApiStatus.Internal
public static CollisionRule of(byte id) {
return values[id];
}
@ApiStatus.Internal
public byte id() {
return (byte) ordinal();
}
@ApiStatus.Internal
public byte id() {
return (byte) ordinal();
}
@ApiStatus.Internal
public String key() {
return this.key;
}
@ApiStatus.Internal
public String key() {
return this.key;
}
}
@@ -3,30 +3,30 @@ package net.megavex.scoreboardlibrary.api.team.enums;
import org.jetbrains.annotations.ApiStatus;
public enum NameTagVisibility {
ALWAYS("always"),
NEVER("never"),
HIDE_FOR_OTHER_TEAMS("hideForOtherTeams"),
HIDE_FOR_OWN_TEAM("hideForOwnTeam");
ALWAYS("always"),
NEVER("never"),
HIDE_FOR_OTHER_TEAMS("hideForOtherTeams"),
HIDE_FOR_OWN_TEAM("hideForOwnTeam");
private static final NameTagVisibility[] values = values();
private final String key;
private static final NameTagVisibility[] values = values();
private final String key;
NameTagVisibility(String key) {
this.key = key;
}
NameTagVisibility(String key) {
this.key = key;
}
@ApiStatus.Internal
public static NameTagVisibility of(byte id) {
return values[id];
}
@ApiStatus.Internal
public static NameTagVisibility of(byte id) {
return values[id];
}
@ApiStatus.Internal
public byte id() {
return (byte) ordinal();
}
@ApiStatus.Internal
public byte id() {
return (byte) ordinal();
}
@ApiStatus.Internal
public String key() {
return this.key;
}
@ApiStatus.Internal
public String key() {
return this.key;
}
}
@@ -6,12 +6,12 @@ import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public final class SidebarUtilities {
private SidebarUtilities() {
}
private SidebarUtilities() {
}
public static void checkLineBounds(int line) {
if (line > Sidebar.MAX_LINES || line < 0) {
throw new IndexOutOfBoundsException("Invalid line: " + line);
}
public static void checkLineBounds(int line) {
if (line > Sidebar.MAX_LINES || line < 0) {
throw new IndexOutOfBoundsException("Invalid line: " + line);
}
}
}
@@ -6,25 +6,25 @@ import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public class ScoreboardLibraryLogger {
public static final boolean DEBUG;
public static final boolean DEBUG;
static {
String property = System.getProperty(ScoreboardLibrary.NAMESPACE + ".debug");
if (property != null) {
DEBUG = property.equalsIgnoreCase("true");
logMessage("Debug enabled.");
} else {
DEBUG = false;
}
static {
String property = System.getProperty(ScoreboardLibrary.NAMESPACE + ".debug");
if (property != null) {
DEBUG = property.equalsIgnoreCase("true");
logMessage("Debug enabled.");
} else {
DEBUG = false;
}
}
public static void logMessage(String message) {
if (DEBUG) {
ScoreboardManagerProvider provider = ScoreboardManagerProvider.instance();
ScoreboardManagerProvider
.loaderPlugin()
.getLogger()
.info("[ScoreboardManager] " + message);
}
public static void logMessage(String message) {
if (DEBUG) {
ScoreboardManagerProvider provider = ScoreboardManagerProvider.instance();
ScoreboardManagerProvider
.loaderPlugin()
.getLogger()
.info("[ScoreboardManager] " + message);
}
}
}
@@ -18,52 +18,52 @@ import java.util.Collection;
@ApiStatus.Internal
public abstract class ScoreboardManagerProvider {
private static ScoreboardManagerProvider instance;
private static JavaPlugin loaderPlugin;
private static ScoreboardManagerProvider instance;
private static JavaPlugin loaderPlugin;
public static ScoreboardManagerProvider instance() {
return instance;
}
public static ScoreboardManagerProvider instance() {
return instance;
}
public static void instance(ScoreboardManagerProvider instance) {
ScoreboardManagerProvider.instance = instance;
}
public static void instance(ScoreboardManagerProvider instance) {
ScoreboardManagerProvider.instance = instance;
}
public static JavaPlugin loaderPlugin() {
return loaderPlugin;
}
public static JavaPlugin loaderPlugin() {
return loaderPlugin;
}
public static void loaderPlugin(JavaPlugin loaderPlugin) {
ScoreboardManagerProvider.loaderPlugin = loaderPlugin;
}
public static void loaderPlugin(JavaPlugin loaderPlugin) {
ScoreboardManagerProvider.loaderPlugin = loaderPlugin;
}
@NotNull
public TeamInfo teamInfo() {
return teamInfo(null);
}
@NotNull
public TeamInfo teamInfo() {
return teamInfo(null);
}
@NotNull
public abstract TeamInfo teamInfo(@Nullable Collection<String> entries);
@NotNull
public abstract TeamInfo teamInfo(@Nullable Collection<String> entries);
@NotNull
public abstract ScoreboardManager scoreboardManager(JavaPlugin plugin);
@NotNull
public abstract ScoreboardManager scoreboardManager(JavaPlugin plugin);
/**
* Gets the {@link Sidebar} that a player has
*
* @param player Player
* @return Sidebar
*/
@Nullable
public abstract Sidebar sidebar(Player player);
/**
* Gets the {@link Sidebar} that a player has
*
* @param player Player
* @return Sidebar
*/
@Nullable
public abstract Sidebar sidebar(Player player);
/**
* Gets the {@link TeamManager} that a player has
*
* @param player Player
* @return Sidebar
*/
@Nullable
public abstract TeamManager teamManager(Player player);
/**
* Gets the {@link TeamManager} that a player has
*
* @param player Player
* @return Sidebar
*/
@Nullable
public abstract TeamManager teamManager(Player player);
}
+3 -3
View File
@@ -1,7 +1,7 @@
plugins {
`kotlin-dsl`
`kotlin-dsl`
}
repositories {
gradlePluginPortal()
}
gradlePluginPortal()
}
@@ -1,38 +1,38 @@
plugins {
`java-library`
`maven-publish`
`java-library`
`maven-publish`
}
repositories {
mavenLocal()
mavenCentral()
maven { url = uri("https://oss.sonatype.org/content/groups/public/") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
mavenLocal()
mavenCentral()
maven { url = uri("https://oss.sonatype.org/content/groups/public/") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
}
dependencies {
compileOnly("io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT")
val adventureVersion = "4.9.3"
compileOnly("net.kyori:adventure-api:$adventureVersion")
compileOnly("net.kyori:adventure-text-serializer-legacy:$adventureVersion")
compileOnly("net.kyori:adventure-text-serializer-gson:$adventureVersion")
val adventureVersion = "4.9.3"
compileOnly("net.kyori:adventure-api:$adventureVersion")
compileOnly("net.kyori:adventure-text-serializer-legacy:$adventureVersion")
compileOnly("net.kyori:adventure-text-serializer-gson:$adventureVersion")
}
group = "net.megavex.scoreboardlibrary"
version = "1.0.0"
tasks {
compileJava {
options.encoding = Charsets.UTF_8.name()
options.release.set(17)
}
compileJava {
options.encoding = Charsets.UTF_8.name()
options.release.set(17)
}
javadoc {
options.encoding = Charsets.UTF_8.name()
}
javadoc {
options.encoding = Charsets.UTF_8.name()
}
processResources {
filteringCharset = Charsets.UTF_8.name()
}
}
processResources {
filteringCharset = Charsets.UTF_8.name()
}
}
@@ -1,7 +1,7 @@
plugins {
id("net.megavex.scoreboardlibrary.java-conventions")
id("net.megavex.scoreboardlibrary.java-conventions")
}
dependencies {
compileOnly(project(":nms-base"))
}
compileOnly(project(":nms-base"))
}
@@ -1,10 +1,10 @@
plugins {
id("net.megavex.scoreboardlibrary.java-conventions")
`maven-publish`
id("net.megavex.scoreboardlibrary.java-conventions")
`maven-publish`
}
publishing {
publications.create<MavenPublication>("maven") {
from(components["java"])
}
}
publications.create<MavenPublication>("maven") {
from(components["java"])
}
}
+4 -4
View File
@@ -1,8 +1,8 @@
plugins {
id("net.megavex.scoreboardlibrary.publish-conventions")
id("net.megavex.scoreboardlibrary.publish-conventions")
}
dependencies {
api(project(":api"))
implementation(project(":nms-base"))
}
api(project(":api"))
implementation(project(":nms-base"))
}
@@ -16,56 +16,56 @@ import java.lang.reflect.InvocationTargetException;
*/
public final class ScoreboardLibraryImplementation {
private ScoreboardLibraryImplementation() {
private ScoreboardLibraryImplementation() {
}
/**
* Initializes the library
*/
public static synchronized void init() throws ScoreboardLibraryLoadException {
if (ScoreboardManagerProvider.instance() != null) {
return; // Already initialised
}
/**
* Initializes the library
*/
public static synchronized void init() throws ScoreboardLibraryLoadException {
if (ScoreboardManagerProvider.instance() != null) {
return; // Already initialised
}
JavaPlugin plugin = JavaPlugin.getProvidingPlugin(ScoreboardLibraryImplementation.class);
ScoreboardManagerProvider.loaderPlugin(plugin);
JavaPlugin plugin = JavaPlugin.getProvidingPlugin(ScoreboardLibraryImplementation.class);
ScoreboardManagerProvider.loaderPlugin(plugin);
try {
Class.forName("net.kyori.adventure.Adventure");
} catch (ClassNotFoundException e) {
throw new ScoreboardLibraryLoadException("Adventure is not in the classpath");
}
String versionName = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
Class<?> nmsClass;
try {
nmsClass = Class.forName("net.megavex.scoreboardlibrary.internal.nms." + versionName + ".NMSImpl");
} catch (ClassNotFoundException ignored) {
throw new ScoreboardLibraryLoadException("Server version " + versionName + " is not supported");
}
try {
nmsClass.getConstructors()[0].newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new ScoreboardLibraryLoadException("Couldn't initialize NMS implementation", e);
}
ScoreboardManagerProviderImpl.init();
ScoreboardLibraryLogger.logMessage("Loaded implementation " + nmsClass.getName());
try {
Class.forName("net.kyori.adventure.Adventure");
} catch (ClassNotFoundException e) {
throw new ScoreboardLibraryLoadException("Adventure is not in the classpath");
}
public static synchronized void close() {
if (ScoreboardManagerProvider.instance() == null) {
return;
}
ScoreboardManagerProviderImpl provider = ScoreboardManagerProviderImpl.instance();
if (provider != null && !provider.scoreboardManagerMap.isEmpty()) {
ImmutableList.copyOf(provider.scoreboardManagerMap.values()).forEach(ScoreboardManager::close);
}
ScoreboardManagerProvider.instance(null);
ScoreboardManagerProviderImpl.instance(null);
ScoreboardLibraryLogger.logMessage("Closed");
String versionName = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
Class<?> nmsClass;
try {
nmsClass = Class.forName("net.megavex.scoreboardlibrary.internal.nms." + versionName + ".NMSImpl");
} catch (ClassNotFoundException ignored) {
throw new ScoreboardLibraryLoadException("Server version " + versionName + " is not supported");
}
try {
nmsClass.getConstructors()[0].newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new ScoreboardLibraryLoadException("Couldn't initialize NMS implementation", e);
}
ScoreboardManagerProviderImpl.init();
ScoreboardLibraryLogger.logMessage("Loaded implementation " + nmsClass.getName());
}
public static synchronized void close() {
if (ScoreboardManagerProvider.instance() == null) {
return;
}
ScoreboardManagerProviderImpl provider = ScoreboardManagerProviderImpl.instance();
if (provider != null && !provider.scoreboardManagerMap.isEmpty()) {
ImmutableList.copyOf(provider.scoreboardManagerMap.values()).forEach(ScoreboardManager::close);
}
ScoreboardManagerProvider.instance(null);
ScoreboardManagerProviderImpl.instance(null);
ScoreboardLibraryLogger.logMessage("Closed");
}
}
@@ -2,11 +2,11 @@ package net.megavex.scoreboardlibrary.exception;
public class ScoreboardLibraryLoadException extends Exception {
public ScoreboardLibraryLoadException(String message) {
super(message);
}
public ScoreboardLibraryLoadException(String message) {
super(message);
}
public ScoreboardLibraryLoadException(String message, Throwable cause) {
super(message, cause);
}
public ScoreboardLibraryLoadException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -28,139 +28,139 @@ import java.util.concurrent.ConcurrentHashMap;
public class ScoreboardManagerImpl implements ScoreboardManager {
public final JavaPlugin plugin;
public final PlayerListener playerListener = new PlayerListener(this);
public LocaleListener localeListener;
public boolean closed;
public TeamUpdaterTask teamTask;
public SidebarUpdaterTask sidebarTask;
public Set<TeamManagerImpl> teamManagers;
public Set<AbstractSidebar> sidebars;
public final JavaPlugin plugin;
public final PlayerListener playerListener = new PlayerListener(this);
public LocaleListener localeListener;
public boolean closed;
public TeamUpdaterTask teamTask;
public SidebarUpdaterTask sidebarTask;
public Set<TeamManagerImpl> teamManagers;
public Set<AbstractSidebar> sidebars;
public ScoreboardManagerImpl(JavaPlugin plugin) {
Preconditions.checkNotNull(plugin, "JavaPlugin cannot be null");
this.plugin = plugin;
public ScoreboardManagerImpl(JavaPlugin plugin) {
Preconditions.checkNotNull(plugin, "JavaPlugin cannot be null");
this.plugin = plugin;
plugin.getServer().getPluginManager().registerEvents(playerListener, plugin);
try {
Class.forName("org.bukkit.event.player.PlayerLocaleChangeEvent");
ScoreboardLibraryLogger.logMessage("PlayerLocaleChangeEvent was found");
localeListener = new LocaleListener(this);
plugin.getServer().getPluginManager().registerEvents(localeListener, plugin);
} catch (ClassNotFoundException ignored) {
}
plugin.getServer().getPluginManager().registerEvents(playerListener, plugin);
try {
Class.forName("org.bukkit.event.player.PlayerLocaleChangeEvent");
ScoreboardLibraryLogger.logMessage("PlayerLocaleChangeEvent was found");
localeListener = new LocaleListener(this);
plugin.getServer().getPluginManager().registerEvents(localeListener, plugin);
} catch (ClassNotFoundException ignored) {
}
}
@Override
public @NotNull Plugin plugin() {
return plugin;
}
@Override
public @NotNull Sidebar sidebar(int maxLines, @NotNull ComponentTranslator componentTranslator, @Nullable Locale locale) {
checkDestroyed();
getSidebars0();
if (maxLines < 0 || maxLines > Sidebar.MAX_LINES) {
throw new IllegalArgumentException();
}
@Override
public @NotNull Plugin plugin() {
return plugin;
AbstractSidebar sidebar;
if (locale == null) {
sidebar = new PlayerDependantLocaleSidebar(this, componentTranslator, maxLines);
} else {
sidebar = new SingleLocaleSidebar(this, componentTranslator, maxLines, locale);
}
@Override
public @NotNull Sidebar sidebar(int maxLines, @NotNull ComponentTranslator componentTranslator, @Nullable Locale locale) {
checkDestroyed();
getSidebars0();
sidebars.add(sidebar);
return sidebar;
}
if (maxLines < 0 || maxLines > Sidebar.MAX_LINES) {
throw new IllegalArgumentException();
}
@Override
public @NotNull TeamManagerImpl teamManager(@NotNull ComponentTranslator componentTranslator) {
checkDestroyed();
getTeamManagers0();
AbstractSidebar sidebar;
if (locale == null) {
sidebar = new PlayerDependantLocaleSidebar(this, componentTranslator, maxLines);
} else {
sidebar = new SingleLocaleSidebar(this, componentTranslator, maxLines, locale);
}
TeamManagerImpl teamManager = new TeamManagerImpl(this, componentTranslator);
teamManagers.add(teamManager);
return teamManager;
}
sidebars.add(sidebar);
return sidebar;
@Override
public void close() {
if (closed)
return;
closed = true;
ScoreboardManagerProviderImpl.instance().scoreboardManagerMap.remove(plugin);
HandlerList.unregisterAll(playerListener);
if (teamManagers != null) {
teamTask.cancel();
for (TeamManagerImpl teamManager : teamManagers) {
teamManager.close();
}
}
@Override
public @NotNull TeamManagerImpl teamManager(@NotNull ComponentTranslator componentTranslator) {
checkDestroyed();
getTeamManagers0();
TeamManagerImpl teamManager = new TeamManagerImpl(this, componentTranslator);
teamManagers.add(teamManager);
return teamManager;
if (sidebars != null) {
sidebarTask.cancel();
for (AbstractSidebar sidebar : ImmutableList.copyOf(sidebars)) {
sidebar.close();
}
}
}
@Override
public void close() {
if (closed)
return;
@Override
public boolean closed() {
return closed;
}
closed = true;
ScoreboardManagerProviderImpl.instance().scoreboardManagerMap.remove(plugin);
HandlerList.unregisterAll(playerListener);
if (teamManagers != null) {
teamTask.cancel();
for (TeamManagerImpl teamManager : teamManagers) {
teamManager.close();
}
}
if (sidebars != null) {
sidebarTask.cancel();
for (AbstractSidebar sidebar : ImmutableList.copyOf(sidebars)) {
sidebar.close();
}
}
public Set<TeamManagerImpl> getTeamManagers0() {
if (teamManagers == null) {
teamManagers = ConcurrentHashMap.newKeySet(4);
teamTask = new TeamUpdaterTask(this);
}
return teamManagers;
}
@Override
public boolean closed() {
return closed;
public Set<AbstractSidebar> getSidebars0() {
if (sidebars == null) {
sidebars = ConcurrentHashMap.newKeySet(4);
sidebarTask = new SidebarUpdaterTask(this);
}
return sidebars;
}
public Set<TeamManagerImpl> getTeamManagers0() {
if (teamManagers == null) {
teamManagers = ConcurrentHashMap.newKeySet(4);
teamTask = new TeamUpdaterTask(this);
}
return teamManagers;
}
@Override
public Set<TeamManager> teamManagers() {
return Collections.unmodifiableSet(getTeamManagers0());
}
public Set<AbstractSidebar> getSidebars0() {
if (sidebars == null) {
sidebars = ConcurrentHashMap.newKeySet(4);
sidebarTask = new SidebarUpdaterTask(this);
}
return sidebars;
}
@Override
public Set<Sidebar> sidebars() {
return Collections.unmodifiableSet(getSidebars0());
}
@Override
public Set<TeamManager> teamManagers() {
return Collections.unmodifiableSet(getTeamManagers0());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ScoreboardManagerImpl that = (ScoreboardManagerImpl) o;
return closed == that.closed &&
Objects.equals(plugin, that.plugin) &&
Objects.equals(teamTask, that.teamTask) &&
Objects.equals(sidebarTask, that.sidebarTask) &&
Objects.equals(teamManagers, that.teamManagers) &&
Objects.equals(sidebars, that.sidebars);
}
@Override
public Set<Sidebar> sidebars() {
return Collections.unmodifiableSet(getSidebars0());
}
@Override
public int hashCode() {
return plugin.getName().hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ScoreboardManagerImpl that = (ScoreboardManagerImpl) o;
return closed == that.closed &&
Objects.equals(plugin, that.plugin) &&
Objects.equals(teamTask, that.teamTask) &&
Objects.equals(sidebarTask, that.sidebarTask) &&
Objects.equals(teamManagers, that.teamManagers) &&
Objects.equals(sidebars, that.sidebars);
}
@Override
public int hashCode() {
return plugin.getName().hashCode();
}
private void checkDestroyed() {
Preconditions.checkState(!closed, "ScoreboardManager is closed");
}
private void checkDestroyed() {
Preconditions.checkState(!closed, "ScoreboardManager is closed");
}
}
@@ -18,53 +18,53 @@ import java.util.concurrent.ConcurrentHashMap;
public class ScoreboardManagerProviderImpl extends ScoreboardManagerProvider {
private static ScoreboardManagerProviderImpl instance;
public final Map<Player, AbstractSidebar> sidebarMap = new ConcurrentHashMap<>();
public final Map<Player, TeamManagerImpl> teamManagerMap = new ConcurrentHashMap<>();
public final Map<JavaPlugin, ScoreboardManager> scoreboardManagerMap = CollectionProvider.map(1);
private static ScoreboardManagerProviderImpl instance;
public final Map<Player, AbstractSidebar> sidebarMap = new ConcurrentHashMap<>();
public final Map<Player, TeamManagerImpl> teamManagerMap = new ConcurrentHashMap<>();
public final Map<JavaPlugin, ScoreboardManager> scoreboardManagerMap = CollectionProvider.map(1);
private ScoreboardManagerProviderImpl() {
private ScoreboardManagerProviderImpl() {
}
public static ScoreboardManagerProviderImpl instance() {
return instance;
}
public static void instance(ScoreboardManagerProviderImpl instance) {
ScoreboardManagerProviderImpl.instance = instance;
}
public static synchronized void init() {
Preconditions.checkState(instance == null && ScoreboardManagerProvider.instance() == null);
ScoreboardManagerProviderImpl provider = new ScoreboardManagerProviderImpl();
instance = provider;
ScoreboardManagerProvider.instance(provider);
}
@Override
@NotNull
public TeamInfo teamInfo(Collection<String> entries) {
TeamInfoImpl impl = new TeamInfoImpl();
if (entries != null) {
impl.entries.addAll(entries);
}
public static ScoreboardManagerProviderImpl instance() {
return instance;
}
return impl;
}
public static void instance(ScoreboardManagerProviderImpl instance) {
ScoreboardManagerProviderImpl.instance = instance;
}
@Override
@NotNull
public ScoreboardManager scoreboardManager(JavaPlugin plugin) {
return scoreboardManagerMap.computeIfAbsent(plugin, name -> new ScoreboardManagerImpl(plugin));
}
public static synchronized void init() {
Preconditions.checkState(instance == null && ScoreboardManagerProvider.instance() == null);
ScoreboardManagerProviderImpl provider = new ScoreboardManagerProviderImpl();
instance = provider;
ScoreboardManagerProvider.instance(provider);
}
@Override
public Sidebar sidebar(Player player) {
return sidebarMap.get(player);
}
@Override
@NotNull
public TeamInfo teamInfo(Collection<String> entries) {
TeamInfoImpl impl = new TeamInfoImpl();
if (entries != null) {
impl.entries.addAll(entries);
}
return impl;
}
@Override
@NotNull
public ScoreboardManager scoreboardManager(JavaPlugin plugin) {
return scoreboardManagerMap.computeIfAbsent(plugin, name -> new ScoreboardManagerImpl(plugin));
}
@Override
public Sidebar sidebar(Player player) {
return sidebarMap.get(player);
}
@Override
public TeamManagerImpl teamManager(Player player) {
return teamManagerMap.get(player);
}
@Override
public TeamManagerImpl teamManager(Player player) {
return teamManagerMap.get(player);
}
}
@@ -18,27 +18,27 @@ import java.util.Collections;
public record LocaleListener(ScoreboardManagerImpl instance) implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onPlayerLocaleChanged(PlayerLocaleChangeEvent event) {
Player player = event.getPlayer();
// Need to wait a tick because the locale didn't update yet
new BukkitRunnable() {
@Override
public void run() {
TeamManagerImpl teamManager = ScoreboardManagerProviderImpl.instance().teamManager(player);
if (teamManager != null) {
for (ScoreboardTeamImpl team : teamManager.teams.values()) {
TeamInfoImpl teamInfo = team.teamInfo(player);
teamInfo.nms.updateTeam(Collections.singleton(player));
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onPlayerLocaleChanged(PlayerLocaleChangeEvent event) {
Player player = event.getPlayer();
// Need to wait a tick because the locale didn't update yet
new BukkitRunnable() {
@Override
public void run() {
TeamManagerImpl teamManager = ScoreboardManagerProviderImpl.instance().teamManager(player);
if (teamManager != null) {
for (ScoreboardTeamImpl team : teamManager.teams.values()) {
TeamInfoImpl teamInfo = team.teamInfo(player);
teamInfo.nms.updateTeam(Collections.singleton(player));
}
}
AbstractSidebar sidebar = ScoreboardManagerProviderImpl.instance().sidebarMap.get(player);
if (sidebar instanceof PlayerDependantLocaleSidebar) {
sidebar.removePlayer(player);
sidebar.addPlayer(player);
}
}
}.runTaskLater(instance.plugin, 1);
}
AbstractSidebar sidebar = ScoreboardManagerProviderImpl.instance().sidebarMap.get(player);
if (sidebar instanceof PlayerDependantLocaleSidebar) {
sidebar.removePlayer(player);
sidebar.addPlayer(player);
}
}
}.runTaskLater(instance.plugin, 1);
}
}
@@ -12,17 +12,17 @@ import org.bukkit.event.player.PlayerQuitEvent;
public record PlayerListener(ScoreboardManagerImpl instance) implements Listener {
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
AbstractSidebar sidebar = ScoreboardManagerProviderImpl.instance().sidebarMap.get(player);
if (sidebar != null) {
sidebar.removePlayer(player);
}
TeamManagerImpl teamManager = ScoreboardManagerProviderImpl.instance().teamManagerMap.get(player);
if (teamManager != null) {
teamManager.removePlayer(player);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
AbstractSidebar sidebar = ScoreboardManagerProviderImpl.instance().sidebarMap.get(player);
if (sidebar != null) {
sidebar.removePlayer(player);
}
TeamManagerImpl teamManager = ScoreboardManagerProviderImpl.instance().teamManagerMap.get(player);
if (teamManager != null) {
teamManager.removePlayer(player);
}
}
}
@@ -26,287 +26,287 @@ import static net.kyori.adventure.text.Component.empty;
public abstract class AbstractSidebar implements Sidebar {
public final GlobalLineInfo[] lines;
protected final Object lock = new Object();
protected final Object visibilityLock = new Object();
protected final Object playerLock = new Object();
private final ScoreboardManager scoreboardManager;
private final ComponentTranslator componentTranslator;
private final AtomicBoolean updateTitle = new AtomicBoolean(),
updateLines = new AtomicBoolean();
protected volatile boolean closed, visible, visibilityChanged;
private Component title = empty();
private volatile SidebarNMS<?, ?> nms;
public final GlobalLineInfo[] lines;
protected final Object lock = new Object();
protected final Object visibilityLock = new Object();
protected final Object playerLock = new Object();
private final ScoreboardManager scoreboardManager;
private final ComponentTranslator componentTranslator;
private final AtomicBoolean updateTitle = new AtomicBoolean(),
updateLines = new AtomicBoolean();
protected volatile boolean closed, visible, visibilityChanged;
private Component title = empty();
private volatile SidebarNMS<?, ?> nms;
public AbstractSidebar(ScoreboardManager scoreboardManager, ComponentTranslator componentTranslator, int size) {
this.scoreboardManager = scoreboardManager;
this.componentTranslator = componentTranslator;
SidebarUtilities.checkLineBounds(size);
this.lines = new GlobalLineInfo[size];
public AbstractSidebar(ScoreboardManager scoreboardManager, ComponentTranslator componentTranslator, int size) {
this.scoreboardManager = scoreboardManager;
this.componentTranslator = componentTranslator;
SidebarUtilities.checkLineBounds(size);
this.lines = new GlobalLineInfo[size];
}
protected abstract void forEachSidebar(Consumer<SidebarLineHandler> consumer);
protected abstract SidebarLineHandler addPlayer0(Player player);
protected abstract SidebarLineHandler removePlayer0(Player player);
protected void updateScores() {
byte size = 0;
for (GlobalLineInfo line : lines) {
if (line != null && line.value != null) {
size++;
}
}
protected abstract void forEachSidebar(Consumer<SidebarLineHandler> consumer);
protected abstract SidebarLineHandler addPlayer0(Player player);
protected abstract SidebarLineHandler removePlayer0(Player player);
protected void updateScores() {
byte size = 0;
for (GlobalLineInfo line : lines) {
if (line != null && line.value != null) {
size++;
}
}
byte i = 0;
for (GlobalLineInfo line : lines) {
if (line != null && line.value != null) {
byte oldScore = line.objectiveScore;
line.objectiveScore = (byte) (size - i - 1);
if (line.objectiveScore != oldScore) line.updateScore = true;
i++;
}
}
byte i = 0;
for (GlobalLineInfo line : lines) {
if (line != null && line.value != null) {
byte oldScore = line.objectiveScore;
line.objectiveScore = (byte) (size - i - 1);
if (line.objectiveScore != oldScore) line.updateScore = true;
i++;
}
}
}
@Override
public @NotNull ScoreboardManager scoreboardManager() {
return scoreboardManager;
}
@Override
public @NotNull ScoreboardManager scoreboardManager() {
return scoreboardManager;
}
@Override
public @NotNull ComponentTranslator componentTranslator() {
return componentTranslator;
}
@Override
public @NotNull ComponentTranslator componentTranslator() {
return componentTranslator;
}
@Override
public byte maxLines() {
return (byte) lines.length;
}
@Override
public byte maxLines() {
return (byte) lines.length;
}
public void update() {
if (closed) return;
public void update() {
if (closed) return;
synchronized (lock) {
if (closed) return;
synchronized (lock) {
if (closed) return;
synchronized (playerLock) {
Collection<Player> players = players();
synchronized (playerLock) {
Collection<Player> players = players();
if (visibilityChanged) {
synchronized (visibilityLock) {
if (!visibilityChanged) return;
if (visible) {
sidebarBridge().create(players);
forEachSidebar(SidebarLineHandler::show);
ScoreboardManagerNMS.INSTANCE.displaySidebar(players);
} else {
forEachSidebar(SidebarLineHandler::hide);
ScoreboardManagerNMS.INSTANCE.removeSidebar(players);
}
visibilityChanged = false;
}
}
if (updateTitle.getAndSet(false)) {
sidebarBridge().updateTitle(title);
if (visible) {
nms.update(players);
}
}
}
if (updateLines.getAndSet(false)) {
updateScores();
boolean updateTeams = false;
for (GlobalLineInfo line : lines) {
if (line == null || !line.update) continue;
line.updateTeams = true;
updateTeams = true;
forEachSidebar(s -> {
if (line.value != null) {
Component rendered = componentTranslator.translate(line.value, s.locale());
s.setLine(line.line, rendered);
} else {
s.setLine(line.line, null);
}
});
line.update = false;
}
if (updateTeams) {
forEachSidebar(SidebarLineHandler::update);
for (GlobalLineInfo line : lines) {
if (line != null) line.updateTeams = false;
}
}
}
}
}
@Override
public boolean addPlayer(@NotNull Player player) {
checkClosed();
checkPlayer(player);
synchronized (playerLock) {
SidebarLineHandler sidebar = addPlayer0(player);
if (sidebar == null) return false;
LineType lineType = LineType.getType(player);
sidebar.playersInit(lineType).add(player);
ScoreboardManagerProviderImpl.instance().sidebarMap.put(player, this);
if (visibilityChanged) {
synchronized (visibilityLock) {
if (!visibilityChanged) return;
if (visible) {
var singleton = Collections.singleton(player);
sidebarBridge().create(singleton);
sidebar.show(singleton, lineType);
ScoreboardManagerNMS.INSTANCE.displaySidebar(singleton);
}
}
return true;
}
@Override
public boolean removePlayer(@NotNull Player player) {
checkClosed();
synchronized (playerLock) {
SidebarLineHandler sidebar = removePlayer0(player);
if (sidebar == null) return false;
LineType lineType = LineType.getType(player);
sidebar.players(lineType).remove(player);
ScoreboardManagerProviderImpl.instance().sidebarMap.remove(player, this);
if (visible) {
var singleton = Collections.singleton(player);
sidebar.hide(singleton, lineType);
ScoreboardManagerNMS.INSTANCE.removeSidebar(singleton);
}
}
return true;
}
@Override
public boolean visible() {
return visible;
}
@Override
public void visible(boolean visible) {
checkClosed();
if (this.visible == visible) return;
synchronized (visibilityLock) {
if (this.visible == visible) return;
this.visible = visible;
this.visibilityChanged = !visibilityChanged;
}
}
@Override
public Component title() {
return title;
}
@Override
public void line(int line, Component value) {
checkClosed();
checkLine(line);
Component component = line(line);
if (Objects.equals(value, component)) return;
GlobalLineInfo lineInfo = getLineInfo(line);
lineInfo.value = value;
if (visible) {
lineInfo.update = true;
updateLines.set(true);
}
}
@Override
public @Nullable Component line(int line) {
GlobalLineInfo info = lines[line];
return info == null ? null : info.value;
}
public GlobalLineInfo getLineInfo(int line) {
GlobalLineInfo info = lines[line];
if (info == null) {
info = new GlobalLineInfo((byte) line);
lines[line] = info;
}
return info;
}
@Override
public void title(Component title) {
checkClosed();
Preconditions.checkNotNull(title);
if (!this.title.equals(title)) {
this.title = title;
updateTitle.set(true);
}
}
@Override
public void close() {
synchronized (lock) {
removePlayers(players());
visible = false;
closed = true;
}
}
@Override
public boolean closed() {
return closed;
}
public SidebarNMS<?, ?> sidebarBridge() {
if (nms == null)
synchronized (lock) {
if (nms == null) nms = ScoreboardManagerNMS.INSTANCE.createSidebarNMS(this);
sidebarBridge().create(players);
forEachSidebar(SidebarLineHandler::show);
ScoreboardManagerNMS.INSTANCE.displaySidebar(players);
} else {
forEachSidebar(SidebarLineHandler::hide);
ScoreboardManagerNMS.INSTANCE.removeSidebar(players);
}
return nms;
}
private void checkPlayer(Player player) {
// TODO: remove this restriction
Sidebar sidebar = ScoreboardManagerProviderImpl.instance().sidebar(player);
if (sidebar != null && sidebar != this)
throw new IllegalArgumentException("Player " + player.getName() + " already has a sidebar");
}
private void checkClosed() {
if (closed) {
throw new IllegalStateException("Sidebar is closed");
visibilityChanged = false;
}
}
if (updateTitle.getAndSet(false)) {
sidebarBridge().updateTitle(title);
if (visible) {
nms.update(players);
}
}
}
if (updateLines.getAndSet(false)) {
updateScores();
boolean updateTeams = false;
for (GlobalLineInfo line : lines) {
if (line == null || !line.update) continue;
line.updateTeams = true;
updateTeams = true;
forEachSidebar(s -> {
if (line.value != null) {
Component rendered = componentTranslator.translate(line.value, s.locale());
s.setLine(line.line, rendered);
} else {
s.setLine(line.line, null);
}
});
line.update = false;
}
if (updateTeams) {
forEachSidebar(SidebarLineHandler::update);
for (GlobalLineInfo line : lines) {
if (line != null) line.updateTeams = false;
}
}
}
}
private void checkLine(int line) {
if (line > lines.length || line < 0) {
throw new IndexOutOfBoundsException("Invalid line " + line);
}
}
@Override
public boolean addPlayer(@NotNull Player player) {
checkClosed();
checkPlayer(player);
synchronized (playerLock) {
SidebarLineHandler sidebar = addPlayer0(player);
if (sidebar == null) return false;
LineType lineType = LineType.getType(player);
sidebar.playersInit(lineType).add(player);
ScoreboardManagerProviderImpl.instance().sidebarMap.put(player, this);
if (visible) {
var singleton = Collections.singleton(player);
sidebarBridge().create(singleton);
sidebar.show(singleton, lineType);
ScoreboardManagerNMS.INSTANCE.displaySidebar(singleton);
}
}
return true;
}
@Override
public boolean removePlayer(@NotNull Player player) {
checkClosed();
synchronized (playerLock) {
SidebarLineHandler sidebar = removePlayer0(player);
if (sidebar == null) return false;
LineType lineType = LineType.getType(player);
sidebar.players(lineType).remove(player);
ScoreboardManagerProviderImpl.instance().sidebarMap.remove(player, this);
if (visible) {
var singleton = Collections.singleton(player);
sidebar.hide(singleton, lineType);
ScoreboardManagerNMS.INSTANCE.removeSidebar(singleton);
}
}
return true;
}
@Override
public boolean visible() {
return visible;
}
@Override
public void visible(boolean visible) {
checkClosed();
if (this.visible == visible) return;
synchronized (visibilityLock) {
if (this.visible == visible) return;
this.visible = visible;
this.visibilityChanged = !visibilityChanged;
}
}
@Override
public Component title() {
return title;
}
@Override
public void line(int line, Component value) {
checkClosed();
checkLine(line);
Component component = line(line);
if (Objects.equals(value, component)) return;
GlobalLineInfo lineInfo = getLineInfo(line);
lineInfo.value = value;
if (visible) {
lineInfo.update = true;
updateLines.set(true);
}
}
@Override
public @Nullable Component line(int line) {
GlobalLineInfo info = lines[line];
return info == null ? null : info.value;
}
public GlobalLineInfo getLineInfo(int line) {
GlobalLineInfo info = lines[line];
if (info == null) {
info = new GlobalLineInfo((byte) line);
lines[line] = info;
}
return info;
}
@Override
public void title(Component title) {
checkClosed();
Preconditions.checkNotNull(title);
if (!this.title.equals(title)) {
this.title = title;
updateTitle.set(true);
}
}
@Override
public void close() {
synchronized (lock) {
removePlayers(players());
visible = false;
closed = true;
}
}
@Override
public boolean closed() {
return closed;
}
public SidebarNMS<?, ?> sidebarBridge() {
if (nms == null)
synchronized (lock) {
if (nms == null) nms = ScoreboardManagerNMS.INSTANCE.createSidebarNMS(this);
}
return nms;
}
private void checkPlayer(Player player) {
// TODO: remove this restriction
Sidebar sidebar = ScoreboardManagerProviderImpl.instance().sidebar(player);
if (sidebar != null && sidebar != this)
throw new IllegalArgumentException("Player " + player.getName() + " already has a sidebar");
}
private void checkClosed() {
if (closed) {
throw new IllegalStateException("Sidebar is closed");
}
}
private void checkLine(int line) {
if (line > lines.length || line < 0) {
throw new IndexOutOfBoundsException("Invalid line " + line);
}
}
}
@@ -17,86 +17,86 @@ import java.util.function.Consumer;
public class PlayerDependantLocaleSidebar extends AbstractSidebar {
private volatile Map<Player, SidebarLineHandler> playerMap;
private volatile Map<Locale, SidebarLineHandler> localeMap;
private volatile Map<Player, SidebarLineHandler> playerMap;
private volatile Map<Locale, SidebarLineHandler> localeMap;
public PlayerDependantLocaleSidebar(ScoreboardManager scoreboardManager, ComponentTranslator componentTranslator, int size) {
super(scoreboardManager, componentTranslator, size);
public PlayerDependantLocaleSidebar(ScoreboardManager scoreboardManager, ComponentTranslator componentTranslator, int size) {
super(scoreboardManager, componentTranslator, size);
}
@Override
public @Nullable Locale locale() {
return null;
}
@Override
protected void forEachSidebar(Consumer<SidebarLineHandler> consumer) {
if (localeMap != null) {
for (SidebarLineHandler value : localeMap.values()) {
consumer.accept(value);
}
}
}
@Override
public @NotNull Collection<Player> players() {
return playerMap == null ? Collections.emptySet() : playerMap.keySet();
}
@Override
protected SidebarLineHandler addPlayer0(Player player) {
SidebarLineHandler sidebar = playerMap == null ? null : playerMap.get(player);
if (sidebar != null) {
return sidebar;
}
@Override
public @Nullable Locale locale() {
return null;
Locale locale = LocaleUtilities.getLocaleOfPlayer(player);
if (localeMap == null)
synchronized (lock) {
if (localeMap == null) localeMap = new ConcurrentHashMap<>(4, 0.75f, 2);
}
sidebar = localeMap.get(locale);
if (sidebar != null) {
return sidebar;
}
@Override
protected void forEachSidebar(Consumer<SidebarLineHandler> consumer) {
if (localeMap != null) {
for (SidebarLineHandler value : localeMap.values()) {
consumer.accept(value);
}
}
sidebar = new SidebarLineHandler(this, locale);
localeMap.put(locale, sidebar);
if (playerMap == null)
synchronized (lock) {
if (playerMap == null) playerMap = new ConcurrentHashMap<>(4, 0.75f, 2);
}
playerMap.put(player, sidebar);
return sidebar;
}
@Override
protected SidebarLineHandler removePlayer0(Player player) {
if (playerMap == null) return null;
SidebarLineHandler lineHandler = playerMap.remove(player);
if (lineHandler == null) return null;
if (!lineHandler.hasPlayers() && localeMap != null) {
localeMap.remove(lineHandler.locale());
}
@Override
public @NotNull Collection<Player> players() {
return playerMap == null ? Collections.emptySet() : playerMap.keySet();
}
@Override
protected SidebarLineHandler addPlayer0(Player player) {
SidebarLineHandler sidebar = playerMap == null ? null : playerMap.get(player);
if (sidebar != null) {
return sidebar;
}
Locale locale = LocaleUtilities.getLocaleOfPlayer(player);
if (localeMap == null)
synchronized (lock) {
if (localeMap == null) localeMap = new ConcurrentHashMap<>(4, 0.75f, 2);
}
sidebar = localeMap.get(locale);
if (sidebar != null) {
return sidebar;
}
sidebar = new SidebarLineHandler(this, locale);
localeMap.put(locale, sidebar);
if (playerMap == null)
synchronized (lock) {
if (playerMap == null) playerMap = new ConcurrentHashMap<>(4, 0.75f, 2);
}
playerMap.put(player, sidebar);
return sidebar;
}
@Override
protected SidebarLineHandler removePlayer0(Player player) {
if (playerMap == null) return null;
SidebarLineHandler lineHandler = playerMap.remove(player);
if (lineHandler == null) return null;
if (!lineHandler.hasPlayers() && localeMap != null) {
localeMap.remove(lineHandler.locale());
}
return lineHandler;
}
@Override
public void close() {
super.close();
if (closed) {
playerMap = null;
localeMap = null;
}
return lineHandler;
}
@Override
public void close() {
super.close();
if (closed) {
playerMap = null;
localeMap = null;
}
}
}
@@ -10,25 +10,25 @@ import java.util.logging.Logger;
public class SidebarUpdaterTask extends BukkitRunnable {
private final Logger logger;
private final Set<AbstractSidebar> sidebars;
private final Logger logger;
private final Set<AbstractSidebar> sidebars;
public SidebarUpdaterTask(ScoreboardManagerImpl manager) {
Preconditions.checkNotNull(manager);
this.logger = manager.plugin().getLogger();
this.sidebars = manager.sidebars;
public SidebarUpdaterTask(ScoreboardManagerImpl manager) {
Preconditions.checkNotNull(manager);
this.logger = manager.plugin().getLogger();
this.sidebars = manager.sidebars;
runTaskTimerAsynchronously(manager.plugin(), 1, 1);
}
@Override
public void run() {
for (AbstractSidebar sidebar : sidebars) {
try {
sidebar.update();
} catch (Exception e) {
logger.log(Level.WARNING, "Exception caught when updating Sidebar", e);
}
}
runTaskTimerAsynchronously(manager.plugin(), 1, 1);
}
@Override
public void run() {
for (AbstractSidebar sidebar : sidebars) {
try {
sidebar.update();
} catch (Exception e) {
logger.log(Level.WARNING, "Exception caught when updating Sidebar", e);
}
}
}
}
@@ -16,70 +16,70 @@ import java.util.function.Consumer;
public class SingleLocaleSidebar extends AbstractSidebar {
private final Locale locale;
private volatile SidebarLineHandler sidebar;
private volatile Set<Player> players;
private final Locale locale;
private volatile SidebarLineHandler sidebar;
private volatile Set<Player> players;
public SingleLocaleSidebar(ScoreboardManager scoreboardManager, ComponentTranslator componentTranslator, int size, Locale locale) {
super(scoreboardManager, componentTranslator, size);
this.locale = locale;
public SingleLocaleSidebar(ScoreboardManager scoreboardManager, ComponentTranslator componentTranslator, int size, Locale locale) {
super(scoreboardManager, componentTranslator, size);
this.locale = locale;
}
@Override
public @NotNull Collection<Player> players() {
return players == null ? Collections.emptySet() : Collections.unmodifiableCollection(players);
}
@Override
protected SidebarLineHandler addPlayer0(Player player) {
if (!playerSet().add(player)) return null;
return lineHandler();
}
@Override
protected SidebarLineHandler removePlayer0(Player player) {
if (players == null || !players.remove(player)) return null;
return lineHandler();
}
@Override
public @Nullable Locale locale() {
return locale;
}
@Override
protected void forEachSidebar(Consumer<SidebarLineHandler> consumer) {
consumer.accept(lineHandler());
}
@Override
public void close() {
super.close();
if (closed) {
players = null;
}
}
@Override
public @NotNull Collection<Player> players() {
return players == null ? Collections.emptySet() : Collections.unmodifiableCollection(players);
}
@Override
protected SidebarLineHandler addPlayer0(Player player) {
if (!playerSet().add(player)) return null;
return lineHandler();
}
@Override
protected SidebarLineHandler removePlayer0(Player player) {
if (players == null || !players.remove(player)) return null;
return lineHandler();
}
@Override
public @Nullable Locale locale() {
return locale;
}
@Override
protected void forEachSidebar(Consumer<SidebarLineHandler> consumer) {
consumer.accept(lineHandler());
}
@Override
public void close() {
super.close();
if (closed) {
players = null;
private Set<Player> playerSet() {
if (players == null)
synchronized (lock) {
if (players == null) {
players = CollectionProvider.set(1);
}
}
}
private Set<Player> playerSet() {
if (players == null)
synchronized (lock) {
if (players == null) {
players = CollectionProvider.set(1);
}
}
return players;
}
return players;
}
private SidebarLineHandler lineHandler() {
if (sidebar == null)
synchronized (lock) {
if (sidebar == null) sidebar = new SidebarLineHandler(this, locale());
}
private SidebarLineHandler lineHandler() {
if (sidebar == null)
synchronized (lock) {
if (sidebar == null) sidebar = new SidebarLineHandler(this, locale());
}
return sidebar;
}
return sidebar;
}
}
@@ -7,27 +7,27 @@ import org.bukkit.ChatColor;
public class GlobalLineInfo {
private static final String[] lineColors = new String[15];
private static final String[] lineColors = new String[15];
static {
ChatColor[] values = ChatColor.values();
for (byte i = 0; i < lineColors.length; i++) {
lineColors[i] = values[i].toString();
}
static {
ChatColor[] values = ChatColor.values();
for (byte i = 0; i < lineColors.length; i++) {
lineColors[i] = values[i].toString();
}
}
public final byte line;
public final TeamNMS<?, ?> bridge;
public Component value;
public byte objectiveScore;
public boolean update, updateTeams, updateScore;
public final byte line;
public final TeamNMS<?, ?> bridge;
public Component value;
public byte objectiveScore;
public boolean update, updateTeams, updateScore;
public GlobalLineInfo(byte line) {
this.line = line;
this.bridge = ScoreboardManagerNMS.INSTANCE.createTeamNMS("_l" + line);
}
public GlobalLineInfo(byte line) {
this.line = line;
this.bridge = ScoreboardManagerNMS.INSTANCE.createTeamNMS("_l" + line);
}
public String player() {
return lineColors[line];
}
public String player() {
return lineColors[line];
}
}
@@ -13,170 +13,170 @@ import java.util.Set;
public class SidebarLineHandler {
private final AbstractSidebar sidebar;
private final Locale locale;
private final AbstractSidebar sidebar;
private final Locale locale;
private Set<Player> players, legacyPlayers;
private LocaleLine<?>[] lines, legacyLines;
private Set<Player> players, legacyPlayers;
private LocaleLine<?>[] lines, legacyLines;
public SidebarLineHandler(AbstractSidebar sidebar, Locale locale) {
this.sidebar = sidebar;
this.locale = locale;
public SidebarLineHandler(AbstractSidebar sidebar, Locale locale) {
this.sidebar = sidebar;
this.locale = locale;
}
public AbstractSidebar sidebar() {
return sidebar;
}
public Locale locale() {
return locale;
}
public boolean hasPlayers() {
if (players != null && !players.isEmpty()) return true;
return legacyPlayers != null && !legacyPlayers.isEmpty();
}
public Set<Player> players(LineType lineType) {
if (lineType == LineType.NEW) {
return players;
} else {
return legacyPlayers;
}
}
public AbstractSidebar sidebar() {
return sidebar;
public Set<Player> playersInit(LineType lineType) {
if (lineType == LineType.NEW) {
if (players == null) players = CollectionProvider.set(1);
return players;
} else {
if (legacyPlayers == null) legacyPlayers = CollectionProvider.set(1);
return legacyPlayers;
}
}
public Locale locale() {
return locale;
public LocaleLine<?>[] lines(LineType lineType) {
if (lineType == LineType.NEW) {
return lines;
} else {
return legacyLines;
}
}
public boolean hasPlayers() {
if (players != null && !players.isEmpty()) return true;
return legacyPlayers != null && !legacyPlayers.isEmpty();
public LocaleLine<?>[] linesInit(LineType lineType) {
if (lineType == LineType.NEW) {
if (lines == null) {
lines = new LocaleLine[sidebar.maxLines()];
initLines(lineType);
}
return lines;
} else {
if (legacyLines == null) {
legacyLines = new LocaleLine[sidebar.maxLines()];
initLines(lineType);
}
return legacyLines;
}
}
public Set<Player> players(LineType lineType) {
if (lineType == LineType.NEW) {
return players;
} else {
return legacyPlayers;
}
}
public void update() {
update(LineType.NEW);
update(LineType.LEGACY);
}
public Set<Player> playersInit(LineType lineType) {
if (lineType == LineType.NEW) {
if (players == null) players = CollectionProvider.set(1);
return players;
} else {
if (legacyPlayers == null) legacyPlayers = CollectionProvider.set(1);
return legacyPlayers;
}
}
private void update(LineType lineType) {
LocaleLine<?>[] lines = lines(lineType);
if (lines == null) return;
Set<Player> players = players(lineType);
public LocaleLine<?>[] lines(LineType lineType) {
if (lineType == LineType.NEW) {
return lines;
} else {
return legacyLines;
}
}
public LocaleLine<?>[] linesInit(LineType lineType) {
if (lineType == LineType.NEW) {
if (lines == null) {
lines = new LocaleLine[sidebar.maxLines()];
initLines(lineType);
}
return lines;
} else {
if (legacyLines == null) {
legacyLines = new LocaleLine[sidebar.maxLines()];
initLines(lineType);
}
return legacyLines;
}
}
public void update() {
update(LineType.NEW);
update(LineType.LEGACY);
}
private void update(LineType lineType) {
LocaleLine<?>[] lines = lines(lineType);
if (lines == null) return;
Set<Player> players = players(lineType);
for (LocaleLine<?> line : lines) {
if (line != null) {
if (line.info().updateTeams) {
line.updateTeam();
}
if (line.info().updateScore && sidebar.visible()) {
line.sendScore(players);
}
}
}
}
public void setLine(int line, Component renderedLine) {
setLine(line, renderedLine, LineType.NEW);
setLine(line, renderedLine, LineType.LEGACY);
}
public void setLine(int line, Component renderedLine, LineType lineType) {
setLine(line, renderedLine, lineType, true);
}
public void setLine(int line, Component renderedLine, LineType lineType, boolean sendPackets) {
LocaleLine<?>[] lines = lines(lineType);
if (lines == null) return;
LocaleLine<?> localeLine = lines[line];
if (renderedLine == null && localeLine == null) {
return;
for (LocaleLine<?> line : lines) {
if (line != null) {
if (line.info().updateTeams) {
line.updateTeam();
}
boolean newlyCreated = false;
if (localeLine == null) {
lines[line] = localeLine = lineType.create(sidebar.getLineInfo(line), this);
newlyCreated = true;
if (line.info().updateScore && sidebar.visible()) {
line.sendScore(players);
}
}
}
}
if (renderedLine == null) {
lines[line] = null;
} else {
localeLine.value(renderedLine);
}
public void setLine(int line, Component renderedLine) {
setLine(line, renderedLine, LineType.NEW);
setLine(line, renderedLine, LineType.LEGACY);
}
if (!sidebar.visible() || !sendPackets) return;
public void setLine(int line, Component renderedLine, LineType lineType) {
setLine(line, renderedLine, lineType, true);
}
Collection<Player> players = players(lineType);
public void setLine(int line, Component renderedLine, LineType lineType, boolean sendPackets) {
LocaleLine<?>[] lines = lines(lineType);
if (lines == null) return;
if (renderedLine == null) {
localeLine.hide(players);
} else if (newlyCreated) {
localeLine.show(players);
}
LocaleLine<?> localeLine = lines[line];
if (renderedLine == null && localeLine == null) {
return;
}
public void show() {
if (players != null) show(players, LineType.NEW);
if (legacyPlayers != null) show(legacyPlayers, LineType.LEGACY);
boolean newlyCreated = false;
if (localeLine == null) {
lines[line] = localeLine = lineType.create(sidebar.getLineInfo(line), this);
newlyCreated = true;
}
public void hide() {
if (players != null) hide(players, LineType.NEW);
if (legacyPlayers != null) hide(legacyPlayers, LineType.LEGACY);
if (renderedLine == null) {
lines[line] = null;
} else {
localeLine.value(renderedLine);
}
public void show(Collection<Player> players, LineType lineType) {
LocaleLine<?>[] lines = linesInit(lineType);
for (LocaleLine<?> line : lines) {
if (line != null && line.info().value != null) {
line.show(players);
}
}
}
if (!sidebar.visible() || !sendPackets) return;
public void hide(Collection<Player> players, LineType lineType) {
LocaleLine<?>[] lines = lines(lineType);
if (lines == null) return;
for (LocaleLine<?> line : lines) {
if (line != null && ((line.info().update) || line.info().value != null)) {
line.hide(players);
}
}
}
Collection<Player> players = players(lineType);
private void initLines(LineType lineType) {
for (GlobalLineInfo line : sidebar.lines) {
if (line != null) {
setLine(line.line, sidebar.componentTranslator().translate(line.value, locale), lineType, false);
}
}
if (renderedLine == null) {
localeLine.hide(players);
} else if (newlyCreated) {
localeLine.show(players);
}
}
public void show() {
if (players != null) show(players, LineType.NEW);
if (legacyPlayers != null) show(legacyPlayers, LineType.LEGACY);
}
public void hide() {
if (players != null) hide(players, LineType.NEW);
if (legacyPlayers != null) hide(legacyPlayers, LineType.LEGACY);
}
public void show(Collection<Player> players, LineType lineType) {
LocaleLine<?>[] lines = linesInit(lineType);
for (LocaleLine<?> line : lines) {
if (line != null && line.info().value != null) {
line.show(players);
}
}
}
public void hide(Collection<Player> players, LineType lineType) {
LocaleLine<?>[] lines = lines(lineType);
if (lines == null) return;
for (LocaleLine<?> line : lines) {
if (line != null && ((line.info().update) || line.info().value != null)) {
line.hide(players);
}
}
}
private void initLines(LineType lineType) {
for (GlobalLineInfo line : sidebar.lines) {
if (line != null) {
setLine(line.line, sidebar.componentTranslator().translate(line.value, locale), lineType, false);
}
}
}
}
@@ -14,142 +14,142 @@ import java.util.Set;
class LegacyLocaleLine implements LocaleLine<String> {
private final GlobalLineInfo info;
private final SidebarLineHandler handler;
private final TeamNMS.TeamInfoNMS<String> bridge;
private String player, oldPlayer;
private String prefix, suffix;
private String currentValue;
private boolean update = false;
private final GlobalLineInfo info;
private final SidebarLineHandler handler;
private final TeamNMS.TeamInfoNMS<String> bridge;
private String player, oldPlayer;
private String prefix, suffix;
private String currentValue;
private boolean update = false;
public LegacyLocaleLine(GlobalLineInfo info, SidebarLineHandler handler) {
this.info = info;
this.handler = handler;
public LegacyLocaleLine(GlobalLineInfo info, SidebarLineHandler handler) {
this.info = info;
this.handler = handler;
this.player = info.player();
this.bridge = info.bridge.createLegacyTeamInfoNMS(this);
bridge.updateTeamPackets(entries());
}
public GlobalLineInfo info() {
return info;
}
@Override
public String displayName() {
return "";
}
@Override
public String prefix() {
return prefix;
}
@Override
public String suffix() {
return suffix;
}
@Override
public Collection<String> entries() {
return Collections.singleton(player);
}
@Override
public void value(Component renderedComponent) {
String legacyValue = LegacyComponentSerializer.legacySection().serialize(renderedComponent);
oldPlayer = player;
if (legacyValue.length() <= 16) {
this.prefix = legacyValue;
this.suffix = "";
if (this.currentValue != null && this.currentValue.length() > 32) {
this.player = info.player();
this.bridge = info.bridge.createLegacyTeamInfoNMS(this);
bridge.updateTeamPackets(entries());
}
}
} else {
boolean color = legacyValue.charAt(15) == ChatColor.COLOR_CHAR;
public GlobalLineInfo info() {
return info;
}
int prefixEnd = color ? 15 : 16;
this.prefix = legacyValue.substring(0, prefixEnd);
@Override
public String displayName() {
return "";
}
this.player = info.player() + ChatColor.RESET
+ ChatColor.getLastColors(prefix +
ChatColor.COLOR_CHAR + (color ? legacyValue.charAt(16) : ""));
@Override
public String prefix() {
return prefix;
}
int playerEnd = prefixEnd;
if (legacyValue.length() > 32) {
int remaining = 16 - player.length();
assert remaining > 0;
@Override
public String suffix() {
return suffix;
}
playerEnd += remaining;
player += legacyValue.substring(prefixEnd, playerEnd);
}
@Override
public Collection<String> entries() {
return Collections.singleton(player);
}
@Override
public void value(Component renderedComponent) {
String legacyValue = LegacyComponentSerializer.legacySection().serialize(renderedComponent);
oldPlayer = player;
if (legacyValue.length() <= 16) {
this.prefix = legacyValue;
this.suffix = "";
if (this.currentValue != null && this.currentValue.length() > 32) {
this.player = info.player();
}
} else {
boolean color = legacyValue.charAt(15) == ChatColor.COLOR_CHAR;
int prefixEnd = color ? 15 : 16;
this.prefix = legacyValue.substring(0, prefixEnd);
this.player = info.player() + ChatColor.RESET
+ ChatColor.getLastColors(prefix +
ChatColor.COLOR_CHAR + (color ? legacyValue.charAt(16) : ""));
int playerEnd = prefixEnd;
if (legacyValue.length() > 32) {
int remaining = 16 - player.length();
assert remaining > 0;
playerEnd += remaining;
player += legacyValue.substring(prefixEnd, playerEnd);
}
this.suffix = legacyValue.substring(playerEnd + (color ? 2 : 0));
if (suffix.length() > 16) {
String newSuffix = suffix.substring(0, 16);
if (newSuffix.endsWith(String.valueOf(ChatColor.COLOR_CHAR)) &&
ChatColor.getByChar(suffix.charAt(16)) != null) {
newSuffix = newSuffix.substring(0, 15);
}
suffix = newSuffix;
}
this.suffix = legacyValue.substring(playerEnd + (color ? 2 : 0));
if (suffix.length() > 16) {
String newSuffix = suffix.substring(0, 16);
if (newSuffix.endsWith(String.valueOf(ChatColor.COLOR_CHAR)) &&
ChatColor.getByChar(suffix.charAt(16)) != null) {
newSuffix = newSuffix.substring(0, 15);
}
currentValue = legacyValue;
update = true;
if (oldPlayer.equals(player)) {
oldPlayer = null;
}
suffix = newSuffix;
}
}
@Override
public void updateTeam() {
if (!update) {
return;
}
currentValue = legacyValue;
update = true;
Set<Player> players = handler.players(LineType.LEGACY);
if (oldPlayer != null) {
bridge.removeEntries(players, Collections.singleton(oldPlayer));
handler.sidebar().sidebarBridge().removeLine(players, oldPlayer);
oldPlayer = null;
}
if (oldPlayer.equals(player)) {
oldPlayer = null;
}
}
Collection<String> entries = entries();
bridge.updateTeamPackets(entries);
bridge.addEntries(players, entries);
bridge.updateTeam(players);
update = false;
@Override
public void updateTeam() {
if (!update) {
return;
}
@Override
public void sendScore(Collection<Player> players) {
if (oldPlayer != null) {
handler.sidebar().sidebarBridge().removeLine(players, oldPlayer);
}
handler.sidebar().sidebarBridge().score(players, info.objectiveScore, player);
Set<Player> players = handler.players(LineType.LEGACY);
if (oldPlayer != null) {
bridge.removeEntries(players, Collections.singleton(oldPlayer));
handler.sidebar().sidebarBridge().removeLine(players, oldPlayer);
oldPlayer = null;
}
@Override
public void show(Collection<Player> players) {
sendScore(players);
bridge.createTeam(players);
Collection<String> entries = entries();
bridge.updateTeamPackets(entries);
bridge.addEntries(players, entries);
bridge.updateTeam(players);
update = false;
}
@Override
public void sendScore(Collection<Player> players) {
if (oldPlayer != null) {
handler.sidebar().sidebarBridge().removeLine(players, oldPlayer);
}
@Override
public void hide(Collection<Player> players) {
if (oldPlayer != null) {
handler.sidebar().sidebarBridge().removeLine(players, oldPlayer);
}
handler.sidebar().sidebarBridge().score(players, info.objectiveScore, player);
}
handler.sidebar().sidebarBridge().removeLine(players, player);
info.bridge.removeTeam(players);
@Override
public void show(Collection<Player> players) {
sendScore(players);
bridge.createTeam(players);
}
@Override
public void hide(Collection<Player> players) {
if (oldPlayer != null) {
handler.sidebar().sidebarBridge().removeLine(players, oldPlayer);
}
handler.sidebar().sidebarBridge().removeLine(players, player);
info.bridge.removeTeam(players);
}
}
@@ -8,20 +8,20 @@ import org.bukkit.entity.Player;
import java.util.function.BiFunction;
public enum LineType {
NEW(LocaleLineImpl::new),
LEGACY(LegacyLocaleLine::new);
NEW(LocaleLineImpl::new),
LEGACY(LegacyLocaleLine::new);
private final BiFunction<GlobalLineInfo, SidebarLineHandler, LocaleLine<?>> constructor;
private final BiFunction<GlobalLineInfo, SidebarLineHandler, LocaleLine<?>> constructor;
LineType(BiFunction<GlobalLineInfo, SidebarLineHandler, LocaleLine<?>> constructor) {
this.constructor = constructor;
}
LineType(BiFunction<GlobalLineInfo, SidebarLineHandler, LocaleLine<?>> constructor) {
this.constructor = constructor;
}
public static LineType getType(Player player) {
return ScoreboardManagerNMS.INSTANCE.isLegacy(player) ? LEGACY : NEW;
}
public static LineType getType(Player player) {
return ScoreboardManagerNMS.INSTANCE.isLegacy(player) ? LEGACY : NEW;
}
public LocaleLine<?> create(GlobalLineInfo line, SidebarLineHandler sidebarLineHandler) {
return constructor.apply(line, sidebarLineHandler);
}
public LocaleLine<?> create(GlobalLineInfo line, SidebarLineHandler sidebarLineHandler) {
return constructor.apply(line, sidebarLineHandler);
}
}
@@ -8,15 +8,15 @@ import org.bukkit.entity.Player;
import java.util.Collection;
public interface LocaleLine<C> extends ImmutableTeamProperties<C> {
GlobalLineInfo info();
GlobalLineInfo info();
void value(Component renderedComponent);
void value(Component renderedComponent);
void updateTeam();
void updateTeam();
void sendScore(Collection<Player> players);
void sendScore(Collection<Player> players);
void show(Collection<Player> players);
void show(Collection<Player> players);
void hide(Collection<Player> players);
void hide(Collection<Player> players);
}
@@ -14,75 +14,75 @@ import static net.kyori.adventure.text.Component.empty;
// Implementation for new versions above 1.12.2
class LocaleLineImpl implements LocaleLine<Component> {
private final GlobalLineInfo info;
private final SidebarLineHandler handler;
private final Collection<String> entries;
private final TeamNMS.TeamInfoNMS<Component> bridge;
private boolean update = false;
private final GlobalLineInfo info;
private final SidebarLineHandler handler;
private final Collection<String> entries;
private final TeamNMS.TeamInfoNMS<Component> bridge;
private boolean update = false;
public LocaleLineImpl(GlobalLineInfo info, SidebarLineHandler handler) {
this.info = info;
this.handler = handler;
this.entries = Collections.singletonList(info.player());
this.bridge = info.bridge.createTeamInfoNMS(this, handler.sidebar().componentTranslator());
bridge.updateTeamPackets(entries);
public LocaleLineImpl(GlobalLineInfo info, SidebarLineHandler handler) {
this.info = info;
this.handler = handler;
this.entries = Collections.singletonList(info.player());
this.bridge = info.bridge.createTeamInfoNMS(this, handler.sidebar().componentTranslator());
bridge.updateTeamPackets(entries);
}
@Override
public GlobalLineInfo info() {
return info;
}
@Override
public void value(Component renderedComponent) {
update = true;
}
@Override
public void updateTeam() {
if (!update) {
return;
}
@Override
public GlobalLineInfo info() {
return info;
}
bridge.updateTeamPackets(entries);
if (handler.sidebar().visible()) bridge.updateTeam(handler.players(LineType.NEW));
update = false;
}
@Override
public void value(Component renderedComponent) {
update = true;
}
@Override
public void sendScore(Collection<Player> players) {
handler.sidebar().sidebarBridge().score(players, info.objectiveScore, info.player());
}
@Override
public void updateTeam() {
if (!update) {
return;
}
@Override
public void show(Collection<Player> players) {
sendScore(players);
bridge.createTeam(players);
}
bridge.updateTeamPackets(entries);
if (handler.sidebar().visible()) bridge.updateTeam(handler.players(LineType.NEW));
update = false;
}
@Override
public void hide(Collection<Player> players) {
handler.sidebar().sidebarBridge().removeLine(players, info.player());
info.bridge.removeTeam(players);
}
@Override
public void sendScore(Collection<Player> players) {
handler.sidebar().sidebarBridge().score(players, info.objectiveScore, info.player());
}
@Override
public Collection<String> entries() {
return entries;
}
@Override
public void show(Collection<Player> players) {
sendScore(players);
bridge.createTeam(players);
}
@Override
public Component displayName() {
return empty();
}
@Override
public void hide(Collection<Player> players) {
handler.sidebar().sidebarBridge().removeLine(players, info.player());
info.bridge.removeTeam(players);
}
@Override
public Component prefix() {
return info.value;
}
@Override
public Collection<String> entries() {
return entries;
}
@Override
public Component displayName() {
return empty();
}
@Override
public Component prefix() {
return info.value;
}
@Override
public Component suffix() {
return empty();
}
@Override
public Component suffix() {
return empty();
}
}
@@ -18,166 +18,166 @@ import java.util.Set;
public class ScoreboardTeamImpl implements ScoreboardTeam {
public final TeamManagerImpl teamManager;
public final String name;
public final TeamNMS<?, ?> nms;
public Collection<TeamInfoImpl> infos;
public boolean closed;
short idCounter = 0;
private TeamInfoImpl globalInfo;
public final TeamManagerImpl teamManager;
public final String name;
public final TeamNMS<?, ?> nms;
public Collection<TeamInfoImpl> infos;
public boolean closed;
short idCounter = 0;
private TeamInfoImpl globalInfo;
public ScoreboardTeamImpl(TeamManagerImpl teamManager, String name) {
this.teamManager = teamManager;
this.name = name;
this.nms = ScoreboardManagerNMS.INSTANCE.createTeamNMS(name);
public ScoreboardTeamImpl(TeamManagerImpl teamManager, String name) {
this.teamManager = teamManager;
this.name = name;
this.nms = ScoreboardManagerNMS.INSTANCE.createTeamNMS(name);
}
public Collection<TeamInfoImpl> teamInfos() {
if (infos == null) {
infos = CollectionProvider.set(1);
}
public Collection<TeamInfoImpl> teamInfos() {
if (infos == null) {
infos = CollectionProvider.set(1);
}
return infos;
}
return infos;
public void update() {
if (infos == null) return;
for (TeamInfoImpl teamInfo : infos) {
teamInfo.update();
}
}
@Override
public @NotNull TeamInfoImpl globalInfo() {
if (globalInfo == null) {
globalInfo = new TeamInfoImpl();
globalInfo.assign(this);
infos.add(globalInfo);
}
public void update() {
if (infos == null) return;
for (TeamInfoImpl teamInfo : infos) {
teamInfo.update();
}
return globalInfo;
}
@Override
public @NotNull String name() {
return name;
}
@Override
public @NotNull TeamManager teamManager() {
return teamManager;
}
@Override
public @NotNull TeamInfoImpl teamInfo(Player player) {
return getTeamInfo(player, true, false);
}
public TeamInfoImpl getTeamInfo(Player player, boolean check, boolean nullable) {
checkDestroyed();
if (check) {
checkPlayer(player);
}
@Override
public @NotNull TeamInfoImpl globalInfo() {
if (globalInfo == null) {
globalInfo = new TeamInfoImpl();
globalInfo.assign(this);
infos.add(globalInfo);
}
return globalInfo;
for (TeamInfoImpl teamInfo : infos) {
if (teamInfo.players.contains(player)) {
return teamInfo;
}
}
@Override
public @NotNull String name() {
return name;
if (nullable) {
return null;
}
@Override
public @NotNull TeamManager teamManager() {
return teamManager;
}
globalInfo().players.add(player);
return globalInfo;
}
@Override
public @NotNull TeamInfoImpl teamInfo(Player player) {
return getTeamInfo(player, true, false);
}
@Override
public @NotNull TeamInfoImpl teamInfo(Player player, @Nullable TeamInfo teamInfo) {
checkDestroyed();
checkPlayer(player);
public TeamInfoImpl getTeamInfo(Player player, boolean check, boolean nullable) {
checkDestroyed();
if (check) {
checkPlayer(player);
}
for (TeamInfoImpl teamInfo : infos) {
if (teamInfo.players.contains(player)) {
return teamInfo;
}
}
if (nullable) {
return null;
}
globalInfo().players.add(player);
return globalInfo;
}
@Override
public @NotNull TeamInfoImpl teamInfo(Player player, @Nullable TeamInfo teamInfo) {
checkDestroyed();
checkPlayer(player);
TeamInfoImpl impl = teamInfo == null ? globalInfo() : (TeamInfoImpl) teamInfo;
TeamInfoImpl oldInfo = getTeamInfo(player, true, true);
if (oldInfo != null) {
if (oldInfo == impl)
return impl;
oldInfo.players.remove(player);
}
if (impl.team() != this)
impl.unassign();
impl.assign(this);
Set<Player> singleton = Collections.singleton(player);
impl.addPlayers(singleton);
if (oldInfo != null) {
impl.nms.updateTeam(singleton);
TeamInfoImpl.syncEntries(singleton, oldInfo, impl);
} else {
impl.nms.createTeam(singleton);
}
TeamInfoImpl impl = teamInfo == null ? globalInfo() : (TeamInfoImpl) teamInfo;
TeamInfoImpl oldInfo = getTeamInfo(player, true, true);
if (oldInfo != null) {
if (oldInfo == impl)
return impl;
oldInfo.players.remove(player);
}
@Override
public boolean closed() {
return closed;
if (impl.team() != this)
impl.unassign();
impl.assign(this);
Set<Player> singleton = Collections.singleton(player);
impl.addPlayers(singleton);
if (oldInfo != null) {
impl.nms.updateTeam(singleton);
TeamInfoImpl.syncEntries(singleton, oldInfo, impl);
} else {
impl.nms.createTeam(singleton);
}
@Override
public void close() {
if (closed) {
return;
return impl;
}
@Override
public boolean closed() {
return closed;
}
@Override
public void close() {
if (closed) {
return;
}
if (infos != null) {
infos.forEach(info -> {
if (info != null && info.team() != null) {
Objects.requireNonNull(info.team()).nms.removeTeam(info.players);
}
if (infos != null) {
infos.forEach(info -> {
if (info != null && info.team() != null) {
Objects.requireNonNull(info.team()).nms.removeTeam(info.players);
}
});
}
teamManager.teams.remove(name);
closed = true;
});
}
teamManager.teams.remove(name);
closed = true;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ScoreboardTeamImpl that = (ScoreboardTeamImpl) o;
return closed == that.closed &&
idCounter == that.idCounter &&
Objects.equals(teamManager, that.teamManager) &&
Objects.equals(name, that.name) &&
Objects.equals(nms, that.nms) &&
Objects.equals(globalInfo, that.globalInfo) &&
Objects.equals(infos, that.infos);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ScoreboardTeamImpl that = (ScoreboardTeamImpl) o;
return closed == that.closed &&
idCounter == that.idCounter &&
Objects.equals(teamManager, that.teamManager) &&
Objects.equals(name, that.name) &&
Objects.equals(nms, that.nms) &&
Objects.equals(globalInfo, that.globalInfo) &&
Objects.equals(infos, that.infos);
}
@Override
public String toString() {
return "ScoreboardTeamImpl{" +
"name='" + name + '\'' +
", destroyed=" + closed +
'}';
}
@Override
public String toString() {
return "ScoreboardTeamImpl{" +
"name='" + name + '\'' +
", destroyed=" + closed +
'}';
}
@Override
public int hashCode() {
return Objects.hash(teamManager, name);
}
@Override
public int hashCode() {
return Objects.hash(teamManager, name);
}
protected void checkDestroyed() {
Preconditions.checkState(!closed, "Team is closed");
}
protected void checkDestroyed() {
Preconditions.checkState(!closed, "Team is closed");
}
protected void checkPlayer(Player player) {
Preconditions.checkNotNull(player, "Player cannot be null");
Preconditions.checkArgument(teamManager.players().contains(player), "Player is not in fillTeamPacket teamManager");
}
protected void checkPlayer(Player player) {
Preconditions.checkNotNull(player, "Player cannot be null");
Preconditions.checkArgument(teamManager.players().contains(player), "Player is not in fillTeamPacket teamManager");
}
}
@@ -22,324 +22,324 @@ import static net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializ
public class TeamInfoImpl implements TeamInfo, ImmutableTeamProperties<Component> {
public final Set<Player> players = Collections.synchronizedSet(CollectionProvider.set(4));
public final Set<String> entries = Collections.synchronizedSet(CollectionProvider.set(4));
private final AtomicBoolean updateTeam = new AtomicBoolean();
public Component displayName = empty(),
prefix = empty(),
suffix = empty();
public boolean allowFriendlyFire, canSeeFriendlyInvisibles;
public byte nameTagVisibility = NameTagVisibility.ALWAYS.id(),
collisionRule = CollisionRule.ALWAYS.id();
public char playerColor = '\0';
public TeamNMS.TeamInfoNMS<Component> nms;
private ScoreboardTeamImpl team;
private List<String> addEntries, removeEntries;
private short id;
private volatile boolean updateEntries;
public final Set<Player> players = Collections.synchronizedSet(CollectionProvider.set(4));
public final Set<String> entries = Collections.synchronizedSet(CollectionProvider.set(4));
private final AtomicBoolean updateTeam = new AtomicBoolean();
public Component displayName = empty(),
prefix = empty(),
suffix = empty();
public boolean allowFriendlyFire, canSeeFriendlyInvisibles;
public byte nameTagVisibility = NameTagVisibility.ALWAYS.id(),
collisionRule = CollisionRule.ALWAYS.id();
public char playerColor = '\0';
public TeamNMS.TeamInfoNMS<Component> nms;
private ScoreboardTeamImpl team;
private List<String> addEntries, removeEntries;
private short id;
private volatile boolean updateEntries;
public TeamInfoImpl() {
public TeamInfoImpl() {
}
public static void syncEntries(Collection<Player> players, TeamInfoImpl old, TeamInfoImpl info) {
if (old != null && !old.entries.isEmpty()) {
List<String> entries = new ArrayList<>(old.entries);
entries.removeAll(info.entries);
if (!entries.isEmpty())
info.nms.removeEntries(players, entries);
entries = new ArrayList<>(info.entries);
entries.removeAll(old.entries);
if (!entries.isEmpty())
info.nms.addEntries(players, entries);
} else if (!info.entries.isEmpty()) {
info.nms.addEntries(players, info.entries);
}
}
public void assign(ScoreboardTeamImpl team) {
if (this.team == team) return;
this.team = team;
this.id = team.idCounter++;
team.teamInfos().add(this);
nms = team.nms.createTeamInfoNMS(this, team.teamManager.componentTranslator());
nms.updateTeamPackets(entries);
}
@Override
public ScoreboardTeamImpl team() {
if (team == null) throw new IllegalStateException("Not assigned to a team");
return team;
}
@Override
public boolean isAssigned() {
return team != null;
}
@Override
public synchronized void unassign() {
if (!isAssigned()) return;
Preconditions.checkState(team.globalInfo() != this, "Cannot unnasign a global TeamInfo");
team.teamInfos().remove(this);
TeamInfoImpl global = team.globalInfo();
global.addPlayers(players);
global.nms.updateTeam(players);
syncEntries(players, this, global);
players.clear();
team = null;
}
@Override
public @NotNull Collection<String> entries() {
return Collections.unmodifiableSet(entries);
}
@Override
public boolean addEntry(@NotNull String entry) {
Preconditions.checkNotNull(entry);
synchronized (entries) {
if (entries.add(entry)) {
entries.add(entry);
if (addEntries == null) addEntries = CollectionProvider.list(1);
addEntries.add(entry);
if (removeEntries != null) removeEntries.remove(entry);
updateEntries();
return true;
}
return false;
}
}
@Override
public boolean removeEntry(@NotNull String entry) {
Preconditions.checkNotNull(entry);
synchronized (entries) {
if (entries.remove(entry)) {
entries.remove(entry);
if (removeEntries == null) removeEntries = CollectionProvider.list(1);
removeEntries.add(entry);
if (addEntries != null) addEntries.remove(entry);
updateEntries();
return true;
}
return false;
}
}
@Override
public @NotNull Component displayName() {
return displayName;
}
@Override
public void displayName(@NotNull Component displayName) {
Preconditions.checkNotNull(displayName);
if (!Objects.equals(displayName, this.displayName)) {
this.displayName = displayName;
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public @NotNull Component prefix() {
return prefix;
}
@Override
public void prefix(@NotNull Component prefix) {
Preconditions.checkNotNull(prefix);
if ((!Objects.equals(prefix, this.prefix))) {
this.prefix = prefix;
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public @NotNull Component suffix() {
return suffix;
}
@Override
public void suffix(@NotNull Component suffix) {
Preconditions.checkNotNull(suffix);
if (!Objects.equals(suffix, this.suffix)) {
this.suffix = suffix;
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public boolean friendlyFire() {
return allowFriendlyFire;
}
@Override
public void friendlyFire(boolean allowFriendlyFire) {
if (this.allowFriendlyFire != allowFriendlyFire) {
this.allowFriendlyFire = allowFriendlyFire;
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public void canSeeFriendlyInvisibles(boolean canSeeFriendlyInvisibles) {
if (this.canSeeFriendlyInvisibles != canSeeFriendlyInvisibles) {
this.canSeeFriendlyInvisibles = canSeeFriendlyInvisibles;
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public boolean canSeeFriendlyInvisibles() {
return canSeeFriendlyInvisibles;
}
@Override
public @NotNull NameTagVisibility nameTagVisibility() {
return NameTagVisibility.of(nameTagVisibility);
}
@Override
public void nameTagVisibility(@NotNull NameTagVisibility nameTagVisibility) {
Preconditions.checkNotNull(nameTagVisibility);
if (this.nameTagVisibility != nameTagVisibility.id()) {
this.nameTagVisibility = nameTagVisibility.id();
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public @NotNull CollisionRule collisionRule() {
return CollisionRule.of(collisionRule);
}
@Override
public void collisionRule(@NotNull CollisionRule collisionRule) {
Preconditions.checkNotNull(collisionRule);
if (this.collisionRule != collisionRule.id()) {
this.collisionRule = collisionRule.id();
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public NamedTextColor playerColor() {
if (playerColor == '\0') return null;
return (NamedTextColor) requireNonNull(parseChar(playerColor)).color();
}
@Override
public void playerColor(NamedTextColor color) {
if (color == null) {
playerColor = '\0';
return;
}
public static void syncEntries(Collection<Player> players, TeamInfoImpl old, TeamInfoImpl info) {
if (old != null && !old.entries.isEmpty()) {
List<String> entries = new ArrayList<>(old.entries);
entries.removeAll(info.entries);
if (!entries.isEmpty())
info.nms.removeEntries(players, entries);
char c = LegacyFormatUtil.getChar(color);
if (this.playerColor != c) {
this.playerColor = c;
updateTeam.set(true);
scheduleUpdate();
}
}
entries = new ArrayList<>(info.entries);
entries.removeAll(old.entries);
if (!entries.isEmpty())
info.nms.addEntries(players, entries);
} else if (!info.entries.isEmpty()) {
info.nms.addEntries(players, info.entries);
}
public void scheduleUpdate() {
team.teamManager.update.set(true);
}
public void update() {
if (updateTeam.getAndSet(false)) {
nms.updateTeamPackets(entries);
if (!players.isEmpty()) {
nms.updateTeam(players);
}
}
public void assign(ScoreboardTeamImpl team) {
if (this.team == team) return;
this.team = team;
this.id = team.idCounter++;
team.teamInfos().add(this);
nms = team.nms.createTeamInfoNMS(this, team.teamManager.componentTranslator());
nms.updateTeamPackets(entries);
}
@Override
public ScoreboardTeamImpl team() {
if (team == null) throw new IllegalStateException("Not assigned to a team");
return team;
}
@Override
public boolean isAssigned() {
return team != null;
}
@Override
public synchronized void unassign() {
if (!isAssigned()) return;
Preconditions.checkState(team.globalInfo() != this, "Cannot unnasign a global TeamInfo");
team.teamInfos().remove(this);
TeamInfoImpl global = team.globalInfo();
global.addPlayers(players);
global.nms.updateTeam(players);
syncEntries(players, this, global);
players.clear();
team = null;
}
@Override
public @NotNull Collection<String> entries() {
return Collections.unmodifiableSet(entries);
}
@Override
public boolean addEntry(@NotNull String entry) {
Preconditions.checkNotNull(entry);
synchronized (entries) {
if (entries.add(entry)) {
entries.add(entry);
if (addEntries == null) addEntries = CollectionProvider.list(1);
addEntries.add(entry);
if (removeEntries != null) removeEntries.remove(entry);
updateEntries();
return true;
}
return false;
}
}
@Override
public boolean removeEntry(@NotNull String entry) {
Preconditions.checkNotNull(entry);
synchronized (entries) {
if (entries.remove(entry)) {
entries.remove(entry);
if (removeEntries == null) removeEntries = CollectionProvider.list(1);
removeEntries.add(entry);
if (addEntries != null) addEntries.remove(entry);
updateEntries();
return true;
}
return false;
}
}
@Override
public @NotNull Component displayName() {
return displayName;
}
@Override
public void displayName(@NotNull Component displayName) {
Preconditions.checkNotNull(displayName);
if (!Objects.equals(displayName, this.displayName)) {
this.displayName = displayName;
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public @NotNull Component prefix() {
return prefix;
}
@Override
public void prefix(@NotNull Component prefix) {
Preconditions.checkNotNull(prefix);
if ((!Objects.equals(prefix, this.prefix))) {
this.prefix = prefix;
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public @NotNull Component suffix() {
return suffix;
}
@Override
public void suffix(@NotNull Component suffix) {
Preconditions.checkNotNull(suffix);
if (!Objects.equals(suffix, this.suffix)) {
this.suffix = suffix;
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public boolean friendlyFire() {
return allowFriendlyFire;
}
@Override
public void friendlyFire(boolean allowFriendlyFire) {
if (this.allowFriendlyFire != allowFriendlyFire) {
this.allowFriendlyFire = allowFriendlyFire;
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public void canSeeFriendlyInvisibles(boolean canSeeFriendlyInvisibles) {
if (this.canSeeFriendlyInvisibles != canSeeFriendlyInvisibles) {
this.canSeeFriendlyInvisibles = canSeeFriendlyInvisibles;
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public boolean canSeeFriendlyInvisibles() {
return canSeeFriendlyInvisibles;
}
@Override
public @NotNull NameTagVisibility nameTagVisibility() {
return NameTagVisibility.of(nameTagVisibility);
}
@Override
public void nameTagVisibility(@NotNull NameTagVisibility nameTagVisibility) {
Preconditions.checkNotNull(nameTagVisibility);
if (this.nameTagVisibility != nameTagVisibility.id()) {
this.nameTagVisibility = nameTagVisibility.id();
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public @NotNull CollisionRule collisionRule() {
return CollisionRule.of(collisionRule);
}
@Override
public void collisionRule(@NotNull CollisionRule collisionRule) {
Preconditions.checkNotNull(collisionRule);
if (this.collisionRule != collisionRule.id()) {
this.collisionRule = collisionRule.id();
updateTeam.set(true);
scheduleUpdate();
}
}
@Override
public NamedTextColor playerColor() {
if (playerColor == '\0') return null;
return (NamedTextColor) requireNonNull(parseChar(playerColor)).color();
}
@Override
public void playerColor(NamedTextColor color) {
if (color == null) {
playerColor = '\0';
return;
}
char c = LegacyFormatUtil.getChar(color);
if (this.playerColor != c) {
this.playerColor = c;
updateTeam.set(true);
scheduleUpdate();
}
}
public void scheduleUpdate() {
team.teamManager.update.set(true);
}
public void update() {
if (updateTeam.getAndSet(false)) {
nms.updateTeamPackets(entries);
if (!players.isEmpty()) {
nms.updateTeam(players);
}
}
if (updateEntries) {
synchronized (entries) {
if (!players.isEmpty()) {
if (addEntries != null && !addEntries.isEmpty()) {
nms.addEntries(players, addEntries);
addEntries.clear();
}
if (removeEntries != null && !removeEntries.isEmpty()) {
nms.removeEntries(players, removeEntries);
removeEntries.clear();
}
}
updateEntries = false;
}
}
}
public void addPlayers(Collection<Player> players) {
this.players.addAll(players);
}
private void updateEntries() {
if (updateEntries) return;
if (updateEntries) {
synchronized (entries) {
if (!players.isEmpty()) {
updateEntries = true;
scheduleUpdate();
} else {
if (addEntries != null) addEntries.clear();
if (removeEntries != null) removeEntries.clear();
if (addEntries != null && !addEntries.isEmpty()) {
nms.addEntries(players, addEntries);
addEntries.clear();
}
if (removeEntries != null && !removeEntries.isEmpty()) {
nms.removeEntries(players, removeEntries);
removeEntries.clear();
}
}
updateEntries = false;
}
}
}
@Override
public int hashCode() {
return Objects.hash(team, id);
public void addPlayers(Collection<Player> players) {
this.players.addAll(players);
}
private void updateEntries() {
if (updateEntries) return;
if (!players.isEmpty()) {
updateEntries = true;
scheduleUpdate();
} else {
if (addEntries != null) addEntries.clear();
if (removeEntries != null) removeEntries.clear();
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@Override
public int hashCode() {
return Objects.hash(team, id);
}
TeamInfoImpl teamInfo = (TeamInfoImpl) o;
return allowFriendlyFire == teamInfo.allowFriendlyFire &&
canSeeFriendlyInvisibles == teamInfo.canSeeFriendlyInvisibles &&
Objects.equals(players, teamInfo.players) &&
Objects.equals(entries, teamInfo.entries) &&
Objects.equals(addEntries, teamInfo.addEntries) &&
Objects.equals(removeEntries, teamInfo.removeEntries) &&
Objects.equals(displayName, teamInfo.displayName) &&
Objects.equals(prefix, teamInfo.prefix) &&
Objects.equals(suffix, teamInfo.suffix) &&
nameTagVisibility == teamInfo.nameTagVisibility &&
Objects.equals(nms, teamInfo.nms) &&
Objects.equals(team, teamInfo.team);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@Override
public String toString() {
return "TeamInfo{" +
"players=" + players +
", entries=" + entries +
", team=" + team +
'}';
}
TeamInfoImpl teamInfo = (TeamInfoImpl) o;
return allowFriendlyFire == teamInfo.allowFriendlyFire &&
canSeeFriendlyInvisibles == teamInfo.canSeeFriendlyInvisibles &&
Objects.equals(players, teamInfo.players) &&
Objects.equals(entries, teamInfo.entries) &&
Objects.equals(addEntries, teamInfo.addEntries) &&
Objects.equals(removeEntries, teamInfo.removeEntries) &&
Objects.equals(displayName, teamInfo.displayName) &&
Objects.equals(prefix, teamInfo.prefix) &&
Objects.equals(suffix, teamInfo.suffix) &&
nameTagVisibility == teamInfo.nameTagVisibility &&
Objects.equals(nms, teamInfo.nms) &&
Objects.equals(team, teamInfo.team);
}
@Override
public String toString() {
return "TeamInfo{" +
"players=" + players +
", entries=" + entries +
", team=" + team +
'}';
}
}
@@ -21,227 +21,227 @@ import java.util.function.Function;
public class TeamManagerImpl implements TeamManager {
private static int idCounter = 0;
public final Map<String, ScoreboardTeamImpl> teams = CollectionProvider.map(5);
public final AtomicBoolean update = new AtomicBoolean();
private final ScoreboardManagerImpl scoreboardManager;
private final ComponentTranslator componentTranslator;
private final Set<Player> players = CollectionProvider.set(4);
private final int id = idCounter++;
private boolean closed;
private static int idCounter = 0;
public final Map<String, ScoreboardTeamImpl> teams = CollectionProvider.map(5);
public final AtomicBoolean update = new AtomicBoolean();
private final ScoreboardManagerImpl scoreboardManager;
private final ComponentTranslator componentTranslator;
private final Set<Player> players = CollectionProvider.set(4);
private final int id = idCounter++;
private boolean closed;
public TeamManagerImpl(ScoreboardManagerImpl scoreboardManager, ComponentTranslator componentTranslator) {
this.scoreboardManager = Objects.requireNonNull(scoreboardManager);
this.componentTranslator = Objects.requireNonNull(componentTranslator);
public TeamManagerImpl(ScoreboardManagerImpl scoreboardManager, ComponentTranslator componentTranslator) {
this.scoreboardManager = Objects.requireNonNull(scoreboardManager);
this.componentTranslator = Objects.requireNonNull(componentTranslator);
}
public void update() {
if (!update.getAndSet(false)) return;
ImmutableList<ScoreboardTeamImpl> list;
synchronized (teams) {
list = ImmutableList.copyOf(teams.values());
}
public void update() {
if (!update.getAndSet(false)) return;
for (ScoreboardTeamImpl team : list) {
team.update();
}
}
ImmutableList<ScoreboardTeamImpl> list;
synchronized (teams) {
list = ImmutableList.copyOf(teams.values());
@Override
public @NotNull ScoreboardManager scoreboardManager() {
return scoreboardManager;
}
@Override
public @NotNull Collection<Player> players() {
return Collections.unmodifiableCollection(players);
}
@Override
public @NotNull ComponentTranslator componentTranslator() {
return componentTranslator;
}
@Override
public @NotNull Collection<ScoreboardTeam> teams() {
synchronized (teams) {
return Collections.unmodifiableCollection(teams.values());
}
}
@Override
public @Nullable ScoreboardTeamImpl team(@NotNull String name) {
checkDestroyed();
checkTeamName(name);
synchronized (teams) {
return teams.get(name);
}
}
@Override
public boolean teamExists(String name) {
return team(name) != null;
}
@Override
public @NotNull ScoreboardTeam createIfAbsent(@NotNull String name, @Nullable BiFunction<Player, ScoreboardTeam, TeamInfo> teamInfoFunction) {
checkDestroyed();
ScoreboardTeamImpl team = team(name);
if (team != null)
return team;
team = new ScoreboardTeamImpl(this, name);
synchronized (teams) {
teams.put(name, team);
}
for (Player player : players) {
team.teamInfo(player, teamInfoFunction == null ? null : teamInfoFunction.apply(player, team));
}
return team;
}
@Override
public boolean addPlayer(@NotNull Player player, @Nullable Function<ScoreboardTeam, TeamInfo> teamInfoFunction) {
checkDestroyed();
checkPlayer(player);
if (players.add(player)) {
ScoreboardManagerProviderImpl.instance().teamManagerMap.put(player, this);
for (ScoreboardTeamImpl team : teams.values()) {
TeamInfoImpl info = teamInfoFunction == null ? team.globalInfo() : (TeamInfoImpl) teamInfoFunction.apply(team);
info = info == null ? team.globalInfo() : info;
Collection<Player> singleton = Collections.singletonList(player);
info.assign(team);
info.addPlayers(singleton);
info.nms.createTeam(singleton);
}
return true;
}
return false;
}
@Override
public @NotNull Collection<Player> addPlayers(@NotNull Collection<Player> players, @Nullable Function<ScoreboardTeam, TeamInfo> teamInfoFunction) {
checkDestroyed();
Preconditions.checkNotNull(players, "Players cannot be null");
List<Player> filteredPlayers = new ArrayList<>(players.size());
for (Player player : players) {
checkPlayer(player);
if (this.players.add(player)) {
filteredPlayers.add(player);
ScoreboardManagerProviderImpl.instance().teamManagerMap.put(player, this);
}
}
if (!filteredPlayers.isEmpty()) {
for (ScoreboardTeamImpl team : teams.values()) {
TeamInfoImpl info = teamInfoFunction == null ? team.globalInfo() : (TeamInfoImpl) teamInfoFunction.apply(team);
info = info == null ? team.globalInfo() : info;
info.assign(team);
info.players.addAll(players);
info.nms.createTeam(filteredPlayers);
}
}
return filteredPlayers;
}
@Override
public boolean removePlayer(@NotNull Player player) {
checkDestroyed();
checkPlayer(player);
if (players.remove(player)) {
Collection<Player> singleton = Collections.singleton(player);
for (ScoreboardTeamImpl team : teams.values()) {
TeamInfoImpl info = team.getTeamInfo(player, false, true);
if (info != null) {
info.players.remove(player);
team.nms.removeTeam(singleton);
}
}
ScoreboardManagerProviderImpl.instance().teamManagerMap.remove(player);
return true;
}
return false;
}
for (ScoreboardTeamImpl team : list) {
team.update();
@Override
public void removePlayers(@NotNull Collection<Player> players) {
checkDestroyed();
Preconditions.checkNotNull(players);
List<Player> filteredPlayers = CollectionProvider.list(players.size());
for (Player player : players) {
if (!this.players.remove(player)) continue;
ScoreboardManagerProviderImpl.instance().teamManagerMap.remove(player);
for (ScoreboardTeamImpl team : teams.values()) {
TeamInfoImpl info = team.getTeamInfo(player, false, true);
if (info != null) {
info.players.remove(player);
filteredPlayers.add(player);
}
}
}
@Override
public @NotNull ScoreboardManager scoreboardManager() {
return scoreboardManager;
for (ScoreboardTeamImpl team : teams.values()) {
team.nms.removeTeam(filteredPlayers);
}
}
@Override
public @NotNull Collection<Player> players() {
return Collections.unmodifiableCollection(players);
@Override
public boolean closed() {
return closed;
}
@Override
public void close() {
if (!closed) {
ImmutableList.copyOf(teams.values()).forEach(ScoreboardTeam::close);
if (scoreboardManager.teamManagers != null) {
scoreboardManager.teamManagers.remove(this);
}
for (Player player : players) {
ScoreboardManagerProviderImpl.instance().teamManagerMap.remove(player);
}
players.clear(); // Prevent a memory leak
closed = true;
}
}
@Override
public @NotNull ComponentTranslator componentTranslator() {
return componentTranslator;
}
@Override
public String toString() {
return "TeamManagerImpl{" +
"teams=" + teams +
", scoreboardManager=" + scoreboardManager +
", players=" + players +
", closed=" + closed +
'}';
}
@Override
public @NotNull Collection<ScoreboardTeam> teams() {
synchronized (teams) {
return Collections.unmodifiableCollection(teams.values());
}
}
@Override
public int hashCode() {
return Objects.hash(scoreboardManager, id);
}
@Override
public @Nullable ScoreboardTeamImpl team(@NotNull String name) {
checkDestroyed();
checkTeamName(name);
protected void checkDestroyed() {
Preconditions.checkState(!closed, "Team manager is closed");
}
synchronized (teams) {
return teams.get(name);
}
}
protected void checkTeamName(String name) {
Preconditions.checkNotNull(name, "Team name cannot be null");
Preconditions.checkArgument(!name.isEmpty(), "Team name cannot be empty");
}
@Override
public boolean teamExists(String name) {
return team(name) != null;
}
@Override
public @NotNull ScoreboardTeam createIfAbsent(@NotNull String name, @Nullable BiFunction<Player, ScoreboardTeam, TeamInfo> teamInfoFunction) {
checkDestroyed();
ScoreboardTeamImpl team = team(name);
if (team != null)
return team;
team = new ScoreboardTeamImpl(this, name);
synchronized (teams) {
teams.put(name, team);
}
for (Player player : players) {
team.teamInfo(player, teamInfoFunction == null ? null : teamInfoFunction.apply(player, team));
}
return team;
}
@Override
public boolean addPlayer(@NotNull Player player, @Nullable Function<ScoreboardTeam, TeamInfo> teamInfoFunction) {
checkDestroyed();
checkPlayer(player);
if (players.add(player)) {
ScoreboardManagerProviderImpl.instance().teamManagerMap.put(player, this);
for (ScoreboardTeamImpl team : teams.values()) {
TeamInfoImpl info = teamInfoFunction == null ? team.globalInfo() : (TeamInfoImpl) teamInfoFunction.apply(team);
info = info == null ? team.globalInfo() : info;
Collection<Player> singleton = Collections.singletonList(player);
info.assign(team);
info.addPlayers(singleton);
info.nms.createTeam(singleton);
}
return true;
}
return false;
}
@Override
public @NotNull Collection<Player> addPlayers(@NotNull Collection<Player> players, @Nullable Function<ScoreboardTeam, TeamInfo> teamInfoFunction) {
checkDestroyed();
Preconditions.checkNotNull(players, "Players cannot be null");
List<Player> filteredPlayers = new ArrayList<>(players.size());
for (Player player : players) {
checkPlayer(player);
if (this.players.add(player)) {
filteredPlayers.add(player);
ScoreboardManagerProviderImpl.instance().teamManagerMap.put(player, this);
}
}
if (!filteredPlayers.isEmpty()) {
for (ScoreboardTeamImpl team : teams.values()) {
TeamInfoImpl info = teamInfoFunction == null ? team.globalInfo() : (TeamInfoImpl) teamInfoFunction.apply(team);
info = info == null ? team.globalInfo() : info;
info.assign(team);
info.players.addAll(players);
info.nms.createTeam(filteredPlayers);
}
}
return filteredPlayers;
}
@Override
public boolean removePlayer(@NotNull Player player) {
checkDestroyed();
checkPlayer(player);
if (players.remove(player)) {
Collection<Player> singleton = Collections.singleton(player);
for (ScoreboardTeamImpl team : teams.values()) {
TeamInfoImpl info = team.getTeamInfo(player, false, true);
if (info != null) {
info.players.remove(player);
team.nms.removeTeam(singleton);
}
}
ScoreboardManagerProviderImpl.instance().teamManagerMap.remove(player);
return true;
}
return false;
}
@Override
public void removePlayers(@NotNull Collection<Player> players) {
checkDestroyed();
Preconditions.checkNotNull(players);
List<Player> filteredPlayers = CollectionProvider.list(players.size());
for (Player player : players) {
if (!this.players.remove(player)) continue;
ScoreboardManagerProviderImpl.instance().teamManagerMap.remove(player);
for (ScoreboardTeamImpl team : teams.values()) {
TeamInfoImpl info = team.getTeamInfo(player, false, true);
if (info != null) {
info.players.remove(player);
filteredPlayers.add(player);
}
}
}
for (ScoreboardTeamImpl team : teams.values()) {
team.nms.removeTeam(filteredPlayers);
}
}
@Override
public boolean closed() {
return closed;
}
@Override
public void close() {
if (!closed) {
ImmutableList.copyOf(teams.values()).forEach(ScoreboardTeam::close);
if (scoreboardManager.teamManagers != null) {
scoreboardManager.teamManagers.remove(this);
}
for (Player player : players) {
ScoreboardManagerProviderImpl.instance().teamManagerMap.remove(player);
}
players.clear(); // Prevent a memory leak
closed = true;
}
}
@Override
public String toString() {
return "TeamManagerImpl{" +
"teams=" + teams +
", scoreboardManager=" + scoreboardManager +
", players=" + players +
", closed=" + closed +
'}';
}
@Override
public int hashCode() {
return Objects.hash(scoreboardManager, id);
}
protected void checkDestroyed() {
Preconditions.checkState(!closed, "Team manager is closed");
}
protected void checkTeamName(String name) {
Preconditions.checkNotNull(name, "Team name cannot be null");
Preconditions.checkArgument(!name.isEmpty(), "Team name cannot be empty");
}
protected void checkPlayer(Player player) {
Preconditions.checkNotNull(player, "Player cannot be null");
TeamManagerImpl teamManager = ScoreboardManagerProviderImpl.instance().teamManager(player);
if (teamManager != this && teamManager != null)
throw new IllegalArgumentException("Player already has a TeamManager which is owned by " + teamManager.scoreboardManager().plugin().getName());
}
protected void checkPlayer(Player player) {
Preconditions.checkNotNull(player, "Player cannot be null");
TeamManagerImpl teamManager = ScoreboardManagerProviderImpl.instance().teamManager(player);
if (teamManager != this && teamManager != null)
throw new IllegalArgumentException("Player already has a TeamManager which is owned by " + teamManager.scoreboardManager().plugin().getName());
}
}
@@ -10,25 +10,25 @@ import java.util.logging.Logger;
public class TeamUpdaterTask extends BukkitRunnable {
private final Logger logger;
private final Set<TeamManagerImpl> teamManagers;
private final Logger logger;
private final Set<TeamManagerImpl> teamManagers;
public TeamUpdaterTask(ScoreboardManagerImpl manager) {
Preconditions.checkNotNull(manager);
this.logger = manager.plugin().getLogger();
this.teamManagers = manager.teamManagers;
public TeamUpdaterTask(ScoreboardManagerImpl manager) {
Preconditions.checkNotNull(manager);
this.logger = manager.plugin().getLogger();
this.teamManagers = manager.teamManagers;
runTaskTimerAsynchronously(manager.plugin(), 1, 1);
}
@Override
public void run() {
for (TeamManagerImpl teamManager : teamManagers) {
try {
teamManager.update();
} catch (Exception e) {
logger.log(Level.WARNING, "Exception caught when updating TeamManager", e);
}
}
runTaskTimerAsynchronously(manager.plugin(), 1, 1);
}
@Override
public void run() {
for (TeamManagerImpl teamManager : teamManagers) {
try {
teamManager.update();
} catch (Exception e) {
logger.log(Level.WARNING, "Exception caught when updating TeamManager", e);
}
}
}
}
+5 -5
View File
@@ -1,8 +1,8 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven("https://papermc.io/repo/repository/maven-public/")
}
repositories {
gradlePluginPortal()
maven("https://papermc.io/repo/repository/maven-public/")
}
}
rootProject.name = "scoreboard-library"
@@ -18,4 +18,4 @@ include(":v1_18_R2")
project(":v1_18_R2").projectDir = file("versions/v1_18_R2")
include(":v1_8_R3")
project(":v1_8_R3").projectDir = file("versions/v1_8_R3")
project(":v1_8_R3").projectDir = file("versions/v1_8_R3")
+14 -14
View File
@@ -1,26 +1,26 @@
plugins {
id("net.megavex.scoreboardlibrary.java-conventions")
id("net.minecrell.plugin-yml.bukkit") version "0.5.0"
id("com.github.johnrengelman.shadow") version "7.1.0"
id("net.megavex.scoreboardlibrary.java-conventions")
id("net.minecrell.plugin-yml.bukkit") version "0.5.0"
id("com.github.johnrengelman.shadow") version "7.1.0"
}
dependencies {
api(project(":implementation"))
api(project(":implementation"))
implementation(project(":v1_8_R3"))
implementation(project(":v1_18_R2"))
implementation(project(":v1_8_R3"))
implementation(project(":v1_18_R2"))
}
bukkit {
name = "ScoreboardLibrary"
main = "net.megavex.scoreboardlibrary.plugin.ScoreboardLibraryPlugin"
apiVersion = "1.18"
description = "https://github.com/MegavexNetwork/scoreboard-library"
author = "VytskaLT"
name = "ScoreboardLibrary"
main = "net.megavex.scoreboardlibrary.plugin.ScoreboardLibraryPlugin"
apiVersion = "1.18"
description = "https://github.com/MegavexNetwork/scoreboard-library"
author = "VytskaLT"
}
tasks {
build {
dependsOn(shadowJar)
}
build {
dependsOn(shadowJar)
}
}
@@ -8,18 +8,18 @@ import java.util.logging.Level;
public class ScoreboardLibraryPlugin extends JavaPlugin {
@Override
public void onEnable() {
try {
ScoreboardLibraryImplementation.init();
} catch (ScoreboardLibraryLoadException e) {
getLogger().log(Level.SEVERE, "Couldn't load ScoreboardLibrary", e);
getServer().getPluginManager().disablePlugin(this);
}
@Override
public void onEnable() {
try {
ScoreboardLibraryImplementation.init();
} catch (ScoreboardLibraryLoadException e) {
getLogger().log(Level.SEVERE, "Couldn't load ScoreboardLibrary", e);
getServer().getPluginManager().disablePlugin(this);
}
}
@Override
public void onDisable() {
ScoreboardLibraryImplementation.close();
}
@Override
public void onDisable() {
ScoreboardLibraryImplementation.close();
}
}
+4 -4
View File
@@ -1,11 +1,11 @@
plugins {
id("net.megavex.scoreboardlibrary.publish-conventions")
id("net.megavex.scoreboardlibrary.publish-conventions")
}
dependencies {
api(project(":api"))
api(project(":api"))
}
tasks.withType<JavaCompile> {
options.compilerArgs.add("-XDignore.symbol.file")
}
options.compilerArgs.add("-XDignore.symbol.file")
}
@@ -10,47 +10,47 @@ import java.util.Collections;
public interface ImmutableTeamProperties<T> {
default Collection<String> entries() {
return Collections.emptySet();
default Collection<String> entries() {
return Collections.emptySet();
}
T displayName();
T prefix();
T suffix();
default boolean friendlyFire() {
return false;
}
default boolean canSeeFriendlyInvisibles() {
return false;
}
default NameTagVisibility nameTagVisibility() {
return NameTagVisibility.ALWAYS;
}
default CollisionRule collisionRule() {
return CollisionRule.ALWAYS;
}
@Nullable
default NamedTextColor playerColor() {
return null;
}
default int packOptions() {
int options = 0;
if (this.friendlyFire()) {
options |= 1;
}
T displayName();
T prefix();
T suffix();
default boolean friendlyFire() {
return false;
if (this.canSeeFriendlyInvisibles()) {
options |= 2;
}
default boolean canSeeFriendlyInvisibles() {
return false;
}
default NameTagVisibility nameTagVisibility() {
return NameTagVisibility.ALWAYS;
}
default CollisionRule collisionRule() {
return CollisionRule.ALWAYS;
}
@Nullable
default NamedTextColor playerColor() {
return null;
}
default int packOptions() {
int options = 0;
if (this.friendlyFire()) {
options |= 1;
}
if (this.canSeeFriendlyInvisibles()) {
options |= 2;
}
return options;
}
return options;
}
}
@@ -14,64 +14,64 @@ import java.util.function.Function;
public abstract class ScoreboardManagerNMS<P> {
public static ScoreboardManagerNMS<?> INSTANCE;
public final String objectiveName = "_s" + RandomStringUtils.randomAlphanumeric(5);
public static ScoreboardManagerNMS<?> INSTANCE;
public final String objectiveName = "_s" + RandomStringUtils.randomAlphanumeric(5);
public ScoreboardManagerNMS() {
Preconditions.checkState(INSTANCE == null);
INSTANCE = this;
}
public ScoreboardManagerNMS() {
Preconditions.checkState(INSTANCE == null);
INSTANCE = this;
}
public static <P> void sendLocalePackets(
Locale specificLocale,
ScoreboardManagerNMS<P> nms,
Collection<Player> players,
Function<Locale, P> packetFunction
) {
if (players.isEmpty()) return;
public static <P> void sendLocalePackets(
Locale specificLocale,
ScoreboardManagerNMS<P> nms,
Collection<Player> players,
Function<Locale, P> packetFunction
) {
if (players.isEmpty()) return;
if (specificLocale != null) {
P packet = packetFunction.apply(specificLocale);
nms.sendPacket(players, packet);
} else if (players.size() == 1) {
Player player = players.iterator().next();
P packet = packetFunction.apply(LocaleUtilities.getLocaleOfPlayer(player));
nms.sendPacket(player, packet);
} else {
Map<Locale, P> map = CollectionProvider.map(1);
for (Player player : players) {
Locale locale = LocaleUtilities.getLocaleOfPlayer(player);
P packet = map.get(locale);
if (packet == null) {
map.put(locale, packetFunction.apply(locale));
}
nms.sendPacket(player, packet);
}
if (specificLocale != null) {
P packet = packetFunction.apply(specificLocale);
nms.sendPacket(players, packet);
} else if (players.size() == 1) {
Player player = players.iterator().next();
P packet = packetFunction.apply(LocaleUtilities.getLocaleOfPlayer(player));
nms.sendPacket(player, packet);
} else {
Map<Locale, P> map = CollectionProvider.map(1);
for (Player player : players) {
Locale locale = LocaleUtilities.getLocaleOfPlayer(player);
P packet = map.get(locale);
if (packet == null) {
map.put(locale, packetFunction.apply(locale));
}
nms.sendPacket(player, packet);
}
}
}
// Sidebar
// Sidebar
public abstract SidebarNMS<P, ?> createSidebarNMS(Sidebar sidebar);
public abstract SidebarNMS<P, ?> createSidebarNMS(Sidebar sidebar);
public abstract void displaySidebar(Iterable<Player> players);
public abstract void displaySidebar(Iterable<Player> players);
public abstract void removeSidebar(Iterable<Player> players);
public abstract void removeSidebar(Iterable<Player> players);
// Team
// Team
public abstract TeamNMS<?, ?> createTeamNMS(String teamName);
public abstract TeamNMS<?, ?> createTeamNMS(String teamName);
public abstract boolean isLegacy(Player player);
public abstract boolean isLegacy(Player player);
// Packet
// Packet
public abstract void sendPacket(Player players, P packet);
public abstract void sendPacket(Player players, P packet);
public final void sendPacket(Iterable<Player> players, P packet) {
for (Player player : players) {
sendPacket(player, packet);
}
public final void sendPacket(Iterable<Player> players, P packet) {
for (Player player : players) {
sendPacket(player, packet);
}
}
}
@@ -8,27 +8,27 @@ import java.util.Collection;
public abstract class SidebarNMS<P, T extends ScoreboardManagerNMS<P>> {
protected final T impl;
protected final Sidebar sidebar;
protected final T impl;
protected final Sidebar sidebar;
public SidebarNMS(T impl, Sidebar sidebar) {
this.impl = impl;
this.sidebar = sidebar;
}
public SidebarNMS(T impl, Sidebar sidebar) {
this.impl = impl;
this.sidebar = sidebar;
}
public abstract void updateTitle(Component displayName);
public abstract void updateTitle(Component displayName);
public void create(Collection<Player> players) {
sendObjectivePacket(players, true);
}
public void create(Collection<Player> players) {
sendObjectivePacket(players, true);
}
public void update(Collection<Player> players) {
sendObjectivePacket(players, false);
}
public void update(Collection<Player> players) {
sendObjectivePacket(players, false);
}
protected abstract void sendObjectivePacket(Collection<Player> players, boolean create);
protected abstract void sendObjectivePacket(Collection<Player> players, boolean create);
public abstract void removeLine(Collection<Player> players, String line);
public abstract void removeLine(Collection<Player> players, String line);
public abstract void score(Collection<Player> players, int score, String line);
public abstract void score(Collection<Player> players, int score, String line);
}
@@ -8,47 +8,47 @@ import java.util.Collection;
public abstract class TeamNMS<P, T extends ScoreboardManagerNMS<P>> {
public static final byte LEGACY_CHARACTER_LIMIT = 16;
public static final byte LEGACY_CHARACTER_LIMIT = 16;
public static final byte MODE_CREATE = 0,
MODE_REMOVE = 1,
MODE_UPDATE = 2,
MODE_ADD_ENTRIES = 3,
MODE_REMOVE_ENTRIES = 4;
public static final byte MODE_CREATE = 0,
MODE_REMOVE = 1,
MODE_UPDATE = 2,
MODE_ADD_ENTRIES = 3,
MODE_REMOVE_ENTRIES = 4;
protected final T impl;
protected final String teamName;
protected final T impl;
protected final String teamName;
public TeamNMS(T impl, String teamName) {
this.impl = impl;
this.teamName = teamName;
public TeamNMS(T impl, String teamName) {
this.impl = impl;
this.teamName = teamName;
}
public abstract void removeTeam(Iterable<Player> players);
public abstract TeamInfoNMS<Component> createTeamInfoNMS(ImmutableTeamProperties<Component> properties, ComponentTranslator componentTranslator);
public TeamInfoNMS<String> createLegacyTeamInfoNMS(ImmutableTeamProperties<String> properties) {
throw new UnsupportedOperationException();
}
public abstract static class TeamInfoNMS<C> {
protected final ImmutableTeamProperties<C> properties;
protected TeamInfoNMS(ImmutableTeamProperties<C> properties) {
this.properties = properties;
}
public abstract void removeTeam(Iterable<Player> players);
public abstract TeamInfoNMS<Component> createTeamInfoNMS(ImmutableTeamProperties<Component> properties, ComponentTranslator componentTranslator);
public TeamInfoNMS<String> createLegacyTeamInfoNMS(ImmutableTeamProperties<String> properties) {
throw new UnsupportedOperationException();
public void updateTeamPackets(Collection<String> entries) {
}
public abstract static class TeamInfoNMS<C> {
public abstract void addEntries(Collection<Player> players, Collection<String> entries);
protected final ImmutableTeamProperties<C> properties;
public abstract void removeEntries(Collection<Player> players, Collection<String> entries);
protected TeamInfoNMS(ImmutableTeamProperties<C> properties) {
this.properties = properties;
}
public abstract void createTeam(Collection<Player> players);
public void updateTeamPackets(Collection<String> entries) {
}
public abstract void addEntries(Collection<Player> players, Collection<String> entries);
public abstract void removeEntries(Collection<Player> players, Collection<String> entries);
public abstract void createTeam(Collection<Player> players);
public abstract void updateTeam(Collection<Player> players);
}
public abstract void updateTeam(Collection<Player> players);
}
}
@@ -9,60 +9,60 @@ import java.util.*;
public final class CollectionProvider {
private static final String FASTUTIL = "it.unimi.dsi.fastutil.objects.";
private static final MethodHandle mapConstructor, setConstructor, listConstructor;
private static final String FASTUTIL = "it.unimi.dsi.fastutil.objects.";
private static final MethodHandle mapConstructor, setConstructor, listConstructor;
static {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodType parameters = MethodType.methodType(void.class, int.class);
mapConstructor = getConstructor(lookup, FASTUTIL + "Object2ObjectOpenHashMap", HashMap.class, parameters);
setConstructor = getConstructor(lookup, FASTUTIL + "ObjectOpenHashSet", HashSet.class, parameters);
listConstructor = getConstructor(lookup, FASTUTIL + "ObjectArrayList", ArrayList.class, parameters);
static {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodType parameters = MethodType.methodType(void.class, int.class);
mapConstructor = getConstructor(lookup, FASTUTIL + "Object2ObjectOpenHashMap", HashMap.class, parameters);
setConstructor = getConstructor(lookup, FASTUTIL + "ObjectOpenHashSet", HashSet.class, parameters);
listConstructor = getConstructor(lookup, FASTUTIL + "ObjectArrayList", ArrayList.class, parameters);
}
private CollectionProvider() {
}
private static MethodHandle getConstructor(MethodHandles.Lookup lookup, String fastUtilClass, Class<?> fallback, MethodType parameters) {
Class<?> clazz;
try {
clazz = Class.forName(fastUtilClass);
ScoreboardLibraryLogger.logMessage("Using fastutil class " + clazz.getSimpleName());
} catch (ClassNotFoundException e) {
clazz = fallback;
}
private CollectionProvider() {
try {
return lookup.findConstructor(clazz, parameters);
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new ExceptionInInitializerError(e);
}
}
private static MethodHandle getConstructor(MethodHandles.Lookup lookup, String fastUtilClass, Class<?> fallback, MethodType parameters) {
Class<?> clazz;
try {
clazz = Class.forName(fastUtilClass);
ScoreboardLibraryLogger.logMessage("Using fastutil class " + clazz.getSimpleName());
} catch (ClassNotFoundException e) {
clazz = fallback;
}
try {
return lookup.findConstructor(clazz, parameters);
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new ExceptionInInitializerError(e);
}
public static <K, V> Map<K, V> map(int capacity) {
try {
// noinspection unchecked
return (Map<K, V>) mapConstructor.invokeWithArguments(capacity);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
public static <K, V> Map<K, V> map(int capacity) {
try {
// noinspection unchecked
return (Map<K, V>) mapConstructor.invokeWithArguments(capacity);
} catch (Throwable e) {
throw new RuntimeException(e);
}
public static <E> Set<E> set(int capacity) {
try {
// noinspection unchecked
return (Set<E>) setConstructor.invokeWithArguments(capacity);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
public static <E> Set<E> set(int capacity) {
try {
// noinspection unchecked
return (Set<E>) setConstructor.invokeWithArguments(capacity);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
public static <E> List<E> list(int capacity) {
try {
// noinspection unchecked
return (List<E>) listConstructor.invokeWithArguments(capacity);
} catch (Throwable e) {
throw new RuntimeException(e);
}
public static <E> List<E> list(int capacity) {
try {
// noinspection unchecked
return (List<E>) listConstructor.invokeWithArguments(capacity);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
@@ -18,44 +18,44 @@ import static net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializ
public final class LegacyFormatUtil {
private static final Map<NamedTextColor, Character> legacyMap;
private static final Map<NamedTextColor, Character> legacyMap;
static {
ChatColor[] values = ChatColor.values();
legacyMap = CollectionProvider.map(values.length);
for (ChatColor value : values) {
if (!value.isColor()) continue;
static {
ChatColor[] values = ChatColor.values();
legacyMap = CollectionProvider.map(values.length);
for (ChatColor value : values) {
if (!value.isColor()) continue;
char c = value.getChar();
LegacyFormat format = Objects.requireNonNull(parseChar(c));
legacyMap.put((NamedTextColor) format.color(), c);
}
char c = value.getChar();
LegacyFormat format = Objects.requireNonNull(parseChar(c));
legacyMap.put((NamedTextColor) format.color(), c);
}
}
private LegacyFormatUtil() {
}
public static String limitLegacyText(String text, int limit) {
if (text.length() <= limit) {
return text;
}
private LegacyFormatUtil() {
int lastNotColorCharIndex = limit - 1;
while (text.charAt(lastNotColorCharIndex) == ChatColor.COLOR_CHAR) {
lastNotColorCharIndex--;
}
return text.substring(0, lastNotColorCharIndex + 1);
}
public static String limitLegacyText(String text, int limit) {
if (text.length() <= limit) {
return text;
}
public static String serialize(@NotNull ComponentTranslator componentTranslator, @Nullable Component component, Locale locale) {
if (component == null || component == empty()) return "";
int lastNotColorCharIndex = limit - 1;
while (text.charAt(lastNotColorCharIndex) == ChatColor.COLOR_CHAR) {
lastNotColorCharIndex--;
}
return text.substring(0, lastNotColorCharIndex + 1);
}
return legacySection().serialize(componentTranslator.translate(component, locale));
}
public static String serialize(@NotNull ComponentTranslator componentTranslator, @Nullable Component component, Locale locale) {
if (component == null || component == empty()) return "";
public static char getChar(NamedTextColor color) {
if (color == null) return 'r';
return legacySection().serialize(componentTranslator.translate(component, locale));
}
public static char getChar(NamedTextColor color) {
if (color == null) return 'r';
return legacyMap.getOrDefault(color, '\0');
}
return legacyMap.getOrDefault(color, '\0');
}
}
@@ -11,43 +11,43 @@ import java.util.Locale;
public final class LocaleUtilities {
private static MethodHandle adventureMethod, legacySpigotMethod, legacyMethod;
private static MethodHandle adventureMethod, legacySpigotMethod, legacyMethod;
static {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
static {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
try {
adventureMethod = lookup.findVirtual(Player.class, "locale", MethodType.methodType(Locale.class));
} catch (IllegalAccessException | NoSuchMethodException e) {
MethodType methodType = MethodType.methodType(String.class);
try {
legacySpigotMethod = lookup.findVirtual(Player.Spigot.class, "getLocale", methodType);
} catch (IllegalAccessException | NoSuchMethodException ex) {
try {
adventureMethod = lookup.findVirtual(Player.class, "locale", MethodType.methodType(Locale.class));
} catch (IllegalAccessException | NoSuchMethodException e) {
MethodType methodType = MethodType.methodType(String.class);
try {
legacySpigotMethod = lookup.findVirtual(Player.Spigot.class, "getLocale", methodType);
} catch (IllegalAccessException | NoSuchMethodException ex) {
try {
legacyMethod = lookup.findVirtual(Player.class, "getLocale", methodType);
} catch (IllegalAccessException | NoSuchMethodException exc) {
ScoreboardLibraryLogger.logMessage("No way of getting a player's locale was found");
}
}
legacyMethod = lookup.findVirtual(Player.class, "getLocale", methodType);
} catch (IllegalAccessException | NoSuchMethodException exc) {
ScoreboardLibraryLogger.logMessage("No way of getting a player's locale was found");
}
}
}
}
private LocaleUtilities() {
}
private LocaleUtilities() {
}
public static Locale getLocaleOfPlayer(Player player) {
try {
if (adventureMethod != null) {
return (Locale) adventureMethod.invokeExact(player);
} else if (legacySpigotMethod != null) {
return Translator.parseLocale((String) legacySpigotMethod.invokeExact(player.spigot()));
} else if (legacyMethod != null) {
return Translator.parseLocale((String) legacyMethod.invokeExact(player));
} else {
return Locale.US;
}
} catch (Throwable e) {
e.printStackTrace();
return Locale.US;
}
public static Locale getLocaleOfPlayer(Player player) {
try {
if (adventureMethod != null) {
return (Locale) adventureMethod.invokeExact(player);
} else if (legacySpigotMethod != null) {
return Translator.parseLocale((String) legacySpigotMethod.invokeExact(player.spigot()));
} else if (legacyMethod != null) {
return Translator.parseLocale((String) legacyMethod.invokeExact(player));
} else {
return Locale.US;
}
} catch (Throwable e) {
e.printStackTrace();
return Locale.US;
}
}
}
@@ -10,68 +10,68 @@ import java.util.Objects;
public class UnsafeUtilities {
public static final Unsafe UNSAFE;
private static final MethodType VOID_METHOD_TYPE = MethodType.methodType(void.class);
public static final Unsafe UNSAFE;
private static final MethodType VOID_METHOD_TYPE = MethodType.methodType(void.class);
static {
static {
try {
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
UNSAFE = Objects.requireNonNull((Unsafe) theUnsafeField.get(null));
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new ExceptionInInitializerError(e);
}
}
private UnsafeUtilities() {
}
public static Field getField(Class<?> clazz, String name) {
try {
return clazz.getDeclaredField(name);
} catch (NoSuchFieldException e) {
throw new Error(e);
}
}
public static void setField(Field field, Object packet, Object value) {
if (field == null || packet == null || value == null) {
throw new NullPointerException();
} else if (field.getDeclaringClass() != packet.getClass()) {
throw new RuntimeException("Field class does not match the packet class!");
} else if (!field.getType().isInstance(value)) {
throw new RuntimeException("Field type does not match value type!");
}
UNSAFE.putObject(packet, UNSAFE.objectFieldOffset(field), value);
}
public static <T> PacketConstructor<T> findPacketConstructor(Class<T> packetClass, MethodHandles.Lookup lookup) {
try {
MethodHandle constructor = lookup.findConstructor(packetClass, VOID_METHOD_TYPE);
return () -> {
try {
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
UNSAFE = Objects.requireNonNull((Unsafe) theUnsafeField.get(null));
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new ExceptionInInitializerError(e);
// noinspection unchecked
return (T) constructor.invoke();
} catch (Throwable e) {
throw new RuntimeException(e);
}
};
} catch (NoSuchMethodException | IllegalAccessException ignored) {
}
private UnsafeUtilities() {
}
return () -> {
try {
// noinspection unchecked
return (T) UNSAFE.allocateInstance(packetClass);
} catch (Throwable e) {
throw new RuntimeException(e);
}
};
}
public static Field getField(Class<?> clazz, String name) {
try {
return clazz.getDeclaredField(name);
} catch (NoSuchFieldException e) {
throw new Error(e);
}
}
public static void setField(Field field, Object packet, Object value) {
if (field == null || packet == null || value == null) {
throw new NullPointerException();
} else if (field.getDeclaringClass() != packet.getClass()) {
throw new RuntimeException("Field class does not match the packet class!");
} else if (!field.getType().isInstance(value)) {
throw new RuntimeException("Field type does not match value type!");
}
UNSAFE.putObject(packet, UNSAFE.objectFieldOffset(field), value);
}
public static <T> PacketConstructor<T> findPacketConstructor(Class<T> packetClass, MethodHandles.Lookup lookup) {
try {
MethodHandle constructor = lookup.findConstructor(packetClass, VOID_METHOD_TYPE);
return () -> {
try {
// noinspection unchecked
return (T) constructor.invoke();
} catch (Throwable e) {
throw new RuntimeException(e);
}
};
} catch (NoSuchMethodException | IllegalAccessException ignored) {
}
return () -> {
try {
// noinspection unchecked
return (T) UNSAFE.allocateInstance(packetClass);
} catch (Throwable e) {
throw new RuntimeException(e);
}
};
}
@FunctionalInterface
public interface PacketConstructor<T> {
T invoke();
}
@FunctionalInterface
public interface PacketConstructor<T> {
T invoke();
}
}
+13 -13
View File
@@ -1,27 +1,27 @@
plugins {
id("net.megavex.scoreboardlibrary.nms-conventions")
id("io.papermc.paperweight.userdev") version "1.3.5"
`maven-publish`
id("net.megavex.scoreboardlibrary.nms-conventions")
id("io.papermc.paperweight.userdev") version "1.3.5"
`maven-publish`
}
repositories {
maven { url = uri("https://jitpack.io") }
maven { url = uri("https://jitpack.io") }
}
dependencies {
paperDevBundle("1.18.2-R0.1-SNAPSHOT")
paperDevBundle("1.18.2-R0.1-SNAPSHOT")
compileOnly("com.github.ProtocolSupport:ProtocolSupport:05b7689664")
compileOnly("com.github.ProtocolSupport:ProtocolSupport:05b7689664")
}
tasks {
assemble {
dependsOn(reobfJar)
}
assemble {
dependsOn(reobfJar)
}
}
publishing {
publications.create<MavenPublication>("maven") {
artifact(tasks.reobfJar)
}
}
publications.create<MavenPublication>("maven") {
artifact(tasks.reobfJar)
}
}
@@ -32,72 +32,72 @@ import static net.megavex.scoreboardlibrary.internal.nms.base.util.UnsafeUtiliti
public class NMSImpl extends ScoreboardManagerNMS<Packet<?>> {
private final ClientboundSetDisplayObjectivePacket displayPacket = new ClientboundSetDisplayObjectivePacket(1, null);
private final ClientboundSetObjectivePacket removePacket = UnsafeUtilities.findPacketConstructor(ClientboundSetObjectivePacket.class, MethodHandles.lookup()).invoke();
private boolean nativeAdventure, protocolSupport;
private final ClientboundSetDisplayObjectivePacket displayPacket = new ClientboundSetDisplayObjectivePacket(1, null);
private final ClientboundSetObjectivePacket removePacket = UnsafeUtilities.findPacketConstructor(ClientboundSetObjectivePacket.class, MethodHandles.lookup()).invoke();
private boolean nativeAdventure, protocolSupport;
public NMSImpl() {
setField(getField(ClientboundSetDisplayObjectivePacket.class, "b"), displayPacket, objectiveName);
setField(getField(ClientboundSetObjectivePacket.class, "d"), removePacket, objectiveName);
UnsafeUtilities.UNSAFE.putInt(removePacket, UnsafeUtilities.UNSAFE.objectFieldOffset(getField(ClientboundSetDisplayObjectivePacket.class, "a")), 1);
public NMSImpl() {
setField(getField(ClientboundSetDisplayObjectivePacket.class, "b"), displayPacket, objectiveName);
setField(getField(ClientboundSetObjectivePacket.class, "d"), removePacket, objectiveName);
UnsafeUtilities.UNSAFE.putInt(removePacket, UnsafeUtilities.UNSAFE.objectFieldOffset(getField(ClientboundSetDisplayObjectivePacket.class, "a")), 1);
try {
Class.forName("io.papermc.paper.adventure.PaperAdventure");
nativeAdventure = true;
ScoreboardLibraryLogger.logMessage("Detected native Adventure");
} catch (ClassNotFoundException ignored) { // Imagine still using Spigot
ScoreboardLibraryLogger.logMessage("Not using native Adventure");
}
if (Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null) {
var description = ScoreboardManagerProvider.loaderPlugin().getDescription();
if (description.getDepend().contains("ProtocolSupport")
|| description.getSoftDepend().contains("ProtocolSupport")) {
protocolSupport = true;
ScoreboardLibraryLogger.logMessage("Detected ProtocolSupport");
}
}
try {
Class.forName("io.papermc.paper.adventure.PaperAdventure");
nativeAdventure = true;
ScoreboardLibraryLogger.logMessage("Detected native Adventure");
} catch (ClassNotFoundException ignored) { // Imagine still using Spigot
ScoreboardLibraryLogger.logMessage("Not using native Adventure");
}
public boolean protocolSupport() {
return protocolSupport;
if (Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null) {
var description = ScoreboardManagerProvider.loaderPlugin().getDescription();
if (description.getDepend().contains("ProtocolSupport")
|| description.getSoftDepend().contains("ProtocolSupport")) {
protocolSupport = true;
ScoreboardLibraryLogger.logMessage("Detected ProtocolSupport");
}
}
}
@Override
public SidebarNMS<Packet<?>, ?> createSidebarNMS(Sidebar sidebar) {
return nativeAdventure ? new PaperSidebarNMSImpl(this, sidebar) : new SidebarNMSImpl(this, sidebar);
}
public boolean protocolSupport() {
return protocolSupport;
}
@Override
public void displaySidebar(Iterable<Player> players) {
sendPacket(players, displayPacket);
}
@Override
public SidebarNMS<Packet<?>, ?> createSidebarNMS(Sidebar sidebar) {
return nativeAdventure ? new PaperSidebarNMSImpl(this, sidebar) : new SidebarNMSImpl(this, sidebar);
}
@Override
public void removeSidebar(Iterable<Player> players) {
sendPacket(players, removePacket);
}
@Override
public void displaySidebar(Iterable<Player> players) {
sendPacket(players, displayPacket);
}
@Override
public TeamNMS<?, ?> createTeamNMS(String teamName) {
return nativeAdventure ? new PaperTeamNMSImpl(this, teamName) : new TeamNMSImpl(this, teamName);
}
@Override
public void removeSidebar(Iterable<Player> players) {
sendPacket(players, removePacket);
}
@Override
public boolean isLegacy(Player player) {
if (!protocolSupport) return false;
return ProtocolSupportUtil.isLegacy(player);
}
@Override
public TeamNMS<?, ?> createTeamNMS(String teamName) {
return nativeAdventure ? new PaperTeamNMSImpl(this, teamName) : new TeamNMSImpl(this, teamName);
}
@Override
public void sendPacket(Player player, Packet<?> packet) {
((CraftPlayer) player).getHandle().connection.send(packet);
}
@Override
public boolean isLegacy(Player player) {
if (!protocolSupport) return false;
return ProtocolSupportUtil.isLegacy(player);
}
public net.minecraft.network.chat.Component fromAdventure(Component component, Locale locale, ComponentTranslator componentTranslator) {
if (nativeAdventure) return NativeAdventureUtil.fromAdventureComponent(component);
@Override
public void sendPacket(Player player, Packet<?> packet) {
((CraftPlayer) player).getHandle().connection.send(packet);
}
component = componentTranslator.translate(component, Objects.requireNonNull(locale));
return net.minecraft.network.chat.Component.Serializer.fromJson(gson().serializeToTree(component));
}
public net.minecraft.network.chat.Component fromAdventure(Component component, Locale locale, ComponentTranslator componentTranslator) {
if (nativeAdventure) return NativeAdventureUtil.fromAdventureComponent(component);
component = componentTranslator.translate(component, Objects.requireNonNull(locale));
return net.minecraft.network.chat.Component.Serializer.fromJson(gson().serializeToTree(component));
}
}
@@ -19,31 +19,31 @@ import static net.megavex.scoreboardlibrary.internal.nms.base.util.UnsafeUtiliti
public abstract class AbstractSidebarImpl extends SidebarNMS<Packet<?>, NMSImpl> {
static final UnsafeUtilities.PacketConstructor<ClientboundSetObjectivePacket> objectivePacketConstructor = UnsafeUtilities
.findPacketConstructor(ClientboundSetObjectivePacket.class, MethodHandles.lookup());
static final Field objectiveNameField = UnsafeUtilities.getField(ClientboundSetObjectivePacket.class, "d"),
objectiveDisplayNameField = UnsafeUtilities.getField(ClientboundSetObjectivePacket.class, "e"),
objectiveRenderTypeField = UnsafeUtilities.getField(ClientboundSetObjectivePacket.class, "f");
private static final Field objectiveModeField = getField(ClientboundSetObjectivePacket.class, "g");
static final UnsafeUtilities.PacketConstructor<ClientboundSetObjectivePacket> objectivePacketConstructor = UnsafeUtilities
.findPacketConstructor(ClientboundSetObjectivePacket.class, MethodHandles.lookup());
static final Field objectiveNameField = UnsafeUtilities.getField(ClientboundSetObjectivePacket.class, "d"),
objectiveDisplayNameField = UnsafeUtilities.getField(ClientboundSetObjectivePacket.class, "e"),
objectiveRenderTypeField = UnsafeUtilities.getField(ClientboundSetObjectivePacket.class, "f");
private static final Field objectiveModeField = getField(ClientboundSetObjectivePacket.class, "g");
public AbstractSidebarImpl(NMSImpl impl, Sidebar sidebar) {
super(impl, sidebar);
}
public AbstractSidebarImpl(NMSImpl impl, Sidebar sidebar) {
super(impl, sidebar);
}
protected void createObjectivePacket(ClientboundSetObjectivePacket packet, int mode) {
UnsafeUtilities.setField(objectiveNameField, packet, impl.objectiveName);
UnsafeUtilities.UNSAFE.putInt(packet, UnsafeUtilities.UNSAFE.objectFieldOffset(objectiveModeField), mode);
UnsafeUtilities.setField(objectiveRenderTypeField, packet, ObjectiveCriteria.RenderType.INTEGER);
}
protected void createObjectivePacket(ClientboundSetObjectivePacket packet, int mode) {
UnsafeUtilities.setField(objectiveNameField, packet, impl.objectiveName);
UnsafeUtilities.UNSAFE.putInt(packet, UnsafeUtilities.UNSAFE.objectFieldOffset(objectiveModeField), mode);
UnsafeUtilities.setField(objectiveRenderTypeField, packet, ObjectiveCriteria.RenderType.INTEGER);
}
@Override
public void removeLine(Collection<Player> players, String line) {
impl.sendPacket(players, new ClientboundSetScorePacket(ServerScoreboard.Method.REMOVE, impl.objectiveName, line, 0));
}
@Override
public void removeLine(Collection<Player> players, String line) {
impl.sendPacket(players, new ClientboundSetScorePacket(ServerScoreboard.Method.REMOVE, impl.objectiveName, line, 0));
}
@Override
public void score(Collection<Player> players, int score, String line) {
ClientboundSetScorePacket packet = new ClientboundSetScorePacket(ServerScoreboard.Method.CHANGE, impl.objectiveName, line, score);
impl.sendPacket(players, packet);
}
@Override
public void score(Collection<Player> players, int score, String line) {
ClientboundSetScorePacket packet = new ClientboundSetScorePacket(ServerScoreboard.Method.CHANGE, impl.objectiveName, line, score);
impl.sendPacket(players, packet);
}
}
@@ -15,43 +15,43 @@ import java.util.Collection;
*/
public class PaperSidebarNMSImpl extends AbstractSidebarImpl {
private ClientboundSetObjectivePacket createPacket;
private ClientboundSetObjectivePacket updatePacket;
private ClientboundSetObjectivePacket createPacket;
private ClientboundSetObjectivePacket updatePacket;
public PaperSidebarNMSImpl(NMSImpl impl, Sidebar sidebar) {
super(impl, sidebar);
}
public PaperSidebarNMSImpl(NMSImpl impl, Sidebar sidebar) {
super(impl, sidebar);
}
private void initialisePackets() {
private void initialisePackets() {
if (createPacket == null || updatePacket == null) {
synchronized (this) {
if (createPacket == null || updatePacket == null) {
synchronized (this) {
if (createPacket == null || updatePacket == null) {
createPacket = objectivePacketConstructor.invoke();
updatePacket = objectivePacketConstructor.invoke();
createObjectivePacket(createPacket, 0);
createObjectivePacket(updatePacket, 2);
updateTitle(sidebar.title());
}
}
createPacket = objectivePacketConstructor.invoke();
updatePacket = objectivePacketConstructor.invoke();
createObjectivePacket(createPacket, 0);
createObjectivePacket(updatePacket, 2);
updateTitle(sidebar.title());
}
}
}
}
private void updateDisplayName(ClientboundSetObjectivePacket packet, net.minecraft.network.chat.Component displayName) {
UnsafeUtilities.setField(objectiveDisplayNameField, packet, displayName);
}
private void updateDisplayName(ClientboundSetObjectivePacket packet, net.minecraft.network.chat.Component displayName) {
UnsafeUtilities.setField(objectiveDisplayNameField, packet, displayName);
}
@Override
public void updateTitle(Component displayName) {
if (createPacket != null && updatePacket != null) {
net.minecraft.network.chat.Component vanilla = NativeAdventureUtil.fromAdventureComponent(displayName);
updateDisplayName(createPacket, vanilla);
updateDisplayName(updatePacket, vanilla);
}
@Override
public void updateTitle(Component displayName) {
if (createPacket != null && updatePacket != null) {
net.minecraft.network.chat.Component vanilla = NativeAdventureUtil.fromAdventureComponent(displayName);
updateDisplayName(createPacket, vanilla);
updateDisplayName(updatePacket, vanilla);
}
}
@Override
protected void sendObjectivePacket(Collection<Player> players, boolean create) {
initialisePackets();
impl.sendPacket(players, create ? createPacket : updatePacket);
}
@Override
protected void sendObjectivePacket(Collection<Player> players, boolean create) {
initialisePackets();
impl.sendPacket(players, create ? createPacket : updatePacket);
}
}
@@ -13,52 +13,52 @@ import java.util.Locale;
public class SidebarNMSImpl extends AbstractSidebarImpl {
private final ClientboundSetObjectivePacket createPacket;
private final ClientboundSetObjectivePacket updatePacket;
private final ClientboundSetObjectivePacket createPacket;
private final ClientboundSetObjectivePacket updatePacket;
public SidebarNMSImpl(NMSImpl impl, Sidebar sidebar) {
super(impl, sidebar);
public SidebarNMSImpl(NMSImpl impl, Sidebar sidebar) {
super(impl, sidebar);
Locale locale = sidebar.locale();
if (locale != null) {
createPacket = objectivePacketConstructor.invoke();
createObjectivePacket(createPacket, 0);
updateDisplayName(createPacket, sidebar.title(), locale);
Locale locale = sidebar.locale();
if (locale != null) {
createPacket = objectivePacketConstructor.invoke();
createObjectivePacket(createPacket, 0);
updateDisplayName(createPacket, sidebar.title(), locale);
updatePacket = objectivePacketConstructor.invoke();
createObjectivePacket(updatePacket, 2);
updateDisplayName(updatePacket, sidebar.title(), locale);
} else {
createPacket = null;
updatePacket = null;
}
updatePacket = objectivePacketConstructor.invoke();
createObjectivePacket(updatePacket, 2);
updateDisplayName(updatePacket, sidebar.title(), locale);
} else {
createPacket = null;
updatePacket = null;
}
}
private void updateDisplayName(ClientboundSetObjectivePacket packet, Component displayName, Locale locale) {
net.minecraft.network.chat.Component vanilla = impl.fromAdventure(displayName, locale, sidebar.componentTranslator());
UnsafeUtilities.setField(objectiveDisplayNameField, packet, vanilla);
}
private void updateDisplayName(ClientboundSetObjectivePacket packet, Component displayName, Locale locale) {
net.minecraft.network.chat.Component vanilla = impl.fromAdventure(displayName, locale, sidebar.componentTranslator());
UnsafeUtilities.setField(objectiveDisplayNameField, packet, vanilla);
}
@Override
public void updateTitle(Component displayName) {
Locale locale = sidebar.locale();
if (locale != null) {
updateDisplayName(createPacket, displayName, locale);
updateDisplayName(updatePacket, displayName, locale);
}
@Override
public void updateTitle(Component displayName) {
Locale locale = sidebar.locale();
if (locale != null) {
updateDisplayName(createPacket, displayName, locale);
updateDisplayName(updatePacket, displayName, locale);
}
}
@Override
protected void sendObjectivePacket(Collection<Player> players, boolean create) {
if (sidebar.locale() != null) {
impl.sendPacket(players, create ? createPacket : updatePacket);
} else {
ScoreboardManagerNMS.sendLocalePackets(sidebar.locale(), impl, players, locale -> {
ClientboundSetObjectivePacket packet = objectivePacketConstructor.invoke();
createObjectivePacket(packet, create ? 0 : 2);
updateDisplayName(packet, sidebar.title(), locale);
return packet;
});
}
@Override
protected void sendObjectivePacket(Collection<Player> players, boolean create) {
if (sidebar.locale() != null) {
impl.sendPacket(players, create ? createPacket : updatePacket);
} else {
ScoreboardManagerNMS.sendLocalePackets(sidebar.locale(), impl, players, locale -> {
ClientboundSetObjectivePacket packet = objectivePacketConstructor.invoke();
createObjectivePacket(packet, create ? 0 : 2);
updateDisplayName(packet, sidebar.title(), locale);
return packet;
});
}
}
}
@@ -25,104 +25,104 @@ import static net.megavex.scoreboardlibrary.internal.nms.base.util.UnsafeUtiliti
public abstract class AbstractTeamNMSImpl extends TeamNMS<Packet<?>, NMSImpl> {
protected static final Field displayNameField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "a"),
prefixField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "b"),
suffixField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "c"),
entriesField = getField(ClientboundSetPlayerTeamPacket.class, "j"),
nameTagVisibilityField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "d"),
collisionRuleField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "e"),
colorField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "f"),
optionsField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "g");
private static final Constructor<ClientboundSetPlayerTeamPacket> teamPacketConstructor;
protected static final Field displayNameField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "a"),
prefixField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "b"),
suffixField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "c"),
entriesField = getField(ClientboundSetPlayerTeamPacket.class, "j"),
nameTagVisibilityField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "d"),
collisionRuleField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "e"),
colorField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "f"),
optionsField = getField(ClientboundSetPlayerTeamPacket.Parameters.class, "g");
private static final Constructor<ClientboundSetPlayerTeamPacket> teamPacketConstructor;
static {
try {
teamPacketConstructor = ClientboundSetPlayerTeamPacket.class.getDeclaredConstructor(String.class, int.class, Optional.class, Collection.class);
teamPacketConstructor.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new ExceptionInInitializerError(e);
}
static {
try {
teamPacketConstructor = ClientboundSetPlayerTeamPacket.class.getDeclaredConstructor(String.class, int.class, Optional.class, Collection.class);
teamPacketConstructor.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new ExceptionInInitializerError(e);
}
}
protected ClientboundSetPlayerTeamPacket removePacket;
protected ClientboundSetPlayerTeamPacket removePacket;
AbstractTeamNMSImpl(NMSImpl impl, String teamName) {
super(impl, teamName);
AbstractTeamNMSImpl(NMSImpl impl, String teamName) {
super(impl, teamName);
}
public static ClientboundSetPlayerTeamPacket createTeamsPacket(
int method,
String name,
ClientboundSetPlayerTeamPacket.Parameters parameters,
Collection<String> entries
) {
try {
return teamPacketConstructor.newInstance(name, method, Optional.ofNullable(parameters), entries == null ? ImmutableList.of() : entries);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
public static ClientboundSetPlayerTeamPacket createTeamsPacket(
int method,
String name,
ClientboundSetPlayerTeamPacket.Parameters parameters,
Collection<String> entries
) {
try {
return teamPacketConstructor.newInstance(name, method, Optional.ofNullable(parameters), entries == null ? ImmutableList.of() : entries);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
@Override
public void removeTeam(Iterable<Player> players) {
if (removePacket == null) {
removePacket = createTeamsPacket(MODE_REMOVE, teamName, null, null);
}
impl.sendPacket(players, removePacket);
}
@Override
public TeamInfoNMS<String> createLegacyTeamInfoNMS(ImmutableTeamProperties<String> properties) {
if (impl.protocolSupport()) return new LegacyTeamInfoNMS(properties, teamName);
return super.createLegacyTeamInfoNMS(properties);
}
abstract class TeamInfoNMSImpl extends TeamNMS.TeamInfoNMS<Component> {
static final UnsafeUtilities.PacketConstructor<ClientboundSetPlayerTeamPacket.Parameters> parametersConstructor =
UnsafeUtilities.findPacketConstructor(ClientboundSetPlayerTeamPacket.Parameters.class, MethodHandles.lookup());
public TeamInfoNMSImpl(ImmutableTeamProperties<Component> properties) {
super(properties);
}
@Override
public void removeTeam(Iterable<Player> players) {
if (removePacket == null) {
removePacket = createTeamsPacket(MODE_REMOVE, teamName, null, null);
}
impl.sendPacket(players, removePacket);
public void addEntries(Collection<Player> players, Collection<String> entries) {
teamEntry(players, entries, MODE_ADD_ENTRIES);
}
@Override
public TeamInfoNMS<String> createLegacyTeamInfoNMS(ImmutableTeamProperties<String> properties) {
if (impl.protocolSupport()) return new LegacyTeamInfoNMS(properties, teamName);
return super.createLegacyTeamInfoNMS(properties);
public void removeEntries(Collection<Player> players, Collection<String> entries) {
teamEntry(players, entries, MODE_REMOVE_ENTRIES);
}
abstract class TeamInfoNMSImpl extends TeamNMS.TeamInfoNMS<Component> {
static final UnsafeUtilities.PacketConstructor<ClientboundSetPlayerTeamPacket.Parameters> parametersConstructor =
UnsafeUtilities.findPacketConstructor(ClientboundSetPlayerTeamPacket.Parameters.class, MethodHandles.lookup());
public TeamInfoNMSImpl(ImmutableTeamProperties<Component> properties) {
super(properties);
}
@Override
public void addEntries(Collection<Player> players, Collection<String> entries) {
teamEntry(players, entries, MODE_ADD_ENTRIES);
}
@Override
public void removeEntries(Collection<Player> players, Collection<String> entries) {
teamEntry(players, entries, MODE_REMOVE_ENTRIES);
}
private void teamEntry(Collection<Player> players, Collection<String> entries, int action) {
impl.sendPacket(players, createTeamsPacket(action, teamName, null, entries));
}
protected void fillTeamPacket(ClientboundSetPlayerTeamPacket packet, Collection<String> entries) {
if (packet.getPlayers() != entries) {
UnsafeUtilities.setField(entriesField, packet, entries);
}
}
protected void fillParameters(ClientboundSetPlayerTeamPacket.Parameters parameters, Locale locale) {
String key = properties.nameTagVisibility().key();
if (!Objects.equals(parameters.getNametagVisibility(), key)) {
UnsafeUtilities.setField(nameTagVisibilityField, parameters, key);
}
key = properties.collisionRule().key();
if (!Objects.equals(parameters.getCollisionRule(), key))
UnsafeUtilities.setField(collisionRuleField, parameters, key);
char c = LegacyFormatUtil.getChar(properties.playerColor());
if (parameters.getColor() == null || parameters.getColor().code != c)
UnsafeUtilities.setField(colorField, parameters, ChatFormatting.getByCode(c));
int options = properties.packOptions();
if (parameters.getOptions() != options)
UnsafeUtilities.UNSAFE.putInt(parameters, UnsafeUtilities.UNSAFE.objectFieldOffset(optionsField), options);
}
private void teamEntry(Collection<Player> players, Collection<String> entries, int action) {
impl.sendPacket(players, createTeamsPacket(action, teamName, null, entries));
}
protected void fillTeamPacket(ClientboundSetPlayerTeamPacket packet, Collection<String> entries) {
if (packet.getPlayers() != entries) {
UnsafeUtilities.setField(entriesField, packet, entries);
}
}
protected void fillParameters(ClientboundSetPlayerTeamPacket.Parameters parameters, Locale locale) {
String key = properties.nameTagVisibility().key();
if (!Objects.equals(parameters.getNametagVisibility(), key)) {
UnsafeUtilities.setField(nameTagVisibilityField, parameters, key);
}
key = properties.collisionRule().key();
if (!Objects.equals(parameters.getCollisionRule(), key))
UnsafeUtilities.setField(collisionRuleField, parameters, key);
char c = LegacyFormatUtil.getChar(properties.playerColor());
if (parameters.getColor() == null || parameters.getColor().code != c)
UnsafeUtilities.setField(colorField, parameters, ChatFormatting.getByCode(c));
int options = properties.packOptions();
if (parameters.getOptions() != options)
UnsafeUtilities.UNSAFE.putInt(parameters, UnsafeUtilities.UNSAFE.objectFieldOffset(optionsField), options);
}
}
}
@@ -15,75 +15,75 @@ import java.util.Collection;
public class LegacyTeamInfoNMS extends TeamNMS.TeamInfoNMS<String> {
private final String teamName;
private final String teamName;
public LegacyTeamInfoNMS(ImmutableTeamProperties<String> properties, String teamName) {
super(properties);
this.teamName = teamName;
public LegacyTeamInfoNMS(ImmutableTeamProperties<String> properties, String teamName) {
super(properties);
this.teamName = teamName;
}
@Override
public void addEntries(Collection<Player> players, Collection<String> entries) {
sendPacket(players, createEntriesPacket(true, entries));
}
@Override
public void removeEntries(Collection<Player> players, Collection<String> entries) {
sendPacket(players, createEntriesPacket(false, entries));
}
@Override
public void createTeam(Collection<Player> players) {
sendPacket(players, createInfoPacket(true));
}
@Override
public void updateTeam(Collection<Player> players) {
sendPacket(players, createInfoPacket(false));
}
private void sendPacket(Collection<Player> players, ClientBoundPacketData data) {
for (Player player : players) {
Connection connection = ProtocolSupportAPI.getConnection(player);
if (connection == null) continue;
((ConnectionImpl) connection).getPacketDataIO().writeClientbound(data);
}
}
private ClientBoundPacketData createPacket(int mode) {
ClientBoundPacketData data = ClientBoundPacketData.create(ClientBoundPacketType.PLAY_SCOREBOARD_TEAM);
StringCodec.writeVarIntUTF8String(data, teamName);
data.writeByte(mode);
return data;
}
private ClientBoundPacketData createInfoPacket(boolean create) {
ClientBoundPacketData data = createPacket(create ? TeamNMS.MODE_CREATE : TeamNMS.MODE_UPDATE);
StringCodec.writeVarIntUTF8String(data, properties.displayName());
StringCodec.writeVarIntUTF8String(data, properties.prefix());
StringCodec.writeVarIntUTF8String(data, properties.suffix());
data.writeByte(properties.packOptions());
StringCodec.writeVarIntUTF8String(data, properties.nameTagVisibility().key());
data.writeByte(0);
if (create) {
writeEntries(data, properties.entries());
}
@Override
public void addEntries(Collection<Player> players, Collection<String> entries) {
sendPacket(players, createEntriesPacket(true, entries));
}
@Override
public void removeEntries(Collection<Player> players, Collection<String> entries) {
sendPacket(players, createEntriesPacket(false, entries));
}
@Override
public void createTeam(Collection<Player> players) {
sendPacket(players, createInfoPacket(true));
}
@Override
public void updateTeam(Collection<Player> players) {
sendPacket(players, createInfoPacket(false));
}
private void sendPacket(Collection<Player> players, ClientBoundPacketData data) {
for (Player player : players) {
Connection connection = ProtocolSupportAPI.getConnection(player);
if (connection == null) continue;
((ConnectionImpl) connection).getPacketDataIO().writeClientbound(data);
}
}
private ClientBoundPacketData createPacket(int mode) {
ClientBoundPacketData data = ClientBoundPacketData.create(ClientBoundPacketType.PLAY_SCOREBOARD_TEAM);
StringCodec.writeVarIntUTF8String(data, teamName);
data.writeByte(mode);
return data;
}
private ClientBoundPacketData createInfoPacket(boolean create) {
ClientBoundPacketData data = createPacket(create ? TeamNMS.MODE_CREATE : TeamNMS.MODE_UPDATE);
StringCodec.writeVarIntUTF8String(data, properties.displayName());
StringCodec.writeVarIntUTF8String(data, properties.prefix());
StringCodec.writeVarIntUTF8String(data, properties.suffix());
data.writeByte(properties.packOptions());
StringCodec.writeVarIntUTF8String(data, properties.nameTagVisibility().key());
data.writeByte(0);
if (create) {
writeEntries(data, properties.entries());
}
return data;
}
private ClientBoundPacketData createEntriesPacket(boolean add, Collection<String> entries) {
ClientBoundPacketData data = createPacket(add ? TeamNMS.MODE_ADD_ENTRIES : TeamNMS.MODE_REMOVE_ENTRIES);
writeEntries(data, entries);
return data;
}
private void writeEntries(ClientBoundPacketData data, Collection<String> entries) {
VarNumberCodec.writeVarInt(data, entries.size());
for (String entry : entries) {
StringCodec.writeVarIntUTF8String(data, entry);
}
return data;
}
private ClientBoundPacketData createEntriesPacket(boolean add, Collection<String> entries) {
ClientBoundPacketData data = createPacket(add ? TeamNMS.MODE_ADD_ENTRIES : TeamNMS.MODE_REMOVE_ENTRIES);
writeEntries(data, entries);
return data;
}
private void writeEntries(ClientBoundPacketData data, Collection<String> entries) {
VarNumberCodec.writeVarInt(data, entries.size());
for (String entry : entries) {
StringCodec.writeVarIntUTF8String(data, entry);
}
}
}
@@ -15,61 +15,61 @@ import java.util.Locale;
public class PaperTeamNMSImpl extends AbstractTeamNMSImpl {
public PaperTeamNMSImpl(NMSImpl impl, String teamName) {
super(impl, teamName);
public PaperTeamNMSImpl(NMSImpl impl, String teamName) {
super(impl, teamName);
}
@Override
public TeamInfoNMS<Component> createTeamInfoNMS(ImmutableTeamProperties<Component> properties, ComponentTranslator componentTranslator) {
return new TeamInfoNMSImpl(properties);
}
private class TeamInfoNMSImpl extends AbstractTeamNMSImpl.TeamInfoNMSImpl {
final ClientboundSetPlayerTeamPacket.Parameters parameters = parametersConstructor.invoke();
protected final ClientboundSetPlayerTeamPacket createPacket = createTeamsPacket(TeamNMS.MODE_CREATE, teamName, parameters, null);
protected final ClientboundSetPlayerTeamPacket updatePacket = createTeamsPacket(TeamNMS.MODE_UPDATE, teamName, parameters, null);
private Component displayName, prefix, suffix;
public TeamInfoNMSImpl(ImmutableTeamProperties<Component> properties) {
super(properties);
}
@Override
public TeamInfoNMS<Component> createTeamInfoNMS(ImmutableTeamProperties<Component> properties, ComponentTranslator componentTranslator) {
return new TeamInfoNMSImpl(properties);
public void updateTeamPackets(Collection<String> entries) {
fillParameters(parameters, null);
fillTeamPacket(createPacket, entries);
fillTeamPacket(updatePacket, entries);
}
private class TeamInfoNMSImpl extends AbstractTeamNMSImpl.TeamInfoNMSImpl {
final ClientboundSetPlayerTeamPacket.Parameters parameters = parametersConstructor.invoke();
protected final ClientboundSetPlayerTeamPacket createPacket = createTeamsPacket(TeamNMS.MODE_CREATE, teamName, parameters, null);
protected final ClientboundSetPlayerTeamPacket updatePacket = createTeamsPacket(TeamNMS.MODE_UPDATE, teamName, parameters, null);
private Component displayName, prefix, suffix;
public TeamInfoNMSImpl(ImmutableTeamProperties<Component> properties) {
super(properties);
}
@Override
public void updateTeamPackets(Collection<String> entries) {
fillParameters(parameters, null);
fillTeamPacket(createPacket, entries);
fillTeamPacket(updatePacket, entries);
}
@Override
public void createTeam(Collection<Player> players) {
impl.sendPacket(players, createPacket);
}
@Override
public void updateTeam(Collection<Player> players) {
impl.sendPacket(players, updatePacket);
}
@Override
protected void fillParameters(ClientboundSetPlayerTeamPacket.Parameters parameters, Locale locale) {
super.fillParameters(parameters, locale);
if (properties.displayName() != displayName) {
UnsafeUtilities.setField(displayNameField, parameters, NativeAdventureUtil.fromAdventureComponent(properties.displayName()));
displayName = properties.displayName();
}
if (properties.prefix() != prefix) {
UnsafeUtilities.setField(prefixField, parameters, NativeAdventureUtil.fromAdventureComponent(properties.prefix()));
prefix = properties.prefix();
}
if (properties.suffix() != suffix) {
UnsafeUtilities.setField(suffixField, parameters, NativeAdventureUtil.fromAdventureComponent(properties.suffix()));
suffix = properties.suffix();
}
}
@Override
public void createTeam(Collection<Player> players) {
impl.sendPacket(players, createPacket);
}
@Override
public void updateTeam(Collection<Player> players) {
impl.sendPacket(players, updatePacket);
}
@Override
protected void fillParameters(ClientboundSetPlayerTeamPacket.Parameters parameters, Locale locale) {
super.fillParameters(parameters, locale);
if (properties.displayName() != displayName) {
UnsafeUtilities.setField(displayNameField, parameters, NativeAdventureUtil.fromAdventureComponent(properties.displayName()));
displayName = properties.displayName();
}
if (properties.prefix() != prefix) {
UnsafeUtilities.setField(prefixField, parameters, NativeAdventureUtil.fromAdventureComponent(properties.prefix()));
prefix = properties.prefix();
}
if (properties.suffix() != suffix) {
UnsafeUtilities.setField(suffixField, parameters, NativeAdventureUtil.fromAdventureComponent(properties.suffix()));
suffix = properties.suffix();
}
}
}
}
@@ -14,54 +14,54 @@ import java.util.Locale;
public class TeamNMSImpl extends AbstractTeamNMSImpl {
public TeamNMSImpl(NMSImpl impl, String teamName) {
super(impl, teamName);
public TeamNMSImpl(NMSImpl impl, String teamName) {
super(impl, teamName);
}
@Override
public TeamInfoNMS<Component> createTeamInfoNMS(ImmutableTeamProperties<Component> properties, ComponentTranslator componentTranslator) {
return new TeamInfoNMSImpl(properties, componentTranslator);
}
private class TeamInfoNMSImpl extends AbstractTeamNMSImpl.TeamInfoNMSImpl {
private final ComponentTranslator componentTranslator;
public TeamInfoNMSImpl(ImmutableTeamProperties<Component> properties, ComponentTranslator componentTranslator) {
super(properties);
this.componentTranslator = componentTranslator;
}
@Override
public TeamInfoNMS<Component> createTeamInfoNMS(ImmutableTeamProperties<Component> properties, ComponentTranslator componentTranslator) {
return new TeamInfoNMSImpl(properties, componentTranslator);
public void createTeam(Collection<Player> players) {
sendTeamPacket(players, true);
}
private class TeamInfoNMSImpl extends AbstractTeamNMSImpl.TeamInfoNMSImpl {
private final ComponentTranslator componentTranslator;
public TeamInfoNMSImpl(ImmutableTeamProperties<Component> properties, ComponentTranslator componentTranslator) {
super(properties);
this.componentTranslator = componentTranslator;
}
@Override
public void createTeam(Collection<Player> players) {
sendTeamPacket(players, true);
}
@Override
public void updateTeam(Collection<Player> players) {
sendTeamPacket(players, false);
}
private void sendTeamPacket(Collection<Player> players, boolean create) {
ScoreboardManagerNMS.sendLocalePackets(null, impl, players, locale -> {
ClientboundSetPlayerTeamPacket.Parameters parameters = parametersConstructor.invoke();
fillParameters(parameters, locale);
return createTeamsPacket(create ? MODE_CREATE : MODE_UPDATE, teamName, parameters, properties.entries());
});
}
@Override
protected void fillParameters(ClientboundSetPlayerTeamPacket.Parameters parameters, Locale locale) {
super.fillParameters(parameters, locale);
net.minecraft.network.chat.Component vanilla = impl.fromAdventure(properties.displayName(), locale, componentTranslator);
UnsafeUtilities.setField(displayNameField, parameters, vanilla);
vanilla = impl.fromAdventure(properties.prefix(), locale, componentTranslator);
UnsafeUtilities.setField(prefixField, parameters, vanilla);
vanilla = impl.fromAdventure(properties.suffix(), locale, componentTranslator);
UnsafeUtilities.setField(suffixField, parameters, vanilla);
}
@Override
public void updateTeam(Collection<Player> players) {
sendTeamPacket(players, false);
}
private void sendTeamPacket(Collection<Player> players, boolean create) {
ScoreboardManagerNMS.sendLocalePackets(null, impl, players, locale -> {
ClientboundSetPlayerTeamPacket.Parameters parameters = parametersConstructor.invoke();
fillParameters(parameters, locale);
return createTeamsPacket(create ? MODE_CREATE : MODE_UPDATE, teamName, parameters, properties.entries());
});
}
@Override
protected void fillParameters(ClientboundSetPlayerTeamPacket.Parameters parameters, Locale locale) {
super.fillParameters(parameters, locale);
net.minecraft.network.chat.Component vanilla = impl.fromAdventure(properties.displayName(), locale, componentTranslator);
UnsafeUtilities.setField(displayNameField, parameters, vanilla);
vanilla = impl.fromAdventure(properties.prefix(), locale, componentTranslator);
UnsafeUtilities.setField(prefixField, parameters, vanilla);
vanilla = impl.fromAdventure(properties.suffix(), locale, componentTranslator);
UnsafeUtilities.setField(suffixField, parameters, vanilla);
}
}
}
@@ -5,10 +5,10 @@ import net.kyori.adventure.text.Component;
public final class NativeAdventureUtil {
private NativeAdventureUtil() {
}
private NativeAdventureUtil() {
}
public static net.minecraft.network.chat.Component fromAdventureComponent(Component component) {
return new AdventureComponent(component);
}
public static net.minecraft.network.chat.Component fromAdventureComponent(Component component) {
return new AdventureComponent(component);
}
}
@@ -7,14 +7,14 @@ import protocolsupport.api.ProtocolVersion;
public final class ProtocolSupportUtil {
private ProtocolSupportUtil() {
}
private ProtocolSupportUtil() {
}
public static boolean isLegacy(Player player) {
Connection connection = ProtocolSupportAPI.getConnection(player);
if (connection == null) return false;
public static boolean isLegacy(Player player) {
Connection connection = ProtocolSupportAPI.getConnection(player);
if (connection == null) return false;
// TODO: may work on older versions, need to test that
return connection.getVersion().isBetween(ProtocolVersion.MINECRAFT_1_12_2, ProtocolVersion.MINECRAFT_1_8);
}
// TODO: may work on older versions, need to test that
return connection.getVersion().isBetween(ProtocolVersion.MINECRAFT_1_12_2, ProtocolVersion.MINECRAFT_1_8);
}
}
+8 -8
View File
@@ -1,15 +1,15 @@
plugins {
id("net.megavex.scoreboardlibrary.publish-conventions")
id("net.megavex.scoreboardlibrary.nms-conventions")
id("net.megavex.scoreboardlibrary.publish-conventions")
id("net.megavex.scoreboardlibrary.nms-conventions")
}
repositories {
maven {
name = "SportPaper"
url = uri("https://repo.ashcon.app/nexus/content/repositories/snapshots/")
}
maven {
name = "SportPaper"
url = uri("https://repo.ashcon.app/nexus/content/repositories/snapshots/")
}
}
dependencies {
compileOnly("app.ashcon:sportpaper:1.8.8-R0.1-SNAPSHOT")
}
compileOnly("app.ashcon:sportpaper:1.8.8-R0.1-SNAPSHOT")
}
@@ -15,59 +15,59 @@ import java.lang.reflect.Field;
public class NMSImpl extends ScoreboardManagerNMS<Packet<?>> {
static final Field objectiveModeField;
static final Field objectiveModeField;
static {
objectiveModeField = UnsafeUtilities.getField(PacketPlayOutScoreboardObjective.class, "d");
}
static {
objectiveModeField = UnsafeUtilities.getField(PacketPlayOutScoreboardObjective.class, "d");
}
private final PacketPlayOutScoreboardDisplayObjective displayPacket = new PacketPlayOutScoreboardDisplayObjective();
private final PacketPlayOutScoreboardObjective removePacket = new PacketPlayOutScoreboardObjective();
private final PacketPlayOutScoreboardDisplayObjective displayPacket = new PacketPlayOutScoreboardDisplayObjective();
private final PacketPlayOutScoreboardObjective removePacket = new PacketPlayOutScoreboardObjective();
public NMSImpl() {
// Setup static packets
UnsafeUtilities.UNSAFE.putInt(
displayPacket,
UnsafeUtilities.UNSAFE.objectFieldOffset(UnsafeUtilities.getField(PacketPlayOutScoreboardDisplayObjective.class, "a")),
1
);
UnsafeUtilities.setField(UnsafeUtilities.getField(PacketPlayOutScoreboardDisplayObjective.class, "b"), displayPacket, objectiveName);
public NMSImpl() {
// Setup static packets
UnsafeUtilities.UNSAFE.putInt(
displayPacket,
UnsafeUtilities.UNSAFE.objectFieldOffset(UnsafeUtilities.getField(PacketPlayOutScoreboardDisplayObjective.class, "a")),
1
);
UnsafeUtilities.setField(UnsafeUtilities.getField(PacketPlayOutScoreboardDisplayObjective.class, "b"), displayPacket, objectiveName);
UnsafeUtilities.setField(UnsafeUtilities.getField(PacketPlayOutScoreboardObjective.class, "a"), removePacket, objectiveName);
UnsafeUtilities.UNSAFE.putInt(
removePacket,
UnsafeUtilities.UNSAFE.objectFieldOffset(objectiveModeField),
1
);
}
UnsafeUtilities.setField(UnsafeUtilities.getField(PacketPlayOutScoreboardObjective.class, "a"), removePacket, objectiveName);
UnsafeUtilities.UNSAFE.putInt(
removePacket,
UnsafeUtilities.UNSAFE.objectFieldOffset(objectiveModeField),
1
);
}
@Override
public SidebarNMS<Packet<?>, ?> createSidebarNMS(Sidebar sidebar) {
return new SidebarNMSImpl(this, sidebar);
}
@Override
public SidebarNMS<Packet<?>, ?> createSidebarNMS(Sidebar sidebar) {
return new SidebarNMSImpl(this, sidebar);
}
@Override
public void displaySidebar(Iterable<Player> players) {
sendPacket(players, displayPacket);
}
@Override
public void displaySidebar(Iterable<Player> players) {
sendPacket(players, displayPacket);
}
@Override
public void removeSidebar(Iterable<Player> players) {
sendPacket(players, removePacket);
}
@Override
public void removeSidebar(Iterable<Player> players) {
sendPacket(players, removePacket);
}
@Override
public TeamNMS<?, ?> createTeamNMS(String teamName) {
return new TeamNMSImpl(this, teamName);
}
@Override
public TeamNMS<?, ?> createTeamNMS(String teamName) {
return new TeamNMSImpl(this, teamName);
}
@Override
public boolean isLegacy(Player player) {
return true;
}
@Override
public boolean isLegacy(Player player) {
return true;
}
@Override
public void sendPacket(Player player, Packet<?> packet) {
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
}
@Override
public void sendPacket(Player player, Packet<?> packet) {
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
}
}
@@ -20,82 +20,82 @@ import static net.kyori.adventure.text.Component.empty;
public class SidebarNMSImpl extends SidebarNMS<Packet<?>, NMSImpl> {
private static final Field objectiveNameField, objectiveDisplayNameField, objectiveHealthDisplayField, scoreNameField, scoreObjectiveNameField, scoreScoreField, scoreActionField;
private static final Field objectiveNameField, objectiveDisplayNameField, objectiveHealthDisplayField, scoreNameField, scoreObjectiveNameField, scoreScoreField, scoreActionField;
static {
objectiveNameField = UnsafeUtilities.getField(PacketPlayOutScoreboardObjective.class, "a");
objectiveDisplayNameField = UnsafeUtilities.getField(PacketPlayOutScoreboardObjective.class, "b");
objectiveHealthDisplayField = UnsafeUtilities.getField(PacketPlayOutScoreboardObjective.class, "c");
scoreNameField = UnsafeUtilities.getField(PacketPlayOutScoreboardScore.class, "a");
scoreObjectiveNameField = UnsafeUtilities.getField(PacketPlayOutScoreboardScore.class, "b");
scoreScoreField = UnsafeUtilities.getField(PacketPlayOutScoreboardScore.class, "c");
scoreActionField = UnsafeUtilities.getField(PacketPlayOutScoreboardScore.class, "d");
static {
objectiveNameField = UnsafeUtilities.getField(PacketPlayOutScoreboardObjective.class, "a");
objectiveDisplayNameField = UnsafeUtilities.getField(PacketPlayOutScoreboardObjective.class, "b");
objectiveHealthDisplayField = UnsafeUtilities.getField(PacketPlayOutScoreboardObjective.class, "c");
scoreNameField = UnsafeUtilities.getField(PacketPlayOutScoreboardScore.class, "a");
scoreObjectiveNameField = UnsafeUtilities.getField(PacketPlayOutScoreboardScore.class, "b");
scoreScoreField = UnsafeUtilities.getField(PacketPlayOutScoreboardScore.class, "c");
scoreActionField = UnsafeUtilities.getField(PacketPlayOutScoreboardScore.class, "d");
}
private final PacketPlayOutScoreboardObjective createPacket;
private final PacketPlayOutScoreboardObjective updatePacket;
SidebarNMSImpl(NMSImpl impl, Sidebar sidebar) {
super(impl, sidebar);
Locale locale = sidebar.locale();
if (locale != null) {
createPacket = new PacketPlayOutScoreboardObjective();
updatePacket = new PacketPlayOutScoreboardObjective();
createObjectivePacket(createPacket, 0, empty(), locale);
createObjectivePacket(updatePacket, 2, empty(), locale);
} else {
createPacket = null;
updatePacket = null;
}
}
private final PacketPlayOutScoreboardObjective createPacket;
private final PacketPlayOutScoreboardObjective updatePacket;
private void createObjectivePacket(PacketPlayOutScoreboardObjective packet, int mode, Component displayName, Locale locale) {
UnsafeUtilities.setField(objectiveNameField, packet, impl.objectiveName);
UnsafeUtilities.UNSAFE.putInt(packet, UnsafeUtilities.UNSAFE.objectFieldOffset(NMSImpl.objectiveModeField), mode);
UnsafeUtilities.setField(objectiveHealthDisplayField, packet, IScoreboardCriteria.EnumScoreboardHealthDisplay.INTEGER);
updateDisplayName(packet, displayName, locale);
}
SidebarNMSImpl(NMSImpl impl, Sidebar sidebar) {
super(impl, sidebar);
private void updateDisplayName(PacketPlayOutScoreboardObjective packet, Component displayName, Locale locale) {
String value = LegacyFormatUtil.serialize(sidebar.componentTranslator(), displayName, locale);
UnsafeUtilities.setField(objectiveDisplayNameField, packet, value);
}
Locale locale = sidebar.locale();
if (locale != null) {
createPacket = new PacketPlayOutScoreboardObjective();
updatePacket = new PacketPlayOutScoreboardObjective();
createObjectivePacket(createPacket, 0, empty(), locale);
createObjectivePacket(updatePacket, 2, empty(), locale);
} else {
createPacket = null;
updatePacket = null;
}
@Override
public void updateTitle(Component displayName) {
Locale locale = sidebar.locale();
if (locale != null) {
updateDisplayName(createPacket, displayName, locale);
updateDisplayName(updatePacket, displayName, locale);
}
}
private void createObjectivePacket(PacketPlayOutScoreboardObjective packet, int mode, Component displayName, Locale locale) {
UnsafeUtilities.setField(objectiveNameField, packet, impl.objectiveName);
UnsafeUtilities.UNSAFE.putInt(packet, UnsafeUtilities.UNSAFE.objectFieldOffset(NMSImpl.objectiveModeField), mode);
UnsafeUtilities.setField(objectiveHealthDisplayField, packet, IScoreboardCriteria.EnumScoreboardHealthDisplay.INTEGER);
updateDisplayName(packet, displayName, locale);
@Override
protected void sendObjectivePacket(Collection<Player> players, boolean create) {
if (sidebar.locale() != null) {
impl.sendPacket(players, create ? createPacket : updatePacket);
} else {
ScoreboardManagerNMS.sendLocalePackets(sidebar.locale(), impl, players, locale -> {
PacketPlayOutScoreboardObjective packet = new PacketPlayOutScoreboardObjective();
createObjectivePacket(packet, create ? 0 : 2, sidebar.title(), locale);
return packet;
});
}
}
private void updateDisplayName(PacketPlayOutScoreboardObjective packet, Component displayName, Locale locale) {
String value = LegacyFormatUtil.serialize(sidebar.componentTranslator(), displayName, locale);
UnsafeUtilities.setField(objectiveDisplayNameField, packet, value);
}
@Override
public void removeLine(Collection<Player> players, String line) {
impl.sendPacket(players, new PacketPlayOutScoreboardScore(line));
}
@Override
public void updateTitle(Component displayName) {
Locale locale = sidebar.locale();
if (locale != null) {
updateDisplayName(createPacket, displayName, locale);
updateDisplayName(updatePacket, displayName, locale);
}
}
@Override
protected void sendObjectivePacket(Collection<Player> players, boolean create) {
if (sidebar.locale() != null) {
impl.sendPacket(players, create ? createPacket : updatePacket);
} else {
ScoreboardManagerNMS.sendLocalePackets(sidebar.locale(), impl, players, locale -> {
PacketPlayOutScoreboardObjective packet = new PacketPlayOutScoreboardObjective();
createObjectivePacket(packet, create ? 0 : 2, sidebar.title(), locale);
return packet;
});
}
}
@Override
public void removeLine(Collection<Player> players, String line) {
impl.sendPacket(players, new PacketPlayOutScoreboardScore(line));
}
@Override
public void score(Collection<Player> players, int score, String line) {
PacketPlayOutScoreboardScore packet = new PacketPlayOutScoreboardScore();
UnsafeUtilities.setField(scoreNameField, packet, line);
UnsafeUtilities.setField(scoreObjectiveNameField, packet, impl.objectiveName);
UnsafeUtilities.UNSAFE.putInt(packet, UnsafeUtilities.UNSAFE.objectFieldOffset(scoreScoreField), score);
UnsafeUtilities.setField(scoreActionField, packet, PacketPlayOutScoreboardScore.EnumScoreboardAction.CHANGE);
impl.sendPacket(players, packet);
}
@Override
public void score(Collection<Player> players, int score, String line) {
PacketPlayOutScoreboardScore packet = new PacketPlayOutScoreboardScore();
UnsafeUtilities.setField(scoreNameField, packet, line);
UnsafeUtilities.setField(scoreObjectiveNameField, packet, impl.objectiveName);
UnsafeUtilities.UNSAFE.putInt(packet, UnsafeUtilities.UNSAFE.objectFieldOffset(scoreScoreField), score);
UnsafeUtilities.setField(scoreActionField, packet, PacketPlayOutScoreboardScore.EnumScoreboardAction.CHANGE);
impl.sendPacket(players, packet);
}
}
@@ -19,124 +19,124 @@ import static net.megavex.scoreboardlibrary.internal.nms.base.util.LegacyFormatU
public class TeamNMSImpl extends TeamNMS<Packet<?>, NMSImpl> {
private static final Field teamNameField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "a"),
teamDisplayNameField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "b"),
teamPrefixField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "c"),
teamSuffixField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "d"),
teamNameTagVisibilityField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "e"),
teamEntriesField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "g"),
teamModeField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "h"),
teamRulesField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "i");
private static final Field teamNameField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "a"),
teamDisplayNameField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "b"),
teamPrefixField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "c"),
teamSuffixField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "d"),
teamNameTagVisibilityField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "e"),
teamEntriesField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "g"),
teamModeField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "h"),
teamRulesField = UnsafeUtilities.getField(PacketPlayOutScoreboardTeam.class, "i");
protected PacketPlayOutScoreboardTeam removePacket;
protected PacketPlayOutScoreboardTeam removePacket;
public TeamNMSImpl(NMSImpl impl, String teamName) {
super(impl, teamName);
public TeamNMSImpl(NMSImpl impl, String teamName) {
super(impl, teamName);
}
@Override
public void removeTeam(Iterable<Player> players) {
if (removePacket == null) {
removePacket = new PacketPlayOutScoreboardTeam();
UnsafeUtilities.setField(teamNameField, removePacket, teamName);
UnsafeUtilities.UNSAFE.putInt(removePacket, UnsafeUtilities.UNSAFE.objectFieldOffset(teamModeField), MODE_REMOVE);
}
impl.sendPacket(players, removePacket);
}
@Override
public TeamNMS.TeamInfoNMS<Component> createTeamInfoNMS(ImmutableTeamProperties<Component> properties, ComponentTranslator componentTranslator) {
return new AdventureTeamInfoNMS(properties, componentTranslator);
}
@Override
public TeamInfoNMS<String> createLegacyTeamInfoNMS(ImmutableTeamProperties<String> properties) {
return new LegacyTeamInfoNMS(properties);
}
private abstract class AbstractTeamInfoNMS<C> extends TeamNMS.TeamInfoNMS<C> {
public AbstractTeamInfoNMS(ImmutableTeamProperties<C> properties) {
super(properties);
}
@Override
public void removeTeam(Iterable<Player> players) {
if (removePacket == null) {
removePacket = new PacketPlayOutScoreboardTeam();
UnsafeUtilities.setField(teamNameField, removePacket, teamName);
UnsafeUtilities.UNSAFE.putInt(removePacket, UnsafeUtilities.UNSAFE.objectFieldOffset(teamModeField), MODE_REMOVE);
}
impl.sendPacket(players, removePacket);
public void addEntries(Collection<Player> players, Collection<String> entries) {
teamEntry(players, entries, MODE_ADD_ENTRIES);
}
@Override
public TeamNMS.TeamInfoNMS<Component> createTeamInfoNMS(ImmutableTeamProperties<Component> properties, ComponentTranslator componentTranslator) {
return new AdventureTeamInfoNMS(properties, componentTranslator);
public void removeEntries(Collection<Player> players, Collection<String> entries) {
teamEntry(players, entries, MODE_REMOVE_ENTRIES);
}
protected void teamEntry(Collection<Player> players, Collection<String> entries, int action) {
PacketPlayOutScoreboardTeam packet = new PacketPlayOutScoreboardTeam();
UnsafeUtilities.setField(teamNameField, packet, teamName);
UnsafeUtilities.UNSAFE.putInt(packet, UnsafeUtilities.UNSAFE.objectFieldOffset(teamModeField), action);
UnsafeUtilities.setField(teamEntriesField, packet, entries);
impl.sendPacket(players, packet);
}
@Override
public TeamInfoNMS<String> createLegacyTeamInfoNMS(ImmutableTeamProperties<String> properties) {
return new LegacyTeamInfoNMS(properties);
public void createTeam(Collection<Player> players) {
sendTeamPacket(false, players);
}
private abstract class AbstractTeamInfoNMS<C> extends TeamNMS.TeamInfoNMS<C> {
public AbstractTeamInfoNMS(ImmutableTeamProperties<C> properties) {
super(properties);
}
@Override
public void addEntries(Collection<Player> players, Collection<String> entries) {
teamEntry(players, entries, MODE_ADD_ENTRIES);
}
@Override
public void removeEntries(Collection<Player> players, Collection<String> entries) {
teamEntry(players, entries, MODE_REMOVE_ENTRIES);
}
protected void teamEntry(Collection<Player> players, Collection<String> entries, int action) {
PacketPlayOutScoreboardTeam packet = new PacketPlayOutScoreboardTeam();
UnsafeUtilities.setField(teamNameField, packet, teamName);
UnsafeUtilities.UNSAFE.putInt(packet, UnsafeUtilities.UNSAFE.objectFieldOffset(teamModeField), action);
UnsafeUtilities.setField(teamEntriesField, packet, entries);
impl.sendPacket(players, packet);
}
@Override
public void createTeam(Collection<Player> players) {
sendTeamPacket(false, players);
}
@Override
public void updateTeam(Collection<Player> players) {
sendTeamPacket(true, players);
}
private void sendTeamPacket(boolean update, Collection<Player> players) {
ScoreboardManagerNMS.sendLocalePackets(null, impl, players, locale -> {
String displayName = limitLegacyText(toLegacy(properties.displayName(), locale), TeamNMS.LEGACY_CHARACTER_LIMIT);
String prefix = limitLegacyText(toLegacy(properties.prefix(), locale), TeamNMS.LEGACY_CHARACTER_LIMIT);
String suffix = limitLegacyText(toLegacy(properties.suffix(), locale), TeamNMS.LEGACY_CHARACTER_LIMIT);
PacketPlayOutScoreboardTeam packet = new PacketPlayOutScoreboardTeam();
UnsafeUtilities.setField(teamNameField, packet, teamName);
UnsafeUtilities.UNSAFE.putInt(packet, UnsafeUtilities.UNSAFE.objectFieldOffset(teamModeField), update ? MODE_UPDATE : MODE_CREATE);
UnsafeUtilities.setField(teamDisplayNameField, packet, displayName);
UnsafeUtilities.setField(teamPrefixField, packet, prefix);
UnsafeUtilities.setField(teamSuffixField, packet, suffix);
UnsafeUtilities.setField(teamNameTagVisibilityField, packet, properties.nameTagVisibility().key());
UnsafeUtilities.UNSAFE.putInt(packet, UnsafeUtilities.UNSAFE.objectFieldOffset(teamRulesField), properties.packOptions());
if (!update) {
UnsafeUtilities.setField(teamEntriesField, packet, properties.entries());
}
return packet;
});
}
protected abstract String toLegacy(C component, Locale locale);
@Override
public void updateTeam(Collection<Player> players) {
sendTeamPacket(true, players);
}
private class AdventureTeamInfoNMS extends AbstractTeamInfoNMS<Component> {
private void sendTeamPacket(boolean update, Collection<Player> players) {
ScoreboardManagerNMS.sendLocalePackets(null, impl, players, locale -> {
String displayName = limitLegacyText(toLegacy(properties.displayName(), locale), TeamNMS.LEGACY_CHARACTER_LIMIT);
String prefix = limitLegacyText(toLegacy(properties.prefix(), locale), TeamNMS.LEGACY_CHARACTER_LIMIT);
String suffix = limitLegacyText(toLegacy(properties.suffix(), locale), TeamNMS.LEGACY_CHARACTER_LIMIT);
private final ComponentTranslator componentTranslator;
public AdventureTeamInfoNMS(ImmutableTeamProperties<Component> properties, ComponentTranslator componentTranslator) {
super(properties);
this.componentTranslator = componentTranslator;
PacketPlayOutScoreboardTeam packet = new PacketPlayOutScoreboardTeam();
UnsafeUtilities.setField(teamNameField, packet, teamName);
UnsafeUtilities.UNSAFE.putInt(packet, UnsafeUtilities.UNSAFE.objectFieldOffset(teamModeField), update ? MODE_UPDATE : MODE_CREATE);
UnsafeUtilities.setField(teamDisplayNameField, packet, displayName);
UnsafeUtilities.setField(teamPrefixField, packet, prefix);
UnsafeUtilities.setField(teamSuffixField, packet, suffix);
UnsafeUtilities.setField(teamNameTagVisibilityField, packet, properties.nameTagVisibility().key());
UnsafeUtilities.UNSAFE.putInt(packet, UnsafeUtilities.UNSAFE.objectFieldOffset(teamRulesField), properties.packOptions());
if (!update) {
UnsafeUtilities.setField(teamEntriesField, packet, properties.entries());
}
@Override
protected String toLegacy(Component component, Locale locale) {
return LegacyFormatUtil.serialize(componentTranslator, component, locale);
}
return packet;
});
}
private class LegacyTeamInfoNMS extends AbstractTeamInfoNMS<String> {
protected abstract String toLegacy(C component, Locale locale);
}
public LegacyTeamInfoNMS(ImmutableTeamProperties<String> properties) {
super(properties);
}
private class AdventureTeamInfoNMS extends AbstractTeamInfoNMS<Component> {
@Override
protected String toLegacy(String component, Locale locale) {
return component;
}
private final ComponentTranslator componentTranslator;
public AdventureTeamInfoNMS(ImmutableTeamProperties<Component> properties, ComponentTranslator componentTranslator) {
super(properties);
this.componentTranslator = componentTranslator;
}
@Override
protected String toLegacy(Component component, Locale locale) {
return LegacyFormatUtil.serialize(componentTranslator, component, locale);
}
}
private class LegacyTeamInfoNMS extends AbstractTeamInfoNMS<String> {
public LegacyTeamInfoNMS(ImmutableTeamProperties<String> properties) {
super(properties);
}
@Override
protected String toLegacy(String component, Locale locale) {
return component;
}
}
}