Skip to content
This repository was archived by the owner on Jan 24, 2024. It is now read-only.

Commit 7a1893b

Browse files
authored
Merge pull request #1 from CherryCraftMC/scoreboard-system
Implement Scoreboard system and utilities
2 parents fd17349 + 3962810 commit 7a1893b

File tree

7 files changed

+1091
-0
lines changed

7 files changed

+1091
-0
lines changed

src/main/java/net/cherrycraft/cherrycore/CherryCore.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public void onEnable() {
2626
languageManager.loadAllLanguages();
2727
Loader.registerCommands(this);
2828
Loader.registerListeners(this);
29+
Loader.registerTasks(this);
2930
Loader.loadWorlds(this);
3031
logger.info("ReefCore has been enabled.");
3132
}

src/main/java/net/cherrycraft/cherrycore/Loader.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import net.cherrycraft.cherrycore.languageSystem.command.LanguageCommand;
66
import net.cherrycraft.cherrycore.manager.CommandManager;
77
import net.cherrycraft.cherrycore.manager.LanguageManager;
8+
import net.cherrycraft.cherrycore.scoreboard.Scoreboard;
89
import org.bukkit.Bukkit;
910
import org.bukkit.event.Listener;
1011

@@ -27,6 +28,12 @@ public static void registerListeners(CherryCore plugin) {
2728
Bukkit.getPluginManager().registerEvents(new ChatHistoryLogger(), plugin);
2829
Bukkit.getPluginManager().registerEvents(new LanguageManager(), plugin);
2930
Bukkit.getPluginManager().registerEvents(new ChatSystem(), plugin);
31+
Bukkit.getPluginManager().registerEvents(new Scoreboard(), plugin);
32+
}
33+
34+
public static void registerTasks(CherryCore plugin) {
35+
Scoreboard scoreboard = new Scoreboard();
36+
3037
}
3138

3239
public static void loadWorlds(CherryCore plugin) {
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package net.cherrycraft.cherrycore.scoreboard;
2+
3+
import me.clip.placeholderapi.PlaceholderAPI;
4+
import net.cherrycraft.cherrycore.CherryCore;
5+
import net.cherrycraft.cherrycore.utils.scoreboard.adventure.ScoreboardSystem;
6+
import net.kyori.adventure.text.minimessage.MiniMessage;
7+
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
8+
import org.bukkit.Bukkit;
9+
import org.bukkit.entity.Player;
10+
import org.bukkit.event.EventHandler;
11+
import org.bukkit.event.EventPriority;
12+
import org.bukkit.event.Listener;
13+
import org.bukkit.event.player.PlayerJoinEvent;
14+
import org.bukkit.event.player.PlayerQuitEvent;
15+
16+
import java.util.HashMap;
17+
import java.util.Map;
18+
import java.util.UUID;
19+
20+
public class Scoreboard implements Listener {
21+
22+
private final Map<UUID, ScoreboardSystem> boards = new HashMap<>();
23+
MiniMessage miniMessage = MiniMessage.builder().build();
24+
LegacyComponentSerializer serializer = LegacyComponentSerializer.legacySection();
25+
26+
private String serverType;
27+
28+
@EventHandler
29+
public void playerQuit(PlayerQuitEvent event) {
30+
Player player = event.getPlayer();
31+
32+
ScoreboardSystem board = this.boards.remove(player.getUniqueId());
33+
34+
if (board != null) {
35+
board.delete();
36+
}
37+
38+
}
39+
40+
@EventHandler(priority = EventPriority.HIGHEST)
41+
public void playerJoin(PlayerJoinEvent event) {
42+
Player player = event.getPlayer();
43+
String serverType = CherryCore.getInstance().getConfig().getString("server-type");
44+
45+
if (serverType == null) {
46+
serverType = CherryCore.getInstance().getConfig().getString("server-type");
47+
48+
if (serverType == null) {
49+
Bukkit.getLogger().severe("Server type is not set in the config file.");
50+
return;
51+
}
52+
}
53+
54+
switch (serverType) {
55+
case "skypvp":
56+
setupSkyPVPScoreboard(player);
57+
System.out.println("SkyPVP scoreboard set up for " + player.getName());
58+
break;
59+
case "lobby":
60+
setupLobbyScoreboard(player);
61+
System.out.println("Lobby scoreboard set up for " + player.getName());
62+
break;
63+
default:
64+
Bukkit.getLogger().severe("Unknown server type: " + serverType);
65+
break;
66+
}
67+
}
68+
69+
70+
private void setupSkyPVPScoreboard(Player player) {
71+
ScoreboardSystem scoreboard = new ScoreboardSystem(player);
72+
scoreboard.updateTitle(miniMessage.deserialize("<#C81F3B><bold>Cherry<#31AF14><bold>Craft"));
73+
updateBoardSkyPVP(scoreboard);
74+
Bukkit.getScheduler().runTaskTimerAsynchronously(CherryCore.getInstance(), () -> {
75+
for (ScoreboardSystem board : this.boards.values()) {
76+
updateBoardSkyPVP(board);
77+
}
78+
}, 0L, 20L);
79+
80+
this.boards.put(player.getUniqueId(), scoreboard);
81+
}
82+
83+
private void setupLobbyScoreboard(Player player) {
84+
ScoreboardSystem scoreboard = new ScoreboardSystem(player);
85+
scoreboard.updateTitle(miniMessage.deserialize("<#C81F3B><bold>Cherry<#31AF14><bold>Craft"));
86+
updateBoardLobby(scoreboard);
87+
Bukkit.getScheduler().runTaskTimerAsynchronously(CherryCore.getInstance(), () -> {
88+
for (ScoreboardSystem board : this.boards.values()) {
89+
updateBoardLobby(board);
90+
}
91+
}, 0L, 20L);
92+
this.boards.put(player.getUniqueId(), scoreboard);
93+
}
94+
95+
private void updateBoardSkyPVP(ScoreboardSystem board) {
96+
board.updateLines(
97+
98+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "")),
99+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "<white>Level <#31AF14>%reefrealmskypvp_level%")),
100+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "<white>Progress: <#31AF14>%reefrealmskypvp_required_score%")),
101+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "<gray>[%reefrealmskypvp_progress%<gray>]")),
102+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "")),
103+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "<white>Coins: <#31AF14>%reefrealmskypvp_coins%")),
104+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "")),
105+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "<white>K/D: <#31AF14>%reefrealmskypvp_kd%")),
106+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "<white>Kills: <#31AF14>%reefrealmskypvp_kills%")),
107+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "<white>Deaths: <#31AF14>%reefrealmskypvp_deaths%")),
108+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "<white>Killstreak: <#31AF14>%reefrealmskypvp_killstreak%")),
109+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "")),
110+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "<#C81F3B>cherrycraft.net"))
111+
);
112+
}
113+
114+
private void updateBoardLobby(ScoreboardSystem board) {
115+
board.updateLines(
116+
117+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "")),
118+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "<white>Rank %luckperms_prefix%")),
119+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "")),
120+
miniMessage.deserialize(PlaceholderAPI.setPlaceholders(board.getPlayer(), "<#C81F3B>cherrycraft.net"))
121+
);
122+
}
123+
124+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package net.cherrycraft.cherrycore.utils.scoreboard;
2+
3+
import org.bukkit.Bukkit;
4+
5+
import java.lang.invoke.MethodHandle;
6+
import java.lang.invoke.MethodHandles;
7+
import java.lang.invoke.MethodType;
8+
import java.lang.reflect.Field;
9+
import java.util.Optional;
10+
import java.util.function.Predicate;
11+
12+
/**
13+
* Small reflection utility class to use CraftBukkit and NMS.
14+
*
15+
* @author MrMicky
16+
*/
17+
public final class FastReflection {
18+
19+
public static final String OBC_PACKAGE = "org.bukkit.craftbukkit";
20+
public static final String VERSION = Bukkit.getServer().getClass().getPackage().getName().substring(OBC_PACKAGE.length() + 1);
21+
private static final String NM_PACKAGE = "net.minecraft";
22+
public static final String NMS_PACKAGE = NM_PACKAGE + ".server";
23+
private static final MethodType VOID_METHOD_TYPE = MethodType.methodType(void.class);
24+
private static final boolean NMS_REPACKAGED = optionalClass(NM_PACKAGE + ".network.protocol.Packet").isPresent();
25+
26+
private static volatile Object theUnsafe;
27+
28+
private FastReflection() {
29+
throw new UnsupportedOperationException();
30+
}
31+
32+
public static boolean isRepackaged() {
33+
return NMS_REPACKAGED;
34+
}
35+
36+
public static String nmsClassName(String post1_17package, String className) {
37+
if (NMS_REPACKAGED) {
38+
String classPackage = post1_17package == null ? NM_PACKAGE : NM_PACKAGE + '.' + post1_17package;
39+
return classPackage + '.' + className;
40+
}
41+
return NMS_PACKAGE + '.' + VERSION + '.' + className;
42+
}
43+
44+
public static Class<?> nmsClass(String post1_17package, String className) throws ClassNotFoundException {
45+
return Class.forName(nmsClassName(post1_17package, className));
46+
}
47+
48+
public static Optional<Class<?>> nmsOptionalClass(String post1_17package, String className) {
49+
return optionalClass(nmsClassName(post1_17package, className));
50+
}
51+
52+
public static String obcClassName(String className) {
53+
return OBC_PACKAGE + '.' + VERSION + '.' + className;
54+
}
55+
56+
public static Class<?> obcClass(String className) throws ClassNotFoundException {
57+
return Class.forName(obcClassName(className));
58+
}
59+
60+
public static Optional<Class<?>> obcOptionalClass(String className) {
61+
return optionalClass(obcClassName(className));
62+
}
63+
64+
public static Optional<Class<?>> optionalClass(String className) {
65+
try {
66+
return Optional.of(Class.forName(className));
67+
} catch (ClassNotFoundException e) {
68+
return Optional.empty();
69+
}
70+
}
71+
72+
public static Object enumValueOf(Class<?> enumClass, String enumName) {
73+
return Enum.valueOf(enumClass.asSubclass(Enum.class), enumName);
74+
}
75+
76+
public static Object enumValueOf(Class<?> enumClass, String enumName, int fallbackOrdinal) {
77+
try {
78+
return enumValueOf(enumClass, enumName);
79+
} catch (IllegalArgumentException e) {
80+
Object[] constants = enumClass.getEnumConstants();
81+
if (constants.length > fallbackOrdinal) {
82+
return constants[fallbackOrdinal];
83+
}
84+
throw e;
85+
}
86+
}
87+
88+
static Class<?> innerClass(Class<?> parentClass, Predicate<Class<?>> classPredicate) throws ClassNotFoundException {
89+
for (Class<?> innerClass : parentClass.getDeclaredClasses()) {
90+
if (classPredicate.test(innerClass)) {
91+
return innerClass;
92+
}
93+
}
94+
throw new ClassNotFoundException("No class in " + parentClass.getCanonicalName() + " matches the predicate.");
95+
}
96+
97+
public static PacketConstructor findPacketConstructor(Class<?> packetClass, MethodHandles.Lookup lookup) throws Exception {
98+
try {
99+
MethodHandle constructor = lookup.findConstructor(packetClass, VOID_METHOD_TYPE);
100+
return constructor::invoke;
101+
} catch (NoSuchMethodException | IllegalAccessException e) {
102+
// try below with Unsafe
103+
}
104+
105+
if (theUnsafe == null) {
106+
synchronized (FastReflection.class) {
107+
if (theUnsafe == null) {
108+
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
109+
Field theUnsafeField = unsafeClass.getDeclaredField("theUnsafe");
110+
theUnsafeField.setAccessible(true);
111+
theUnsafe = theUnsafeField.get(null);
112+
}
113+
}
114+
}
115+
116+
MethodType allocateMethodType = MethodType.methodType(Object.class, Class.class);
117+
MethodHandle allocateMethod = lookup.findVirtual(theUnsafe.getClass(), "allocateInstance", allocateMethodType);
118+
return () -> allocateMethod.invoke(theUnsafe, packetClass);
119+
}
120+
121+
@FunctionalInterface
122+
interface PacketConstructor {
123+
Object invoke() throws Throwable;
124+
}
125+
}

0 commit comments

Comments
 (0)