Skip to content

Commit

Permalink
Add support for Mojang mappings (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dominilk01 authored Jul 7, 2024
1 parent 402661c commit d9b2563
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 23 deletions.
21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
[![Maven Central](https://img.shields.io/maven-central/v/fr.mrmicky/fastboard.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/fr.mrmicky/fastboard)
[![Discord](https://img.shields.io/discord/390919659874156560.svg?colorB=5865f2&label=Discord&logo=discord&logoColor=white)](https://discord.gg/q9UwaBT)

Lightweight packet-based scoreboard API for Bukkit plugins, with 1.7.10 to 1.20.x support.
Lightweight packet-based scoreboard API for Bukkit plugins, compatible with all Minecraft versions starting with 1.7.10.

> [!IMPORTANT]
> To use FastBoard on a 1.8 server, the server must be on 1.8.8.
## Features

* No flickering (without using a buffer)
* Works with all versions from 1.7.10 to 1.20
* Compatible with all Minecraft versions starting with 1.7.10
* Small (around 750 lines of code with the JavaDoc) and no dependencies
* Easy to use
* Dynamic scoreboard size: you don't need to add/remove lines, you can directly give a string list (or array) to change all the lines
Expand All @@ -23,6 +23,7 @@ Lightweight packet-based scoreboard API for Bukkit plugins, with 1.7.10 to 1.20.
* [RGB HEX colors support](#rgb-colors) on 1.16 and higher
* [Custom number formatting](#custom-number-formatting) (including blank) for scores on 1.20.3 and higher
* [Adventure components support](#adventure-support)
* Support for both Spigot and Mojang mappings

## Installation

Expand Down Expand Up @@ -59,7 +60,7 @@ Lightweight packet-based scoreboard API for Bukkit plugins, with 1.7.10 to 1.20.
<dependency>
<groupId>fr.mrmicky</groupId>
<artifactId>fastboard</artifactId>
<version>2.1.2</version>
<version>2.1.3</version>
</dependency>
</dependencies>
```
Expand All @@ -79,7 +80,7 @@ repositories {
}
dependencies {
implementation 'fr.mrmicky:fastboard:2.1.2'
implementation 'fr.mrmicky:fastboard:2.1.3'
}
shadowJar {
Expand Down Expand Up @@ -187,24 +188,28 @@ public final class ExamplePlugin extends JavaPlugin implements Listener {

For servers on modern [PaperMC](https://papermc.io) versions, FastBoard supports
using [Adventure](https://github.com/KyoriPowered/adventure) components instead of strings,
by using the class `fr.mrmicky.fastboard.adventure.FastBoard`.
by using the `fr.mrmicky.fastboard.adventure.FastBoard` class.

> [!WARNING]
> With Adventure, on servers below Minecraft 1.13, lines are truncated to a maximum of 16 characters.
> To get around this limit, upgrade to a newer version of Minecraft or use the non-Adventure version (`fr.mrmicky.fastboard.FastBoard`).
## RGB colors

When using the non-Adventure version of FastBoard, RGB colors can be added on 1.16 and higher with `ChatColor.of("#RRGGBB")` (`net.md_5.bungee.api.ChatColor` import).

## Custom number formatting

For servers on Minecraft 1.20.3 and higher, FastBoard supports custom number formatting for scores.
By default, the blank format is used, so no score is visible, but it's also possible to specify custom scores using `FastBoard#updateLine(line, text, scoreText)`,
For servers on Minecraft 1.20.3 and above, FastBoard supports custom number formatting for scores.
By default, it uses the blank format, so that no score is visible, but it's also possible to set custom scores using `FastBoard#updateLine(line, text, scoreText)`,
`FastBoard#updateLines(lines, scores)` and `FastBoard#updateScore(line, text)`.

Passing a `null` value as a score will result in a reset to the default blank formatting.

## ViaBackwards compatibility

When using ViaBackwards on a post-1.13 server with pre-1.13 clients, older clients
might get incomplete lines. To solve this issue, you can override the method `hasLinesMaxLength()` and return `true` for older clients.
may receive incomplete lines. To solve this problem, you can override the `hasLinesMaxLength()` method and return `true` for older clients.
For example using the ViaVersion API:
```java
FastBoard board = new FastBoard(player) {
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>fr.mrmicky</groupId>
<artifactId>fastboard</artifactId>
<version>2.1.2</version>
<version>2.1.3</version>

<name>FastBoard</name>
<description>Lightweight packet-based scoreboard API for Bukkit plugins.</description>
Expand Down
30 changes: 16 additions & 14 deletions src/main/java/fr/mrmicky/fastboard/FastBoardBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
* The project is on <a href="https://github.com/MrMicky-FR/FastBoard">GitHub</a>.
*
* @author MrMicky
* @version 2.1.2
* @version 2.1.3
*/
public abstract class FastBoardBase<T> {

Expand Down Expand Up @@ -84,23 +84,25 @@ public abstract class FastBoardBase<T> {

if (FastReflection.isRepackaged()) {
VERSION_TYPE = VersionType.V1_17;
} else if (FastReflection.nmsOptionalClass(null, "ScoreboardServer$Action").isPresent()) {
} else if (FastReflection.nmsOptionalClass(null, "ScoreboardServer$Action").isPresent()
|| FastReflection.nmsOptionalClass(null, "ServerScoreboard$Method").isPresent()) {
VERSION_TYPE = VersionType.V1_13;
} else if (FastReflection.nmsOptionalClass(null, "IScoreboardCriteria$EnumScoreboardHealthDisplay").isPresent()) {
} else if (FastReflection.nmsOptionalClass(null, "IScoreboardCriteria$EnumScoreboardHealthDisplay").isPresent()
|| FastReflection.nmsOptionalClass(null, "ObjectiveCriteria$RenderType").isPresent()) {
VERSION_TYPE = VersionType.V1_8;
} else {
VERSION_TYPE = VersionType.V1_7;
}

String gameProtocolPackage = "network.protocol.game";
Class<?> craftPlayerClass = FastReflection.obcClass("entity.CraftPlayer");
Class<?> entityPlayerClass = FastReflection.nmsClass("server.level", "EntityPlayer");
Class<?> playerConnectionClass = FastReflection.nmsClass("server.network", "PlayerConnection");
Class<?> entityPlayerClass = FastReflection.nmsClass("server.level", "EntityPlayer", "ServerPlayer");
Class<?> playerConnectionClass = FastReflection.nmsClass("server.network", "PlayerConnection", "ServerGamePacketListenerImpl");
Class<?> packetClass = FastReflection.nmsClass("network.protocol", "Packet");
Class<?> packetSbObjClass = FastReflection.nmsClass(gameProtocolPackage, "PacketPlayOutScoreboardObjective");
Class<?> packetSbDisplayObjClass = FastReflection.nmsClass(gameProtocolPackage, "PacketPlayOutScoreboardDisplayObjective");
Class<?> packetSbScoreClass = FastReflection.nmsClass(gameProtocolPackage, "PacketPlayOutScoreboardScore");
Class<?> packetSbTeamClass = FastReflection.nmsClass(gameProtocolPackage, "PacketPlayOutScoreboardTeam");
Class<?> packetSbObjClass = FastReflection.nmsClass(gameProtocolPackage, "PacketPlayOutScoreboardObjective", "ClientboundSetObjectivePacket");
Class<?> packetSbDisplayObjClass = FastReflection.nmsClass(gameProtocolPackage, "PacketPlayOutScoreboardDisplayObjective", "ClientboundSetDisplayObjectivePacket");
Class<?> packetSbScoreClass = FastReflection.nmsClass(gameProtocolPackage, "PacketPlayOutScoreboardScore", "ClientboundSetScorePacket");
Class<?> packetSbTeamClass = FastReflection.nmsClass(gameProtocolPackage, "PacketPlayOutScoreboardTeam", "ClientboundSetPlayerTeamPacket");
Class<?> sbTeamClass = VersionType.V1_17.isHigherOrEqual()
? FastReflection.innerClass(packetSbTeamClass, innerClass -> !innerClass.isEnum()) : null;
Field playerConnectionField = Arrays.stream(entityPlayerClass.getFields())
Expand All @@ -113,8 +115,8 @@ public abstract class FastBoardBase<T> {
.filter(m -> m.getParameterCount() == 1 && m.getParameterTypes()[0] == packetClass)
.findFirst().orElseThrow(NoSuchMethodException::new);
Optional<Class<?>> displaySlotEnum = FastReflection.nmsOptionalClass("world.scores", "DisplaySlot");
CHAT_COMPONENT_CLASS = FastReflection.nmsClass("network.chat", "IChatBaseComponent");
CHAT_FORMAT_ENUM = FastReflection.nmsClass(null, "EnumChatFormat");
CHAT_COMPONENT_CLASS = FastReflection.nmsClass("network.chat", "IChatBaseComponent","Component");
CHAT_FORMAT_ENUM = FastReflection.nmsClass(null, "EnumChatFormat", "ChatFormatting");
DISPLAY_SLOT_TYPE = displaySlotEnum.orElse(int.class);
RESET_FORMATTING = FastReflection.enumValueOf(CHAT_FORMAT_ENUM, "RESET", 21);
SIDEBAR_DISPLAY_SLOT = displaySlotEnum.isPresent() ? FastReflection.enumValueOf(DISPLAY_SLOT_TYPE, "SIDEBAR", 1) : 1;
Expand Down Expand Up @@ -149,7 +151,7 @@ public abstract class FastBoardBase<T> {
packetSbResetScore = lookup.findConstructor(resetScoreClass, removeScoreType);
blankNumberFormat = blankField.isPresent() ? blankField.get().get(null) : null;
} else if (VersionType.V1_17.isHigherOrEqual()) {
Class<?> enumSbAction = FastReflection.nmsClass("server", "ScoreboardServer$Action");
Class<?> enumSbAction = FastReflection.nmsClass("server", "ScoreboardServer$Action", "ServerScoreboard$Method");
MethodType scoreType = MethodType.methodType(void.class, enumSbAction, String.class, String.class, int.class);
packetSbSetScore = lookup.findConstructor(packetSbScoreClass, scoreType);
} else {
Expand Down Expand Up @@ -181,8 +183,8 @@ public abstract class FastBoardBase<T> {
String enumSbActionClass = VersionType.V1_13.isHigherOrEqual()
? "ScoreboardServer$Action"
: "PacketPlayOutScoreboardScore$EnumScoreboardAction";
ENUM_SB_HEALTH_DISPLAY = FastReflection.nmsClass("world.scores.criteria", "IScoreboardCriteria$EnumScoreboardHealthDisplay");
ENUM_SB_ACTION = FastReflection.nmsClass("server", enumSbActionClass);
ENUM_SB_HEALTH_DISPLAY = FastReflection.nmsClass("world.scores.criteria", "IScoreboardCriteria$EnumScoreboardHealthDisplay", "ObjectiveCriteria$RenderType");
ENUM_SB_ACTION = FastReflection.nmsClass("server", enumSbActionClass, "ServerScoreboard$Method");
ENUM_SB_HEALTH_DISPLAY_INTEGER = FastReflection.enumValueOf(ENUM_SB_HEALTH_DISPLAY, "INTEGER", 0);
ENUM_SB_ACTION_CHANGE = FastReflection.enumValueOf(ENUM_SB_ACTION, "CHANGE", 0);
ENUM_SB_ACTION_REMOVE = FastReflection.enumValueOf(ENUM_SB_ACTION, "REMOVE", 1);
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/fr/mrmicky/fastboard/FastReflection.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public final class FastReflection {

private static final MethodType VOID_METHOD_TYPE = MethodType.methodType(void.class);
private static final boolean NMS_REPACKAGED = optionalClass(NM_PACKAGE + ".network.protocol.Packet").isPresent();
private static final boolean MOJANG_MAPPINGS = optionalClass(NM_PACKAGE + ".network.chat.Component").isPresent();

private static volatile Object theUnsafe;

Expand All @@ -70,6 +71,10 @@ public static Class<?> nmsClass(String post1_17package, String className) throws
return Class.forName(nmsClassName(post1_17package, className));
}

public static Class<?> nmsClass(String post1_17package, String spigotClass, String mojangClass) throws ClassNotFoundException {
return nmsClass(post1_17package, MOJANG_MAPPINGS ? mojangClass : spigotClass);
}

public static Optional<Class<?>> nmsOptionalClass(String post1_17package, String className) {
return optionalClass(nmsClassName(post1_17package, className));
}
Expand Down

0 comments on commit d9b2563

Please sign in to comment.