Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -671,4 +671,4 @@ into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Bungeecord-Expansion
Expansion for bungeecord placeholders
[![Build Status](http://ci.extendedclip.com/buildStatus/icon?job=Bungeecord-Expansion)](http://ci.extendedclip.com/job/Bungeecord-Expansion/)
# BungeeCord-Expansion
Expansion for BungeeCord placeholders
[![Build Status](http://ci.extendedclip.com/buildStatus/icon?job=BungeeCord-Expansion)](http://ci.extendedclip.com/job/BungeeCord-Expansion/)
31 changes: 21 additions & 10 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.extendedclip.papi.bungeeexpansion</groupId>
<artifactId>bungee-expansion</artifactId>
<version>2.2</version>
<version>3.0</version>

<name>Expansion-Bungee</name>
<description>PlaceholderAPI expansion for bungeecord placeholders</description>
<description>PlaceholderAPI expansion for BungeeCord placeholders.</description>

<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>25</maven.compiler.source>
<maven.compiler.target>25</maven.compiler.target>

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<project.build.propertiesEncoding>UTF-8</project.build.propertiesEncoding>

<java.version>25</java.version>
</properties>

<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>

<repository>
<id>placeholderapi</id>
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
Expand All @@ -29,34 +38,36 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.15.2-R0.1-SNAPSHOT</version>
<version>[26.1.2.build,)</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.10.6</version>
<version>2.12.2</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<finalName>${project.name}-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<version>3.5.0</version>
<configuration>
<finalName>${project.name}</finalName>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<manifest>
<addClasspath>false</addClasspath>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>

</project>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import me.clip.placeholderapi.expansion.Configurable;
Expand All @@ -12,14 +11,18 @@
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.bukkit.scheduler.BukkitTask;
import org.jspecify.annotations.NonNull;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.logging.Level;
Expand All @@ -33,76 +36,66 @@ public final class BungeeExpansion extends PlaceholderExpansion implements Plugi

private static final Splitter SPLITTER = Splitter.on(",").trimResults();

private final Map<String, Integer> counts = new ConcurrentHashMap<>();
private final AtomicReference<ScheduledFuture<?>> cached = new AtomicReference<>();

private final Map<String, Integer> counts = new HashMap<>();
private final AtomicReference<BukkitTask> cached = new AtomicReference<>();

private static Field inputField;

static {
try {
inputField = Class.forName("com.google.common.io.ByteStreams$ByteArrayDataInputStream").getDeclaredField("input");
inputField.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
private ScheduledExecutorService executor;

@Override
@NonNull
public String getIdentifier() {
return "bungee";
}

@Override
@NonNull
public String getAuthor() {
return "clip";
}

@Override
@NonNull
public String getVersion() {
return "2.3";
return "3.0";
}

@Override
public Map<String, Object> getDefaults() {
return Collections.singletonMap(CONFIG_INTERVAL, 30);
}


@Override
public String onRequest(final OfflinePlayer player, String identifier) {
final int value;

switch (identifier.toLowerCase()) {
case "all":
case "total":
value = counts.values().stream().mapToInt(Integer::intValue).sum();
break;
default:
value = counts.getOrDefault(identifier.toLowerCase(), 0);
break;
}
final int value = switch (identifier.toLowerCase()) {
case "all", "total" -> counts.values().stream().mapToInt(Integer::intValue).sum();
default -> counts.getOrDefault(identifier.toLowerCase(), 0);
};

return String.valueOf(value);
}

@Override
public void start() {
final BukkitTask task = Bukkit.getScheduler().runTaskTimer(getPlaceholderAPI(), () -> {
if (executor == null) {
executor = Executors.newSingleThreadScheduledExecutor(r -> {
final Thread thread = new Thread(r, "BungeeExpansion-Scheduler");
thread.setDaemon(true);
return thread;
});
}

final ScheduledFuture<?> task = executor.scheduleAtFixedRate(() -> {

if (counts.isEmpty()) {
sendServersChannelMessage();
}
else {
} else {
counts.keySet().forEach(this::sendPlayersChannelMessage);
}
}, 2L, getLong(CONFIG_INTERVAL, 30), TimeUnit.SECONDS);

}, 20L * 2L, 20L * getLong(CONFIG_INTERVAL, 30));


final BukkitTask prev = cached.getAndSet(task);
final ScheduledFuture<?> prev = cached.getAndSet(task);
if (prev != null) {
prev.cancel();
prev.cancel(false);
} else {
Bukkit.getMessenger().registerOutgoingPluginChannel(getPlaceholderAPI(), MESSAGE_CHANNEL);
Bukkit.getMessenger().registerIncomingPluginChannel(getPlaceholderAPI(), MESSAGE_CHANNEL, this);
Expand All @@ -111,69 +104,72 @@ public void start() {

@Override
public void stop() {
final BukkitTask prev = cached.getAndSet(null);
final ScheduledFuture<?> prev = cached.getAndSet(null);
if (prev == null) {
return;
}

prev.cancel();
prev.cancel(false);
counts.clear();

if (executor != null) {
executor.shutdownNow();
executor = null;
}

Bukkit.getMessenger().unregisterOutgoingPluginChannel(getPlaceholderAPI(), MESSAGE_CHANNEL);
Bukkit.getMessenger().unregisterIncomingPluginChannel(getPlaceholderAPI(), MESSAGE_CHANNEL, this);
}


@Override
public void onPluginMessageReceived(final String channel, final Player player, final byte[] message) {
public void onPluginMessageReceived(final @NonNull String channel, final @NonNull Player player, final byte @NonNull [] message) {
if (!MESSAGE_CHANNEL.equals(channel)) {
return;
}

//noinspection UnstableApiUsage
final ByteArrayDataInput in = ByteStreams.newDataInput(message);
try {
DataInputStream stream = (DataInputStream) inputField.get(in);
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(message))) {
switch (in.readUTF()) {
case PLAYERS_CHANNEL:
if (stream.available() == 0) return; // how ?
final String server = in.readUTF();
if (stream.available() == 0) { // how ? x2
getPlaceholderAPI().getLogger().log(Level.SEVERE, String.format("[%s] Could not get the player count from server %s.", getName(), server));
counts.put(server.toLowerCase(), 0);
} else counts.put(server.toLowerCase(), in.readInt());
break;
case SERVERS_CHANNEL:
SPLITTER.split(in.readUTF()).forEach(serverName -> counts.putIfAbsent(serverName.toLowerCase(), 0));
break;
case PLAYERS_CHANNEL -> {
if (in.available() == 0) {
return;
}

final String server = in.readUTF();
if (in.available() == 0) {
getPlaceholderAPI().getLogger().log(Level.SEVERE, String.format("[%s] Could not get the player count from server %s.", getName(), server));
counts.put(server.toLowerCase(), 0);
} else {
counts.put(server.toLowerCase(), in.readInt());
}
}
case SERVERS_CHANNEL ->
SPLITTER.split(in.readUTF()).forEach(serverName -> counts.putIfAbsent(serverName.toLowerCase(), 0));
}
} catch (Exception e) {
e.printStackTrace();
getPlaceholderAPI().getLogger().log(Level.SEVERE, String.format("[%s] Failed to handle plugin message on channel %s.", getName(), channel), e);
}
}


private void sendServersChannelMessage() {
sendMessage(SERVERS_CHANNEL, out -> { });
sendMessage(SERVERS_CHANNEL, _ -> {
});
}

private void sendPlayersChannelMessage(final String serverName) {
sendMessage(PLAYERS_CHANNEL, out -> out.writeUTF(serverName));
}

private void sendMessage(final String channel, final Consumer<ByteArrayDataOutput> consumer) {
final Player player = Iterables.getFirst(Bukkit.getOnlinePlayers(), null);
final Player player = Iterables.getFirst(new ArrayList<>(Bukkit.getOnlinePlayers()), null);
if (player == null) {
return;
}

//noinspection UnstableApiUsage
final ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF(channel);

consumer.accept(out);

player.sendPluginMessage(getPlaceholderAPI(), MESSAGE_CHANNEL, out.toByteArray());
}

}
}