mirror of
https://github.com/MiniPlaceholders/MiniPlaceholders.git
synced 2026-11-04 16:50:11 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a084a6d2e | ||
|
|
d02ac7abc1 | ||
|
|
9bcefee265 | ||
|
|
47dd5a96e9 | ||
|
|
36dbeed21d | ||
|
|
e19527a9d6 | ||
|
|
f648dd8f83 | ||
|
|
079b88d99f | ||
|
|
0f48a4baed | ||
|
|
2608e81fae | ||
|
|
afb4a4451d | ||
|
|
df53a0a2fa | ||
|
|
591df2e6df | ||
|
|
bf995b7103 | ||
|
|
02f30ead85 | ||
|
|
f522456b76 | ||
|
|
de7d14d55d | ||
|
|
c0230efb3b | ||
|
|
3cdb7de9f2 | ||
|
|
9c954834cb | ||
|
|
55e493c013 | ||
|
|
ea725a8121 | ||
|
|
d138d00b26 | ||
|
|
d63397fc96 | ||
|
|
fe6ea73bb0 | ||
|
|
be368a7690 | ||
|
|
b31b91e9b8 | ||
|
|
7d8243711a | ||
|
|
7633ada70e | ||
|
|
6d8267684a | ||
|
|
a1d5bb7eed | ||
|
|
161a254613 | ||
|
|
d957269743 | ||
|
|
7ac5aec82d | ||
|
|
9713704352 | ||
|
|
4240fb556c | ||
|
|
5a9ac8af87 | ||
|
|
97b68a3616 | ||
|
|
afde5e6e2c | ||
|
|
8a37136565 | ||
|
|
8d5378ff3e | ||
|
|
31ee16e412 | ||
|
|
8aec3e592f | ||
|
|
88c26dee51 | ||
|
|
659be54911 | ||
|
|
3808d660d9 | ||
|
|
c6ecdacdbc | ||
|
|
25a9b435ff | ||
|
|
d95b9fddac | ||
|
|
78d1b83513 | ||
|
|
56a1e9afca | ||
|
|
ba1438457b | ||
|
|
ad36fab536 | ||
|
|
f2ff2c0bf3 | ||
|
|
6e28786b09 | ||
|
|
f67690f413 | ||
|
|
cc8646cb4e | ||
|
|
4db80d7583 | ||
|
|
67d480c969 |
No files matched your search
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
MiniPlaceholders Changelog
|
||||
-->
|
||||
|
||||
## 3.1.0 (10/10/2025)
|
||||
|
||||
### Features
|
||||
|
||||
- [feat: Sponge commands implementation](https://github.com/MiniPlaceholders/MiniPlaceholders/commit/7633ada70ed62571b707cbf709fbb5c027c44f46)
|
||||
- [feat: Implement parserel subcommand](https://github.com/MiniPlaceholders/MiniPlaceholders/commit/ea725a81210911a8779545781b56a647d6b84cf3)
|
||||
- [feat: Add --null argument to parse node](https://github.com/MiniPlaceholders/MiniPlaceholders/commit/3cdb7de9f2e675f494c84df693142a817535fe9a)
|
||||
- [misc: Added bstats metrics](https://github.com/MiniPlaceholders/MiniPlaceholders/commit/f648dd8f836d5f2911eaf0bc53f6769ed2a0fdcc)
|
||||
|
||||
### Fixes
|
||||
|
||||
- [fix: Fixed multiple loading expansions](https://github.com/MiniPlaceholders/MiniPlaceholders/commit/f67690f41347031a32d4acd7bb4bb493b42bb4f9)
|
||||
- [fix: Added nullability checks to RelationalAudience](https://github.com/MiniPlaceholders/MiniPlaceholders/commit/8aec3e592ff6774737602a3a3a6187ddb577a681)
|
||||
- [fix: Fixed command formatting](https://github.com/MiniPlaceholders/MiniPlaceholders/commit/de7d14d55d6aeff8dbaf1706dd06bb6812b54390)
|
||||
|
||||
|
||||
### API Additions
|
||||
|
||||
- [feat: Added LoadRequirement#requiredClass and LoadRequirement#anyOf](https://github.com/MiniPlaceholders/MiniPlaceholders/commit/31ee16e41234cabf992736f81eda5bbbdc09d954)
|
||||
- [docs: Replaced some uses of JetBrains annotations with jspecify](https://github.com/MiniPlaceholders/MiniPlaceholders/commit/0f48a4baed91ec5d0fe285649822f189e69a5b57)
|
||||
- [feat: Allow the use of injected constructors when creating an ExpansionProvider](https://github.com/MiniPlaceholders/MiniPlaceholders/commit/bf995b71030064a174532d38282407ab6baa7170)
|
||||
|
||||
@@ -1,45 +1,30 @@
|
||||
# MiniPlaceholders
|
||||
[](https://github.com/MiniPlaceholders/MiniPlaceholders/actions)
|
||||
[](https://github.com/MiniPlaceholders/MiniPlaceholders/actions)
|
||||
[](https://ci.codemc.io/job/MiniPlaceholders/job/MiniPlaceholders/)
|
||||

|
||||
[](https://discord.gg/5NMMzK5mAn)
|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
MiniMessage Component-based Placeholders API for Minecraft Platforms.
|
||||
|
||||
## Compatibility
|
||||
- Paper 1.19.3, 1.19.4+
|
||||
- Folia 1.19.4+
|
||||
- Velocity 3.1.2+
|
||||
- Fabric 1.19.4+
|
||||
- Sponge API 8+
|
||||
|
||||
## Commands
|
||||
|
||||
### Velocity
|
||||
|
||||
- `/vminiplaceholders parse me "[message with placeholders]"`
|
||||
- `/vminiplaceholders parse player [some-player] "[message with placeholders]"`
|
||||
|
||||
### Paper | Folia | Fabric
|
||||
|
||||
- `/miniplaceholders <parse|help> player [some-player] "[message with placeholders]`
|
||||
- `/miniplaceholders parse player [some-player] "[message with placeholders]"`
|
||||
|
||||
#### Example:
|
||||
|
||||
- `/miniplaceholders parse me "<player_xp>"`
|
||||
- `/vminiplaceholders parse player 4drian3d "<player_name>"`
|
||||
- Paper 1.21+
|
||||
- Velocity 3.4+
|
||||
- Fabric 1.21.6+
|
||||
- Sponge API 12+
|
||||
|
||||
## User Usage
|
||||
|
||||
Check our user usage wiki [here](https://github.com/MiniPlaceholders/MiniPlaceholders/wiki/User-Getting-Started)
|
||||
Check our user usage wiki [here](https://miniplaceholders.github.io/docs/user-guide/User-Getting-Started)
|
||||
|
||||
## API
|
||||
|
||||
Check the available [Javadocs](https://javadoc.io/doc/io.github.miniplaceholders/miniplaceholders-api)
|
||||
|
||||
Or check the [Developer Wiki](https://github.com/MiniPlaceholders/MiniPlaceholders/wiki/Developer-Getting-Started)
|
||||
Or check the [Developer Wiki](https://miniplaceholders.github.io/docs/developer-guide/Developer-Getting-Started)
|
||||
|
||||
### Java
|
||||
```java
|
||||
@@ -47,9 +32,7 @@ Or check the [Developer Wiki](https://github.com/MiniPlaceholders/MiniPlaceholde
|
||||
class Main {
|
||||
public static void registerExpansion() {
|
||||
final Expansion expansion = Expansion.builder("my-expansion")
|
||||
.filter(Player.class)
|
||||
.audiencePlaceholder("name", (audience, ctx, queue) -> {
|
||||
final Player player = (player) audience;
|
||||
.audiencePlaceholder(Player.class, "name", (player, ctx, queue) -> {
|
||||
return Tag.selfClosingInserting(player.getName());
|
||||
})
|
||||
.globalPlaceholder("tps", (ctx, queue) ->
|
||||
@@ -59,8 +42,8 @@ class Main {
|
||||
expansion.register();
|
||||
|
||||
Player player;
|
||||
final TagResolver playerResolver = MiniPlaceholders.getAudiencePlaceholders(player);
|
||||
player.sendMessage(miniMessage().deserialize("Player Name: <my-expansion_name>", playerResolver));
|
||||
final TagResolver playerResolver = MiniPlaceholders.audiencePlaceholders();
|
||||
player.sendMessage(miniMessage().deserialize("Player Name: <my-expansion_name>", player, playerResolver));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,10 +53,10 @@ class Main {
|
||||
```kotlin
|
||||
fun register() {
|
||||
val expansion = expansion("my-expansion") {
|
||||
audiencePlaceholder("name") { aud, _, _ ->
|
||||
audience<Player>("name") { player, _, _ ->
|
||||
aud.getName().asClosingTag()
|
||||
}
|
||||
globalPlaceholder("tps") { _, _ ->
|
||||
global("tps") { _, _ ->
|
||||
Component.text(Bukkit.getTps()[0]).asInsertingTag()
|
||||
}
|
||||
}
|
||||
@@ -81,7 +64,7 @@ fun register() {
|
||||
expansion.register()
|
||||
|
||||
val player: Player
|
||||
val playerResolver = MiniPlaceholders.getAudiencePlaceholders(player)
|
||||
player.sendMessage(miniMessage().deserialize("Player Name: <my-expansion_name>", playerResolver))
|
||||
val playerResolver = MiniPlaceholders.audiencePlaceholders()
|
||||
player.sendMessage(miniMessage().deserialize("Player Name: <my-expansion_name>", player, playerResolver))
|
||||
}
|
||||
```
|
||||
@@ -40,7 +40,8 @@ tasks {
|
||||
o.encoding = Charsets.UTF_8.name()
|
||||
o.links(
|
||||
"https://jd.advntr.dev/api/${libs.versions.adventure.get()}/",
|
||||
"https://jd.advntr.dev/text-minimessage/${libs.versions.adventure.get()}/"
|
||||
"https://jd.advntr.dev/text-minimessage/${libs.versions.adventure.get()}/",
|
||||
"https://javadoc.io/doc/org.jspecify/jspecify/latest/index.html"
|
||||
)
|
||||
o.tags(
|
||||
"apiNote:a:API Note:",
|
||||
|
||||
@@ -13,8 +13,7 @@ import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -38,7 +37,6 @@ import java.util.Collection;
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@NullMarked
|
||||
public sealed interface Expansion permits ExpansionImpl {
|
||||
/**
|
||||
* Get the expansion name
|
||||
@@ -112,8 +110,6 @@ public sealed interface Expansion permits ExpansionImpl {
|
||||
*/
|
||||
boolean registered();
|
||||
|
||||
// TODO: Docs and Tests
|
||||
|
||||
/**
|
||||
* Get the registered audience placeholders
|
||||
*
|
||||
@@ -217,8 +213,11 @@ public sealed interface Expansion permits ExpansionImpl {
|
||||
/**
|
||||
* Get a shorter ToString with the details of this expansion.
|
||||
* @return a shorter ToString
|
||||
* @deprecated Starting with MiniPlaceholders 3.1, the way loaded expansions
|
||||
* are displayed in the console has changed, so this method is no longer used
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@Deprecated(forRemoval = true, since = "3.1.0")
|
||||
default String shortToString() {
|
||||
final StringBuilder builder = new StringBuilder(name()).append('[');
|
||||
if (author() != null) {
|
||||
@@ -379,7 +378,7 @@ public sealed interface Expansion permits ExpansionImpl {
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@Contract("_ -> this")
|
||||
@NotNull Builder author(final @Nullable String author);
|
||||
Builder author(final @Nullable String author);
|
||||
|
||||
/**
|
||||
* Sets the version of this expansion
|
||||
@@ -389,6 +388,6 @@ public sealed interface Expansion permits ExpansionImpl {
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@Contract("_ -> this")
|
||||
@NotNull Builder version(final @Nullable String version);
|
||||
Builder version(final @Nullable String version);
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,8 @@ import io.github.miniplaceholders.api.types.PlaceholderType;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.intellij.lang.annotations.Subst;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.annotations.NullUnmarked;
|
||||
|
||||
import java.util.*;
|
||||
@@ -18,7 +17,6 @@ import java.util.*;
|
||||
import static io.github.miniplaceholders.api.utils.Conditions.nonNullOrEmptyString;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@NullMarked
|
||||
final class ExpansionImpl implements Expansion {
|
||||
private static final AudiencePlaceholder<?>[] EMPTY_SINGLE_AUDIENCE = new AudiencePlaceholder[0];
|
||||
private static final RelationalPlaceholder<?>[] EMPTY_RELATIONAL_AUDIENCE = new RelationalPlaceholder[0];
|
||||
@@ -34,23 +32,23 @@ final class ExpansionImpl implements Expansion {
|
||||
private final String version;
|
||||
|
||||
ExpansionImpl(
|
||||
final String expansionName,
|
||||
@Nullable final Collection<AudiencePlaceholder<?>> audiencePlaceholders,
|
||||
@Nullable final Collection<RelationalPlaceholder<?>> relationalPlaceholders,
|
||||
@Nullable final Collection<GlobalPlaceholder> globalPlaceholders,
|
||||
@Nullable final String author,
|
||||
@Nullable final String version
|
||||
final String expansionName,
|
||||
@Nullable final Collection<AudiencePlaceholder<?>> audiencePlaceholders,
|
||||
@Nullable final Collection<RelationalPlaceholder<?>> relationalPlaceholders,
|
||||
@Nullable final Collection<GlobalPlaceholder> globalPlaceholders,
|
||||
@Nullable final String author,
|
||||
@Nullable final String version
|
||||
) {
|
||||
this.name = expansionName;
|
||||
this.audiencePlaceholders = audiencePlaceholders != null
|
||||
? new PlaceholderTagResolver(audiencePlaceholders.toArray(EMPTY_SINGLE_AUDIENCE))
|
||||
: PlaceholderTagResolver.EMPTY;
|
||||
? new PlaceholderTagResolver(audiencePlaceholders.toArray(EMPTY_SINGLE_AUDIENCE))
|
||||
: PlaceholderTagResolver.EMPTY;
|
||||
this.relationalPlaceholders = relationalPlaceholders != null
|
||||
? new PlaceholderTagResolver(relationalPlaceholders.toArray(EMPTY_RELATIONAL_AUDIENCE))
|
||||
: PlaceholderTagResolver.EMPTY;
|
||||
? new PlaceholderTagResolver(relationalPlaceholders.toArray(EMPTY_RELATIONAL_AUDIENCE))
|
||||
: PlaceholderTagResolver.EMPTY;
|
||||
this.globalPlaceholders = globalPlaceholders == null
|
||||
? PlaceholderTagResolver.EMPTY
|
||||
: new PlaceholderTagResolver(globalPlaceholders.toArray(EMPTY_GLOBAL_PLACEHOLDER));
|
||||
? PlaceholderTagResolver.EMPTY
|
||||
: new PlaceholderTagResolver(globalPlaceholders.toArray(EMPTY_GLOBAL_PLACEHOLDER));
|
||||
this.author = author;
|
||||
this.version = version;
|
||||
}
|
||||
@@ -174,16 +172,16 @@ final class ExpansionImpl implements Expansion {
|
||||
private String author;
|
||||
private String version;
|
||||
|
||||
Builder(@NotNull final String name) {
|
||||
Builder(final @NonNull String name) {
|
||||
this.expansionName = nonNullOrEmptyString(name, "Expansion name");
|
||||
this.expansionPrefix = name.toLowerCase(Locale.ROOT).concat("_");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends Audience> @NotNull Builder audiencePlaceholder(
|
||||
final @Nullable Class<A> targetClass,
|
||||
@Subst("name") final @NotNull String key,
|
||||
final @NotNull AudienceTagResolver<@NotNull A> audiencePlaceholder
|
||||
public <A extends Audience> @NonNull Builder audiencePlaceholder(
|
||||
final @Nullable Class<A> targetClass,
|
||||
final @Subst("name") @NonNull String key,
|
||||
final @NonNull AudienceTagResolver<@NonNull A> audiencePlaceholder
|
||||
) {
|
||||
nonNullOrEmptyString(key, "Placeholder key");
|
||||
requireNonNull(audiencePlaceholder, "the audience placeholder cannot be null");
|
||||
@@ -195,10 +193,10 @@ final class ExpansionImpl implements Expansion {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends Audience> @NotNull Builder relationalPlaceholder(
|
||||
@Nullable Class<A> targetClass,
|
||||
@Subst("relation") @NotNull String key,
|
||||
@NotNull RelationalTagResolver<@NotNull A> relationalPlaceholder
|
||||
public <A extends Audience> @NonNull Builder relationalPlaceholder(
|
||||
final Class<A> targetClass,
|
||||
final @Subst("relation") @NonNull String key,
|
||||
final @NonNull RelationalTagResolver<@NonNull A> relationalPlaceholder
|
||||
) {
|
||||
nonNullOrEmptyString(key, "Placeholder key");
|
||||
requireNonNull(relationalPlaceholder, "the relational placeholder cannot be null");
|
||||
@@ -211,9 +209,9 @@ final class ExpansionImpl implements Expansion {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Builder globalPlaceholder(
|
||||
@Subst("time") @NotNull final String key,
|
||||
@NotNull final GlobalTagResolver function
|
||||
public @NonNull Builder globalPlaceholder(
|
||||
final @Subst("time") @NonNull String key,
|
||||
final @NonNull GlobalTagResolver function
|
||||
) {
|
||||
nonNullOrEmptyString(key, "Placeholder key");
|
||||
requireNonNull(function, "the global placeholder cannot be null");
|
||||
@@ -226,26 +224,26 @@ final class ExpansionImpl implements Expansion {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expansion.@NotNull Builder author(@Nullable final String author) {
|
||||
public @NonNull Builder author(final @Nullable String author) {
|
||||
this.author = author;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expansion.@NotNull Builder version(@Nullable final String version) {
|
||||
public @NonNull Builder version(final @Nullable String version) {
|
||||
this.version = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Expansion build() {
|
||||
public @NonNull Expansion build() {
|
||||
return new ExpansionImpl(
|
||||
this.expansionName,
|
||||
this.audiencePlaceholders,
|
||||
this.relationalPlaceholders,
|
||||
this.globalPlaceholders,
|
||||
this.author,
|
||||
this.version
|
||||
this.expansionName,
|
||||
this.audiencePlaceholders,
|
||||
this.relationalPlaceholders,
|
||||
this.globalPlaceholders,
|
||||
this.author,
|
||||
this.version
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -266,12 +264,12 @@ final class ExpansionImpl implements Expansion {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ExpansionImpl{" +
|
||||
"name='" + name + '\'' +
|
||||
", audiencePlaceholders=" + audiencePlaceholders +
|
||||
", relationalPlaceholders=" + relationalPlaceholders +
|
||||
", globalPlaceholders=" + globalPlaceholders +
|
||||
", author='" + author + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
'}';
|
||||
"name='" + name + '\'' +
|
||||
", audiencePlaceholders=" + audiencePlaceholders +
|
||||
", relationalPlaceholders=" + relationalPlaceholders +
|
||||
", globalPlaceholders=" + globalPlaceholders +
|
||||
", author='" + author + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,8 @@ import io.github.miniplaceholders.api.types.RelationalAudience;
|
||||
import io.github.miniplaceholders.connect.InternalPlatform;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -39,7 +39,7 @@ public final class MiniPlaceholders {
|
||||
* @return the platform
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static @NotNull Platform platform() {
|
||||
public static Platform platform() {
|
||||
return switch (InternalPlatform.platform()) {
|
||||
case PAPER -> Platform.PAPER;
|
||||
case VELOCITY -> Platform.VELOCITY;
|
||||
@@ -58,7 +58,7 @@ public final class MiniPlaceholders {
|
||||
* @see TagResolver
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static @NotNull TagResolver globalPlaceholders() {
|
||||
public static TagResolver globalPlaceholders() {
|
||||
final TagResolver.Builder builder = TagResolver.builder();
|
||||
for (final Expansion expansion : expansions) {
|
||||
final TagResolver resolver = expansion.globalPlaceholders();
|
||||
@@ -79,7 +79,7 @@ public final class MiniPlaceholders {
|
||||
* @return {@link TagResolver} with placeholders based on an audience
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static @NotNull TagResolver audiencePlaceholders() {
|
||||
public static TagResolver audiencePlaceholders() {
|
||||
final TagResolver.Builder resolvers = TagResolver.builder();
|
||||
for (final Expansion expansion : expansions) {
|
||||
final TagResolver resolver = expansion.audiencePlaceholders();
|
||||
@@ -103,7 +103,7 @@ public final class MiniPlaceholders {
|
||||
* @since 3.0.0
|
||||
* @see RelationalAudience
|
||||
*/
|
||||
public static @NotNull TagResolver relationalPlaceholders() {
|
||||
public static TagResolver relationalPlaceholders() {
|
||||
final TagResolver.Builder builder = TagResolver.builder();
|
||||
for (final Expansion expansion : expansions) {
|
||||
applyIfNotEmpty(expansion.relationalPlaceholders(), builder);
|
||||
@@ -132,7 +132,7 @@ public final class MiniPlaceholders {
|
||||
* @return {@link TagResolver} with placeholders based on an audience and the global placeholders
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public static @NotNull TagResolver audienceGlobalPlaceholders() {
|
||||
public static TagResolver audienceGlobalPlaceholders() {
|
||||
final TagResolver.Builder builder = TagResolver.builder();
|
||||
|
||||
for (final Expansion expansion : expansions) {
|
||||
@@ -164,7 +164,7 @@ public final class MiniPlaceholders {
|
||||
* @apiNote In the case of audience placeholders, the audience to be used will be the {@link RelationalAudience#audience()}
|
||||
* @see RelationalAudience
|
||||
*/
|
||||
public static @NotNull TagResolver relationalGlobalPlaceholders() {
|
||||
public static TagResolver relationalGlobalPlaceholders() {
|
||||
final TagResolver.Builder builder = TagResolver.builder();
|
||||
for (final Expansion expansion : expansions) {
|
||||
applyIfNotEmpty(expansion.audiencePlaceholders(), builder);
|
||||
@@ -221,7 +221,7 @@ public final class MiniPlaceholders {
|
||||
* @see Expansion#builder(String)
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static @Nullable Expansion expansionByName(final @NotNull String name) {
|
||||
public static @Nullable Expansion expansionByName(final String name) {
|
||||
for (final Expansion expansion : expansions) {
|
||||
if (Objects.equals(expansion.name(), name)) {
|
||||
return expansion;
|
||||
@@ -236,6 +236,7 @@ public final class MiniPlaceholders {
|
||||
* @return all available registered expansions
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@Unmodifiable
|
||||
public static Collection<Expansion> expansionsAvailable() {
|
||||
return Collections.unmodifiableSet(expansions);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.TagPattern;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -24,7 +23,6 @@ import static java.util.Objects.requireNonNull;
|
||||
* @param resolver the object responsible for obtaining audience information
|
||||
* @param <A> the parametrized type
|
||||
*/
|
||||
@NullMarked
|
||||
public record AudiencePlaceholder<A extends Audience>(
|
||||
@Nullable Class<A> targetClass,
|
||||
@TagPattern String key,
|
||||
|
||||
@@ -5,8 +5,7 @@ import net.kyori.adventure.text.minimessage.Context;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.TagPattern;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -20,17 +19,17 @@ import java.util.Objects;
|
||||
*/
|
||||
public record GlobalPlaceholder(@TagPattern String key, String name, GlobalTagResolver resolver) implements Placeholder {
|
||||
@Override
|
||||
public @Nullable Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull Context ctx) {
|
||||
public @Nullable Tag resolve(final String name, final ArgumentQueue arguments, final Context ctx) {
|
||||
return this.has(name) ? resolver.tag(arguments, ctx) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(@NotNull String name) {
|
||||
public boolean has(final String name) {
|
||||
return key.equalsIgnoreCase(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package io.github.miniplaceholders.api.placeholder;
|
||||
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* Base class of all Placeholders
|
||||
*/
|
||||
@NullMarked
|
||||
public sealed interface Placeholder extends TagResolver permits AudiencePlaceholder, GlobalPlaceholder, RelationalPlaceholder {
|
||||
/**
|
||||
* The key of this placeholder.<br>
|
||||
|
||||
+2
-3
@@ -5,7 +5,6 @@ import net.kyori.adventure.text.minimessage.ParsingException;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
@@ -16,7 +15,7 @@ public record PlaceholderTagResolver(Placeholder... placeholders) implements Tag
|
||||
public static final PlaceholderTagResolver EMPTY = new PlaceholderTagResolver();
|
||||
|
||||
@Override
|
||||
public @Nullable Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull Context ctx) throws ParsingException {
|
||||
public @Nullable Tag resolve(final String name, final ArgumentQueue arguments, final Context ctx) throws ParsingException {
|
||||
@Nullable Tag tag;
|
||||
for (final Placeholder placeholder : placeholders) {
|
||||
tag = placeholder.resolve(name, arguments, ctx);
|
||||
@@ -28,7 +27,7 @@ public record PlaceholderTagResolver(Placeholder... placeholders) implements Tag
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(final @NotNull String name) {
|
||||
public boolean has(final String name) {
|
||||
for (final Placeholder placeholder : placeholders) {
|
||||
if (placeholder.has(name)) {
|
||||
return true;
|
||||
|
||||
+31
-34
@@ -9,9 +9,7 @@ import net.kyori.adventure.text.minimessage.Context;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.TagPattern;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -24,47 +22,46 @@ import static java.util.Objects.requireNonNull;
|
||||
* using a type-safe filter and a relational resolver.
|
||||
*
|
||||
* @param targetClass the target class, can be null
|
||||
* @param key the key of the entire placeholder
|
||||
* @param name the name of this placeholder
|
||||
* @param resolver the relational resolver,
|
||||
* in charge of obtaining data based on a relationship of 2 audiences
|
||||
* @param <A> the audience type, if not specified, will be a generic {@linkplain Audience}
|
||||
* @see RelationalTagResolver
|
||||
* @param key the key of the entire placeholder
|
||||
* @param name the name of this placeholder
|
||||
* @param resolver the relational resolver,
|
||||
* in charge of obtaining data based on a relationship of 2 audiences
|
||||
* @param <A> the audience type, if not specified, will be a generic {@linkplain Audience}
|
||||
* @apiNote The {@link #key()} method returns the full name of the placeholder,
|
||||
* for example, if the placeholder is {@code <server_name>},
|
||||
* the {@linkplain #key()} method will return {@code server_name}.
|
||||
* @see RelationalTagResolver
|
||||
*/
|
||||
@NullMarked
|
||||
public record RelationalPlaceholder<A extends Audience>(
|
||||
@Nullable Class<A> targetClass,
|
||||
@TagPattern String key,
|
||||
String name,
|
||||
RelationalTagResolver<A> resolver
|
||||
@Nullable Class<A> targetClass,
|
||||
@TagPattern String key,
|
||||
String name,
|
||||
RelationalTagResolver<A> resolver
|
||||
) implements Placeholder {
|
||||
|
||||
/**
|
||||
* Static method capable of creating an instance of a relational placeholder.
|
||||
*
|
||||
* @param targetClass the target class, can be null
|
||||
* @param key the key of the entire placeholder
|
||||
* @param name the name of this placeholder
|
||||
* @param resolver the relational resolver,
|
||||
* in charge of obtaining data based on a relationship of 2 audiences
|
||||
* @param key the key of the entire placeholder
|
||||
* @param name the name of this placeholder
|
||||
* @param resolver the relational resolver,
|
||||
* in charge of obtaining data based on a relationship of 2 audiences
|
||||
* @param <A> the audience type, if not specified, will be a generic {@linkplain Audience}
|
||||
* @return a new RelationalPlaceholder
|
||||
* @param <A> the audience type, if not specified, will be a generic {@linkplain Audience}
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static <A extends Audience> RelationalPlaceholder<A> relational(
|
||||
@Nullable Class<A> targetClass,
|
||||
@TagPattern String key,
|
||||
String name,
|
||||
RelationalTagResolver<A> resolver
|
||||
final @Nullable Class<A> targetClass,
|
||||
final @TagPattern String key,
|
||||
final String name,
|
||||
final RelationalTagResolver<A> resolver
|
||||
) {
|
||||
return new RelationalPlaceholder<>(targetClass, requireNonNull(key), name, requireNonNull(resolver));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Tag resolve(String name, ArgumentQueue arguments, Context ctx) {
|
||||
public @Nullable Tag resolve(final String name, final ArgumentQueue arguments, final Context ctx) {
|
||||
final Pointered targetRaw = ctx.target();
|
||||
if (targetRaw == null) {
|
||||
return null;
|
||||
@@ -74,7 +71,7 @@ public record RelationalPlaceholder<A extends Audience>(
|
||||
}
|
||||
if (targetClass == null) {
|
||||
//noinspection unchecked
|
||||
return this.resolveA(name, (A)a, (A)b, arguments, ctx);
|
||||
return this.resolveA(name, (A) a, (A) b, arguments, ctx);
|
||||
}
|
||||
final @Nullable A audience = forwardingFilter(a);
|
||||
if (audience == null) {
|
||||
@@ -88,15 +85,15 @@ public record RelationalPlaceholder<A extends Audience>(
|
||||
}
|
||||
|
||||
private @Nullable Tag resolveA(
|
||||
String name,
|
||||
A audience,
|
||||
A relationalAudience,
|
||||
ArgumentQueue arguments,
|
||||
Context ctx
|
||||
final String name,
|
||||
final A audience,
|
||||
final A relationalAudience,
|
||||
final ArgumentQueue arguments,
|
||||
final Context ctx
|
||||
) {
|
||||
return this.has(name)
|
||||
? resolver.tag(audience, relationalAudience, arguments, ctx)
|
||||
: null;
|
||||
? resolver.tag(audience, relationalAudience, arguments, ctx)
|
||||
: null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("OverrideOnly")
|
||||
@@ -112,7 +109,7 @@ public record RelationalPlaceholder<A extends Audience>(
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(@NotNull String name) {
|
||||
public boolean has(final String name) {
|
||||
return key.equalsIgnoreCase(name);
|
||||
}
|
||||
|
||||
@@ -131,7 +128,7 @@ public record RelationalPlaceholder<A extends Audience>(
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RelationalPlaceholder{" +
|
||||
"key='" + key + '\'' +
|
||||
'}';
|
||||
"key='" + key + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,138 +1,223 @@
|
||||
package io.github.miniplaceholders.api.provider;
|
||||
|
||||
import io.github.miniplaceholders.api.types.Platform;
|
||||
import net.kyori.examination.Examinable;
|
||||
import org.intellij.lang.annotations.Pattern;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* This class specifies the conditions that must be met
|
||||
* in order to load an {@link io.github.miniplaceholders.api.Expansion} from an {@link ExpansionProvider}.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public sealed interface LoadRequirement {
|
||||
|
||||
/**
|
||||
* It means that there is no requirement to load an expansion.
|
||||
*
|
||||
* @return a LoadRequirement that does not perform any validation
|
||||
* @since 3.0.0
|
||||
*/
|
||||
static LoadRequirement none() {
|
||||
return NoneLoadRequirement.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requirement for a complement, whether a plugin or mod, to be present in order for an expansion to be loaded.<br>
|
||||
* The ability to provide multiple strings is provided because names may vary on some platforms.
|
||||
* For example, Velocity requires plugin IDs to be lowercase, such as {@code miniplaceholders},
|
||||
* while Paper can contain uppercase letters, such as {@code MiniPlaceholders}.
|
||||
*
|
||||
* @param name the principal name of this complement
|
||||
* @param aliases the platform aliases of a complement
|
||||
* @return a load requirement that checks for an available complement
|
||||
* @since 3.0.0
|
||||
*/
|
||||
static LoadRequirement requiredComplement(final String name, final String... aliases) {
|
||||
requireNonNull(name);
|
||||
requireNonNull(aliases);
|
||||
return new AvailableComplementRequirement(name, aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiple requirement, in case an expansion needs to depend on a platform
|
||||
* as well as one or more add-ons that are installed.
|
||||
*
|
||||
* @param requirements the load requirements
|
||||
* @return a load requirement of many load requirements
|
||||
* @since 3.0.0
|
||||
*/
|
||||
static LoadRequirement allOf(LoadRequirement... requirements) {
|
||||
requireNonNull(requirements);
|
||||
assert requirements.length != 0;
|
||||
return new MultiLoadRequirement(requirements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requirement that the current execution be on a specific platform.
|
||||
*
|
||||
* @param platforms the supported platforms
|
||||
* @return a load requirement that checks for a supported platform
|
||||
* @since 3.0.0
|
||||
*/
|
||||
static LoadRequirement platform(final Platform... platforms) {
|
||||
requireNonNull(platforms);
|
||||
assert platforms.length != 0;
|
||||
|
||||
return new PlatformRequirement(platforms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requirement that a specific class be present.
|
||||
*
|
||||
* @param clazz the specified class.
|
||||
* @return a load requirement that checks for a present class
|
||||
* @since 3.1.0
|
||||
*/
|
||||
static LoadRequirement requiredClass(
|
||||
@Pattern("^([a-z_][a-z0-9_]*)(\\.[a-z_][a-z0-9_]*)*(\\.[A-Z][A-Za-z0-9_]*)$") final String clazz
|
||||
) {
|
||||
requireNonNull(clazz);
|
||||
return new ClassRequirement(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* This requirement checks whether any of the conditions presented are satisfied.
|
||||
*
|
||||
* @param requirements the requerimients
|
||||
* @return a requirement that checks whether a condition is valid
|
||||
* @since 3.1.0
|
||||
*/
|
||||
static LoadRequirement anyOf(LoadRequirement... requirements) {
|
||||
requireNonNull(requirements);
|
||||
assert requirements.length != 0;
|
||||
return new AnyOfRequirement(requirements);
|
||||
}
|
||||
|
||||
/**
|
||||
* NoneLoadRequirement
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
enum NoneLoadRequirement implements LoadRequirement {
|
||||
/**
|
||||
* It means that there is no requirement to load an expansion.
|
||||
* @return a LoadRequirement that does not perform any validation
|
||||
* NoneLoadRequirement instance
|
||||
*/
|
||||
static LoadRequirement none() {
|
||||
return NoneLoadRequirement.INSTANCE;
|
||||
}
|
||||
INSTANCE
|
||||
}
|
||||
|
||||
/**
|
||||
* AvailableComplementRequirement
|
||||
*
|
||||
* @param name the main complement name
|
||||
* @param platformAliases the complement aliases
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@NullMarked
|
||||
record AvailableComplementRequirement(String name, String... platformAliases) implements LoadRequirement {
|
||||
|
||||
/**
|
||||
* Requirement for a complement, whether a plugin or mod, to be present in order for an expansion to be loaded.<br>
|
||||
* The ability to provide multiple strings is provided because names may vary on some platforms.
|
||||
* For example, Velocity requires plugin IDs to be lowercase, such as {@code miniplaceholders},
|
||||
* while Paper can contain uppercase letters, such as {@code MiniPlaceholders}.
|
||||
* @param name the principal name of this complement
|
||||
* @param aliases the platform aliases of a complement
|
||||
* @return a load requirement that checks for an available complement
|
||||
*/
|
||||
static LoadRequirement requiredComplement(final String name, String... aliases) {
|
||||
requireNonNull(name);
|
||||
return new AvailableComplementRequirement(name, aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiple requirement, in case an expansion needs to depend on a platform
|
||||
* as well as one or more add-ons that are installed.
|
||||
* Checks if a complement is loaded
|
||||
*
|
||||
* @param requirements the load requirements
|
||||
* @return a load requirement of many load requirements
|
||||
* @param platformComplementTester the checker predicate
|
||||
* @return is this expansion should load
|
||||
* @since 3.0.0
|
||||
*/
|
||||
static LoadRequirement allOf(LoadRequirement... requirements) {
|
||||
requireNonNull(requirements);
|
||||
assert requirements.length != 0;
|
||||
return new MultiLoadRequirement(requirements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requirement that the current execution be on a specific platform.
|
||||
* @param platforms the supported platforms
|
||||
* @return a load requirement that checks for a supported platform
|
||||
*/
|
||||
static LoadRequirement platform(Platform... platforms) {
|
||||
requireNonNull(platforms);
|
||||
assert platforms.length != 0;
|
||||
|
||||
return new PlatformRequirement(platforms);
|
||||
}
|
||||
|
||||
/**
|
||||
* NoneLoadRequirement
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
enum NoneLoadRequirement implements LoadRequirement {
|
||||
/**
|
||||
* NoneLoadRequirement instance
|
||||
*/
|
||||
INSTANCE
|
||||
}
|
||||
|
||||
/**
|
||||
* AvailableComplementRequirement
|
||||
* @param name the main complement name
|
||||
* @param platformAliases the complement aliases
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@NullMarked
|
||||
record AvailableComplementRequirement(String name, String... platformAliases) implements LoadRequirement {
|
||||
|
||||
/**
|
||||
* Checks if a complement is loaded
|
||||
* @param platformComplementTester the checker predicate
|
||||
* @return is this expansion should load
|
||||
*/
|
||||
public boolean shouldLoad(Predicate<String> platformComplementTester) {
|
||||
if (platformComplementTester.test(name)) {
|
||||
return true;
|
||||
}
|
||||
for (String alias : platformAliases) {
|
||||
if (platformComplementTester.test(alias)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AvailableComplementRequirement{" +
|
||||
"complement='" + name + '\'' +
|
||||
'}';
|
||||
public boolean shouldLoad(final Predicate<String> platformComplementTester) {
|
||||
if (platformComplementTester.test(name)) {
|
||||
return true;
|
||||
}
|
||||
for (String alias : platformAliases) {
|
||||
if (platformComplementTester.test(alias)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* MultiLoadRequirement
|
||||
* @param requirements the load requirements
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@NullMarked
|
||||
record MultiLoadRequirement(LoadRequirement... requirements) implements LoadRequirement {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AvailableComplementRequirement{" +
|
||||
"complement='" + name + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PlatformLoadRequirement
|
||||
* @param platforms the platforms supported
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@NullMarked
|
||||
record PlatformRequirement(Platform... platforms) implements LoadRequirement, Examinable {
|
||||
@Override
|
||||
public String toString() {
|
||||
final String platforms = Stream.of(this.platforms)
|
||||
.map(Platform::name)
|
||||
.collect(Collectors.joining(", "));
|
||||
return "PlatformRequirement{" +
|
||||
"platforms=" + platforms +
|
||||
'}';
|
||||
}
|
||||
/**
|
||||
* MultiLoadRequirement
|
||||
*
|
||||
* @param requirements the load requirements
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@NullMarked
|
||||
record MultiLoadRequirement(LoadRequirement... requirements) implements LoadRequirement {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MultiLoadRequirement{" +
|
||||
"requirements=" + Arrays.toString(requirements) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PlatformLoadRequirement
|
||||
*
|
||||
* @param platforms the platforms supported
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@NullMarked
|
||||
record PlatformRequirement(Platform... platforms) implements LoadRequirement {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PlatformRequirement{" +
|
||||
"platforms=" + Arrays.toString(platforms()) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ClassRequirement
|
||||
*
|
||||
* @param clazz a specified class
|
||||
* @since 3.1.0
|
||||
*/
|
||||
@NullMarked
|
||||
@ApiStatus.Internal
|
||||
record ClassRequirement(String clazz) implements LoadRequirement {
|
||||
public boolean shouldLoad() {
|
||||
try {
|
||||
Class.forName(clazz);
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AnyOfLoadRequirement
|
||||
*
|
||||
* @param requirements the requirements
|
||||
* @since 3.1.0
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@NullMarked
|
||||
record AnyOfRequirement(LoadRequirement... requirements) implements LoadRequirement {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AnyOfRequirement{" +
|
||||
"requirements=" + Arrays.toString(requirements) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Package responsible for providing tools to load expansions provided through installable files
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
package io.github.miniplaceholders.api.provider;
|
||||
@@ -1,12 +1,10 @@
|
||||
package io.github.miniplaceholders.api.resolver;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.minimessage.Context;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Audience Placeholder based on an Audience
|
||||
@@ -14,7 +12,6 @@ import org.jspecify.annotations.NullMarked;
|
||||
* @param <A> the audience type
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@NullMarked
|
||||
public interface AudienceTagResolver<A extends Audience> {
|
||||
/**
|
||||
* A Tag based on an Audience
|
||||
|
||||
@@ -3,7 +3,6 @@ package io.github.miniplaceholders.api.resolver;
|
||||
import net.kyori.adventure.text.minimessage.Context;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
@@ -20,5 +19,5 @@ public interface GlobalTagResolver {
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@Nullable
|
||||
Tag tag(@NonNull ArgumentQueue queue, @NonNull Context context);
|
||||
Tag tag(ArgumentQueue queue, Context context);
|
||||
}
|
||||
+1
-3
@@ -4,8 +4,7 @@ import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.minimessage.Context;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Relational Placeholder based on two Audiences.
|
||||
@@ -15,7 +14,6 @@ import org.jspecify.annotations.NullMarked;
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@NullMarked
|
||||
public interface RelationalTagResolver<A extends Audience> {
|
||||
/**
|
||||
* A Tag based on two audiences
|
||||
|
||||
@@ -2,7 +2,8 @@ package io.github.miniplaceholders.api.types;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.audience.ForwardingAudience;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* A relationship between 2 Audiences.
|
||||
@@ -12,8 +13,12 @@ import org.jspecify.annotations.NullMarked;
|
||||
* @param <A> the audiences type
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@NullMarked
|
||||
public record RelationalAudience<A extends Audience>(A audience, A relational) implements ForwardingAudience.Single {
|
||||
public RelationalAudience {
|
||||
requireNonNull(audience);
|
||||
requireNonNull(relational);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new relation between two audiences.
|
||||
*
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
/**Plugin enums */
|
||||
/**
|
||||
* Plugin types
|
||||
*/
|
||||
package io.github.miniplaceholders.api.types;
|
||||
@@ -4,7 +4,9 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
/**Common components used in expansions */
|
||||
/**
|
||||
* Common components used in expansions
|
||||
*/
|
||||
public final class Components {
|
||||
private Components(){}
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.github.miniplaceholders.api.utils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -23,7 +22,7 @@ public final class Conditions {
|
||||
* @throws IllegalStateException if the provided string is empty
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static String nonNullOrEmptyString(@Nullable String string, @NotNull Supplier<@NotNull String> name) {
|
||||
public static String nonNullOrEmptyString(final @Nullable String string, final Supplier<String> name) {
|
||||
if (string == null)
|
||||
throw new NullPointerException(name.get() + " cannot be null");
|
||||
if (string.isBlank())
|
||||
@@ -40,7 +39,7 @@ public final class Conditions {
|
||||
* @throws IllegalStateException if the provided string is empty
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public static String nonNullOrEmptyString(@Nullable String string, @NotNull String name) {
|
||||
public static String nonNullOrEmptyString(final @Nullable String string, final String name) {
|
||||
if (string == null)
|
||||
throw new NullPointerException(name + " cannot be null");
|
||||
if (string.isBlank())
|
||||
@@ -57,7 +56,7 @@ public final class Conditions {
|
||||
* @throws IllegalStateException if the provided string is empty
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static String nonEmptyString(@NotNull String string, @NotNull Supplier<@NotNull String> reason) {
|
||||
public static String nonEmptyString(final String string, final Supplier<String> reason) {
|
||||
if (string.isBlank()) throw new IllegalStateException(reason.get());
|
||||
return string;
|
||||
}
|
||||
@@ -71,7 +70,7 @@ public final class Conditions {
|
||||
* @throws IllegalStateException if the provided string is empty
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public static String nonEmptyString(@NotNull String string, @NotNull String reason) {
|
||||
public static String nonEmptyString(final String string, final String reason) {
|
||||
if (string.isBlank()) throw new IllegalStateException(reason);
|
||||
return string;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.Context;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -17,7 +16,6 @@ import static net.kyori.adventure.text.minimessage.MiniMessage.miniMessage;
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@NullMarked
|
||||
public final class LegacyStrings {
|
||||
private LegacyStrings() {
|
||||
}
|
||||
@@ -26,7 +24,10 @@ public final class LegacyStrings {
|
||||
* Legacy serializer with hex support
|
||||
* <p>Use this as the last available alternative,
|
||||
* it is recommended to use MiniMessage instead of this serializer</p>
|
||||
*
|
||||
* @deprecated Legacy format “support” will be removed in future versions
|
||||
*/
|
||||
@Deprecated(since = "3.1.0")
|
||||
public static final LegacyComponentSerializer LEGACY_HEX_SERIALIZER = LegacyComponentSerializer.builder()
|
||||
.character('&')
|
||||
.hexColors()
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package io.github.miniplaceholders.api.utils;
|
||||
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* Class of utilities to manage TagResolvers.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@NullMarked
|
||||
public final class Resolvers {
|
||||
private Resolvers() {}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import io.github.miniplaceholders.api.resolver.RelationalTagResolver;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Tags basic instances.
|
||||
@@ -29,7 +29,7 @@ public final class Tags {
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static final Tag NULL_TAG = null;
|
||||
public static final @Nullable Tag NULL_TAG = null;
|
||||
|
||||
/**
|
||||
* An Audience placeholder that returns a null Tag
|
||||
@@ -38,7 +38,7 @@ public final class Tags {
|
||||
* @return an empty audience resolver
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static <A extends Audience> AudienceTagResolver<@NonNull A> emptyAudienceResolver() {
|
||||
public static <A extends Audience> AudienceTagResolver<A> emptyAudienceResolver() {
|
||||
return (audience, queue, ctx) -> NULL_TAG;
|
||||
}
|
||||
|
||||
@@ -49,17 +49,10 @@ public final class Tags {
|
||||
* @return an empty relational resolver
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static <A extends Audience> RelationalTagResolver<@NonNull A> emptyRelationalResolver() {
|
||||
public static <A extends Audience> RelationalTagResolver<A> emptyRelationalResolver() {
|
||||
return (audience, relational, queue, ctx) -> NULL_TAG;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Global placeholder that returns a null tag
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
private static final GlobalTagResolver EMPTY_GLOBAL_PLACEHOLDER = (queue, ctx) -> NULL_TAG;
|
||||
|
||||
/**
|
||||
* A Global placeholder that returns a null tag
|
||||
*
|
||||
@@ -67,7 +60,7 @@ public final class Tags {
|
||||
* @return an empty global placeholder
|
||||
*/
|
||||
public static GlobalTagResolver emptyGlobalPlaceholder() {
|
||||
return EMPTY_GLOBAL_PLACEHOLDER;
|
||||
return (queue, ctx) -> NULL_TAG;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* MiniPlaceholders API Module
|
||||
*/
|
||||
@NullMarked
|
||||
open module io.github.miniplaceholders.api {
|
||||
requires io.github.miniplaceholders.connect;
|
||||
|
||||
|
||||
@@ -10,10 +10,9 @@ import net.kyori.adventure.text.minimessage.tag.ParserDirective;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TagTest implements MiniTest {
|
||||
@@ -35,7 +34,7 @@ public class TagTest implements MiniTest {
|
||||
|
||||
public record FilteringTag(ArgumentQueue queue, Context context) implements Modifying {
|
||||
@Override
|
||||
public Component apply(@NotNull Component current, int depth) {
|
||||
public Component apply(@NonNull Component current, int depth) {
|
||||
if (depth != 0) {
|
||||
return Component.empty();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.github.miniplaceholders.test.instances;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
public record TestAudience(@NotNull String name) implements Audience {}
|
||||
@NullMarked
|
||||
public record TestAudience(String name) implements Audience {}
|
||||
@@ -1,11 +1,12 @@
|
||||
package io.github.miniplaceholders.test.instances;
|
||||
|
||||
import net.kyori.adventure.audience.ForwardingAudience;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public record TestAudienceHolder(TestAudience audience) implements ForwardingAudience.Single {
|
||||
@Override
|
||||
public @NotNull TestAudience audience() {
|
||||
public TestAudience audience() {
|
||||
return audience;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ plugins {
|
||||
dependencies {
|
||||
implementation(libs.plugin.shadow)
|
||||
implementation(libs.plugin.kotlin)
|
||||
implementation(libs.plugin.runtask)
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
||||
@@ -4,4 +4,4 @@ val Project.capitalizeName: String
|
||||
get() = this.name.substring(17)
|
||||
.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
|
||||
|
||||
fun Project.simpleName(): String = this.name.substring(17)
|
||||
fun Project.simpleName(): String = this.name.substring(17)
|
||||
@@ -23,6 +23,6 @@ tasks {
|
||||
java{
|
||||
toolchain{
|
||||
languageVersion.set(JavaLanguageVersion.of(21))
|
||||
//vendor.set(JvmVendorSpec.ADOPTIUM)
|
||||
vendor.set(JvmVendorSpec.AZUL)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import xyz.jpenilla.runtask.task.RunWithPlugins
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
import kotlin.io.path.deleteIfExists
|
||||
|
||||
tasks {
|
||||
withType<RunWithPlugins> {
|
||||
val exampleExpansionProviderProject = project(":miniplaceholders-example-expansion-provider")
|
||||
val exampleExpansionJarTask = exampleExpansionProviderProject.tasks.named<Jar>("jar")
|
||||
dependsOn(exampleExpansionJarTask)
|
||||
doFirst {
|
||||
val folderName = if (project.name.contains("velocity")) "miniplaceholders" else "MiniPlaceholders"
|
||||
val expansionsDirectory = runDirectory.get().file("plugins/$folderName/expansions").asFile.toPath()
|
||||
if (Files.exists(expansionsDirectory)) {
|
||||
Files.newDirectoryStream(expansionsDirectory).use {
|
||||
it.forEach { file ->
|
||||
file.deleteIfExists()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Files.createDirectories(expansionsDirectory)
|
||||
}
|
||||
val exampleExpansionFile = exampleExpansionJarTask.get().archiveFile.get().asFile.toPath()
|
||||
Files.copy(
|
||||
exampleExpansionFile,
|
||||
expansionsDirectory.resolve(exampleExpansionFile.fileName),
|
||||
StandardCopyOption.REPLACE_EXISTING
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,8 @@ tasks {
|
||||
archiveClassifier.set("")
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
relocate("net.william278.desertwell", "io.github.miniplaceholders.libs.desertwell")
|
||||
relocate("org.incendo.cloud", "io.github.miniplaceholders.libs.cloud")
|
||||
// if (project.simpleName() != "sponge") {
|
||||
// relocate("io.leangen.geantyref", "io.github.miniplaceholders.libs.geantyref")
|
||||
// }
|
||||
relocate("org.bstats", "io.github.miniplaceholders.libs.bstats")
|
||||
|
||||
destinationDirectory.set(file("${project.rootDir}/jar"))
|
||||
}
|
||||
build {
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
kotlin("jvm") version "2.2.20-RC" apply false
|
||||
kotlin("jvm") version "2.2.20" apply false
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
||||
@@ -9,13 +9,12 @@ dependencies {
|
||||
implementation(libs.desertwell) {
|
||||
exclude("org.json")
|
||||
}
|
||||
implementation(libs.cloud.core)
|
||||
implementation(libs.unnamedinject)
|
||||
implementation(libs.cloud.extras) {
|
||||
isTransitive = false
|
||||
}
|
||||
compileOnly(libs.adventure.api)
|
||||
compileOnly(libs.adventure.minimessage)
|
||||
compileOnly(libs.jspecify)
|
||||
compileOnly(libs.brigadier)
|
||||
compileOnly(libs.bstats.core)
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
||||
@@ -10,82 +10,126 @@ import io.github.miniplaceholders.common.loader.ExpansionProviderLoader;
|
||||
import io.github.miniplaceholders.common.loader.FailedToLoadExpansion;
|
||||
import io.github.miniplaceholders.common.loader.ProviderLoadResult;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import team.unnamed.inject.Injector;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public interface PlaceholdersPlugin {
|
||||
default void registerPlatformCommand() {
|
||||
default void registerPlatformCommand() {
|
||||
}
|
||||
|
||||
default void loadProvidedExpansions(final Path providersFolderDirectory) throws Exception {
|
||||
final List<Expansion> loadedExpansions = new ArrayList<>();
|
||||
final PlatformData platformData = new PlatformData(this.platformServerInstance(), this);
|
||||
final Injector injector = Injector.create(binder -> binder.bind(PlatformData.class).toInstance(platformData));
|
||||
for (Class<?> providerClass : ExpansionProviderLoader.loadProvidersFromFolder(providersFolderDirectory)) {
|
||||
final ExpansionProvider provider = (ExpansionProvider) injector.getInstance(providerClass);
|
||||
final ProviderLoadResult loadResult = tryLoad(provider, provider.loadRequirement());
|
||||
final ExpansionProvider loadedProvider = loadResult.provider();
|
||||
if (loadedProvider != null) {
|
||||
final Expansion loadedExpansion = loadedProvider.provideExpansion();
|
||||
loadedExpansions.add(loadedExpansion);
|
||||
loadedExpansion.register();
|
||||
continue;
|
||||
}
|
||||
final FailedToLoadExpansion failedToLoad = loadResult.failed();
|
||||
logError(Component.text("The expansion "
|
||||
+ providerClass +
|
||||
" could not be loaded because the requirement " + failedToLoad.requirement() + " could not be resolved",
|
||||
NamedTextColor.RED));
|
||||
}
|
||||
|
||||
default void loadProvidedExpansions(Path providersFolderDirectory) throws Exception {
|
||||
final List<Expansion> loadedExpansions = new ArrayList<>();
|
||||
final PlatformData platformData = new PlatformData(this.platformServerInstance(), this);
|
||||
final Injector injector = Injector.create(binder -> binder.bind(PlatformData.class).toInstance(platformData));
|
||||
for (ExpansionProvider provider : ExpansionProviderLoader.loadProvidersFromFolder(providersFolderDirectory)) {
|
||||
injector.injectMembers(provider);
|
||||
ProviderLoadResult loadResult = tryLoad(provider, provider.loadRequirement());
|
||||
final Expansion loadedExpansion = loadResult.expansion();
|
||||
if (loadedExpansion != null) {
|
||||
loadedExpansions.add(loadedExpansion);
|
||||
loadedExpansion.register();
|
||||
continue;
|
||||
}
|
||||
final FailedToLoadExpansion failedToLoad = loadResult.failed();
|
||||
logError(Component.text("The expansion "
|
||||
+ provider.getClass() +
|
||||
" could not be loaded because the requirement " + failedToLoad.requirement() + " could not be resolved",
|
||||
NamedTextColor.RED));
|
||||
if (loadedExpansions.isEmpty()) {
|
||||
logInfo(Component.text("Not found expansions", NamedTextColor.GRAY));
|
||||
return;
|
||||
}
|
||||
|
||||
final Component expansionsInfo = loadedExpansions.stream()
|
||||
.map(this::expansionInfo)
|
||||
.collect(Component.toComponent(Component.text(", ", NamedTextColor.WHITE)));
|
||||
logInfo(Component.text("Loaded expansions: ", NamedTextColor.GREEN).append(expansionsInfo));
|
||||
}
|
||||
|
||||
private Component expansionInfo(Expansion expansion) {
|
||||
final TextComponent.Builder builder = Component.text();
|
||||
builder.append(Component.text(expansion.name(), NamedTextColor.AQUA));
|
||||
final String author = expansion.author();
|
||||
final String version = expansion.version();
|
||||
if (author == null && version == null) {
|
||||
return builder.build();
|
||||
}
|
||||
builder.append(Component.text('[', NamedTextColor.DARK_GRAY));
|
||||
if (author != null) {
|
||||
builder.append(
|
||||
Component.text("Author", NamedTextColor.GRAY),
|
||||
Component.text(':', NamedTextColor.WHITE),
|
||||
Component.space(),
|
||||
Component.text(author, TextColor.color(0xd4ff54))
|
||||
);
|
||||
}
|
||||
if (version != null) {
|
||||
if (author != null) {
|
||||
builder.append(Component.text(", ", NamedTextColor.WHITE));
|
||||
}
|
||||
builder.append(
|
||||
Component.text("Version", NamedTextColor.GRAY),
|
||||
Component.text(':', NamedTextColor.WHITE),
|
||||
Component.space(),
|
||||
Component.text(version, TextColor.color(0xd4ff54))
|
||||
);
|
||||
}
|
||||
builder.append(Component.text(']', NamedTextColor.DARK_GRAY));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
default ProviderLoadResult tryLoad(final ExpansionProvider provider, final LoadRequirement loadRequirement) {
|
||||
return switch (loadRequirement) {
|
||||
case LoadRequirement.PlatformRequirement platformRequirement -> {
|
||||
for (final Platform supportedPlatform : platformRequirement.platforms()) {
|
||||
if (supportedPlatform == MiniPlaceholders.platform()) {
|
||||
yield ProviderLoadResult.ofLoaded(provider);
|
||||
}
|
||||
}
|
||||
|
||||
if (loadedExpansions.isEmpty()) {
|
||||
logInfo(Component.text("Not found expansions", NamedTextColor.GRAY));
|
||||
return;
|
||||
yield ProviderLoadResult.ofFailed(platformRequirement);
|
||||
}
|
||||
case LoadRequirement.AvailableComplementRequirement complementRequirement ->
|
||||
complementRequirement.shouldLoad(this::platformHasComplementLoaded)
|
||||
? ProviderLoadResult.ofLoaded(provider)
|
||||
: ProviderLoadResult.ofFailed(complementRequirement);
|
||||
case LoadRequirement.MultiLoadRequirement multiLoadRequirement -> {
|
||||
ProviderLoadResult loadResult;
|
||||
for (final LoadRequirement requirement : multiLoadRequirement.requirements()) {
|
||||
if ((loadResult = this.tryLoad(provider, requirement)).failed() != null) {
|
||||
yield loadResult;
|
||||
}
|
||||
}
|
||||
yield ProviderLoadResult.ofLoaded(provider);
|
||||
}
|
||||
case LoadRequirement.ClassRequirement classRequirement -> classRequirement.shouldLoad()
|
||||
? ProviderLoadResult.ofLoaded(provider) : ProviderLoadResult.ofFailed(classRequirement);
|
||||
case LoadRequirement.AnyOfRequirement anyOfRequirement -> {
|
||||
ProviderLoadResult loadResult;
|
||||
for (final LoadRequirement requirement : anyOfRequirement.requirements()) {
|
||||
if ((loadResult = this.tryLoad(provider, requirement)).provider() != null) {
|
||||
yield loadResult;
|
||||
}
|
||||
}
|
||||
yield ProviderLoadResult.ofFailed(anyOfRequirement);
|
||||
}
|
||||
case LoadRequirement.NoneLoadRequirement ignored -> ProviderLoadResult.ofLoaded(provider);
|
||||
};
|
||||
}
|
||||
|
||||
final String expansionsInfo = loadedExpansions.stream()
|
||||
.map(Expansion::shortToString)
|
||||
.collect(Collectors.joining(","));
|
||||
logInfo(Component.text("Loaded expansions: " + expansionsInfo, NamedTextColor.GREEN));
|
||||
}
|
||||
boolean platformHasComplementLoaded(String complementName);
|
||||
|
||||
default ProviderLoadResult tryLoad(final ExpansionProvider provider, final LoadRequirement loadRequirement) {
|
||||
return switch (loadRequirement) {
|
||||
case LoadRequirement.PlatformRequirement platformRequirement -> {
|
||||
for (final Platform supportedPlatform : platformRequirement.platforms()) {
|
||||
if (supportedPlatform == MiniPlaceholders.platform()) {
|
||||
yield ProviderLoadResult.ofLoaded(provider.provideExpansion());
|
||||
}
|
||||
}
|
||||
yield ProviderLoadResult.ofFailed(platformRequirement);
|
||||
}
|
||||
case LoadRequirement.AvailableComplementRequirement complementRequirement ->
|
||||
complementRequirement.shouldLoad(this::platformHasComplementLoaded)
|
||||
? ProviderLoadResult.ofLoaded(provider.provideExpansion())
|
||||
: ProviderLoadResult.ofFailed(complementRequirement);
|
||||
case LoadRequirement.MultiLoadRequirement multiLoadRequirement -> {
|
||||
ProviderLoadResult loadResult;
|
||||
for (final LoadRequirement requirement : multiLoadRequirement.requirements()) {
|
||||
if ((loadResult = this.tryLoad(provider, requirement)).failed() != null) {
|
||||
yield loadResult;
|
||||
}
|
||||
}
|
||||
yield ProviderLoadResult.ofLoaded(provider.provideExpansion());
|
||||
}
|
||||
// NoneRequirement
|
||||
default -> ProviderLoadResult.ofLoaded(provider.provideExpansion());
|
||||
};
|
||||
}
|
||||
void logError(Component component);
|
||||
|
||||
boolean platformHasComplementLoaded(String complementName);
|
||||
void logInfo(Component component);
|
||||
|
||||
void logError(Component component);
|
||||
|
||||
void logInfo(Component component);
|
||||
|
||||
Object platformServerInstance();
|
||||
Object platformServerInstance();
|
||||
}
|
||||
+3
-3
@@ -1,10 +1,10 @@
|
||||
package io.github.miniplaceholders.common.command;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface AudienceConverter {
|
||||
@Nullable Audience convert(@NotNull String string);
|
||||
@Nullable Audience convert(@NonNull String string);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.github.miniplaceholders.common.command;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
@FunctionalInterface
|
||||
public interface AudienceExtractor<S> {
|
||||
Audience extract(S source);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package io.github.miniplaceholders.common.command;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import io.github.miniplaceholders.api.MiniPlaceholders;
|
||||
import io.github.miniplaceholders.api.types.Platform;
|
||||
import io.github.miniplaceholders.common.PluginConstants;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import net.william278.desertwell.about.AboutMenu;
|
||||
import net.william278.desertwell.util.Version;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static net.kyori.adventure.text.Component.newline;
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
import static net.kyori.adventure.text.minimessage.MiniMessage.miniMessage;
|
||||
|
||||
public final class CommandConstants {
|
||||
// Global
|
||||
public static final Component TITLE = miniMessage().deserialize("<b><gradient:#4d8bff:#a4ff96>MiniPlaceholders</b>");
|
||||
public static final Component HEADER = miniMessage().deserialize(
|
||||
"""
|
||||
<gradient:aqua:white:aqua><st><b> </st> \
|
||||
<title> \
|
||||
<st><b> </st>""", Placeholder.component("title", TITLE));
|
||||
public static final Component FOOTER = miniMessage().deserialize(
|
||||
"<gradient:aqua:white:aqua><st><b> ");
|
||||
|
||||
// -- /miniplaceholders --
|
||||
public static final Component INFO = AboutMenu.builder()
|
||||
.title(TITLE)
|
||||
.description(text("MiniMessage Component-based Placeholders API"))
|
||||
.credits("Author", AboutMenu.Credit.of("4drian3d").url("https://github.com/4drian3d"))
|
||||
.credits("Contributors",
|
||||
AboutMenu.Credit.of("Sliman4"),
|
||||
AboutMenu.Credit.of("Stampede2011"),
|
||||
AboutMenu.Credit.of("powercasgamer"),
|
||||
AboutMenu.Credit.of("fabianmakila"),
|
||||
AboutMenu.Credit.of("Willsr71")
|
||||
)
|
||||
.buttons(
|
||||
AboutMenu.Link.of("https://miniplaceholders.github.io/docs/category/user-guide").text("Documentation").icon("⛏"),
|
||||
AboutMenu.Link.of("https://discord.gg/5NMMzK5mAn").text("Discord").color(TextColor.color(0x7289da)).icon("⭐"),
|
||||
AboutMenu.Link.of("https://modrinth.com/plugin/miniplaceholders").text("Downloads").color(TextColor.color(0xff496e)).icon("↓")
|
||||
).version(Version.fromString(PluginConstants.VERSION))
|
||||
.build()
|
||||
.toComponent();
|
||||
|
||||
// -- /miniplaceholders help --
|
||||
public static final Supplier<Component> HELP = Suppliers.memoize(() -> {
|
||||
final Platform platform = MiniPlaceholders.platform();
|
||||
final String command = platform == Platform.VELOCITY ? "/vminiplaceholders" : "/miniplaceholders";
|
||||
return text()
|
||||
.append(newline(), HEADER)
|
||||
.append(newline(), miniMessage().deserialize(
|
||||
"<gradient:#9694ff:#5269ff>Commands:</gradient>")
|
||||
)
|
||||
.append(newline(), miniMessage().deserialize(
|
||||
"<gradient:aqua:#94d1ff>" + command + "</gradient> <aqua>help</aqua>")
|
||||
.clickEvent(ClickEvent.runCommand(command + " help"))
|
||||
)
|
||||
.append(newline(), miniMessage().deserialize(
|
||||
"""
|
||||
<gradient:aqua:#94d1ff>%s</gradient> \
|
||||
<aqua>parse</aqua> \
|
||||
<#8fadff><player | me | --null></#8fadff> \
|
||||
<#99ffb6><message></#99ffb6>""".formatted(command))
|
||||
.clickEvent(ClickEvent.suggestCommand(command + " parse "))
|
||||
)
|
||||
.append(newline(), miniMessage().deserialize(
|
||||
"""
|
||||
<gradient:aqua:#94d1ff>%s</gradient> \
|
||||
<aqua>parserel</aqua> \
|
||||
<#8fadff><player | me></#8fadff> \
|
||||
<#8fadff><relational player | me></#8fadff> \
|
||||
<#99ffb6><message></#99ffb6>""".formatted(command))
|
||||
.clickEvent(ClickEvent.suggestCommand(command + " parserel "))
|
||||
)
|
||||
.append(newline(), miniMessage().deserialize(
|
||||
"<gradient:aqua:#94d1ff>" + command + "</gradient> <aqua>expansions</aqua>")
|
||||
.clickEvent(ClickEvent.runCommand(command + " help"))
|
||||
)
|
||||
.append(newline(), FOOTER)
|
||||
.build();
|
||||
});
|
||||
|
||||
// -- /miniplaceholders expansions --
|
||||
public static final Component EXPANSIONS_TITLE = miniMessage().deserialize(
|
||||
"""
|
||||
<br><gradient:aqua:white:aqua><st><b> </st> \
|
||||
<title> Expansions <st><b> \
|
||||
</gradient><br>""", Placeholder.component("title", TITLE)
|
||||
);
|
||||
|
||||
public static final Supplier<Component> NON_INSTALLED_EXPANSIONS = Suppliers.memoize(() -> miniMessage().deserialize(
|
||||
"""
|
||||
<aqua>It seems that you don't have any <#a1ff4a>Expansion</#a1ff4a> installed yet,
|
||||
You can find the <#a1ff4a>Expansion</#a1ff4a> you want here <br>\
|
||||
<blue><click:open_url:"https://miniplaceholders.github.io/docs/user-guide/Placeholders">\
|
||||
<hover:show_text:"<gold>Search Expansions">[MiniPlaceholders Expansions]</blue>""")
|
||||
);
|
||||
}
|
||||
+7
-3
@@ -1,9 +1,13 @@
|
||||
package io.github.miniplaceholders.common.command;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import net.kyori.adventure.util.TriState;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
@FunctionalInterface
|
||||
public interface PermissionTester<S extends Audience> {
|
||||
boolean hasPermission(@NotNull S source, @NotNull String permission);
|
||||
public interface PermissionTester {
|
||||
TriState permissionValue(Audience audience, String permission);
|
||||
|
||||
PermissionTester NO_OP = (audience, permission) -> TriState.NOT_SET;
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package io.github.miniplaceholders.common.command;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface PlaceholderCommandExecutor {
|
||||
void execute(@NonNull Audience audience);
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
package io.github.miniplaceholders.common.command;
|
||||
|
||||
import io.github.miniplaceholders.common.command.node.ExpansionsNode;
|
||||
import io.github.miniplaceholders.common.command.node.HelpNode;
|
||||
import io.github.miniplaceholders.common.command.node.ParseNode;
|
||||
import io.github.miniplaceholders.common.command.node.RootNode;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.builder.AbstractBuilder;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.minecraft.extras.AudienceProvider;
|
||||
import org.incendo.cloud.minecraft.extras.MinecraftExceptionHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static net.kyori.adventure.text.minimessage.MiniMessage.miniMessage;
|
||||
|
||||
public record PlaceholdersCommand<A extends Audience>(
|
||||
PlayerSuggestions playersSuggestions,
|
||||
AudienceConverter audienceConverter,
|
||||
PermissionTester<A> hasPermission,
|
||||
String command,
|
||||
CommandManager<A> commandManager
|
||||
) {
|
||||
|
||||
public static final Component TITLE = miniMessage().deserialize("<gradient:#4d8bff:#a4ff96>MiniPlaceholders</gradient>");
|
||||
public static final Component HEADER = miniMessage().deserialize(
|
||||
"<gradient:aqua:white:aqua><st><b> </st> <title> <st><b> </st>", Placeholder.component("title", TITLE));
|
||||
public static final Component FOOTER = miniMessage().deserialize(
|
||||
"<gradient:aqua:white:aqua><st><b> ");
|
||||
|
||||
public void register() {
|
||||
//noinspection unchecked
|
||||
MinecraftExceptionHandler.create(AudienceProvider.nativeAudience())
|
||||
.defaultHandlers()
|
||||
.decorator(component -> Component.text().append(TITLE).appendSpace().append(component))
|
||||
.registerTo((CommandManager<Audience>) commandManager);
|
||||
|
||||
// Nodes
|
||||
Stream.of(new RootNode<>(hasPermission), new HelpNode<A>(), new ParseNode<A>(playersSuggestions, audienceConverter), new ExpansionsNode<A>())
|
||||
.map(handler -> handler.apply(commandManager.commandBuilder(command)))
|
||||
.forEach(commandManager::command);
|
||||
}
|
||||
|
||||
public static <A extends Audience> Builder<A> builder() {
|
||||
return new Builder<>();
|
||||
}
|
||||
|
||||
public final static class Builder<A extends Audience> implements AbstractBuilder<PlaceholdersCommand<A>> {
|
||||
private PlayerSuggestions playersSuggestions;
|
||||
private AudienceConverter audienceConverter;
|
||||
private PermissionTester<A> hasPermission;
|
||||
private String command;
|
||||
private CommandManager<A> commandManager;
|
||||
|
||||
private Builder() {}
|
||||
|
||||
public Builder<A> playerSuggestions(final @NotNull PlayerSuggestions playersSuggestions) {
|
||||
this.playersSuggestions = playersSuggestions;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<A> toAudience(final @NotNull AudienceConverter audienceConverter) {
|
||||
this.audienceConverter = audienceConverter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<A> hasPermissionCheck(final @Nullable PermissionTester<A> hasPermission) {
|
||||
this.hasPermission = hasPermission;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<A> command(final @NotNull String command) {
|
||||
this.command = command;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<A> manager(final @NotNull CommandManager<A> commandManager) {
|
||||
this.commandManager = commandManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PlaceholdersCommand<A> build() {
|
||||
return new PlaceholdersCommand<>(
|
||||
requireNonNull(playersSuggestions),
|
||||
requireNonNull(audienceConverter),
|
||||
hasPermission,
|
||||
requireNonNull(command),
|
||||
requireNonNull(commandManager)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package io.github.miniplaceholders.common.command;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface PlayerSuggestions {
|
||||
@NotNull ArrayList<String> suggest();
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package io.github.miniplaceholders.common.command;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface PlayersNameProvider {
|
||||
@NonNull ArrayList<String> provide();
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package io.github.miniplaceholders.common.command.brigadier;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import io.github.miniplaceholders.common.command.*;
|
||||
import io.github.miniplaceholders.common.command.node.*;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public final class BrigadierCommandProvider {
|
||||
public static <A> LiteralCommandNode<A> provideCommand(
|
||||
final String command,
|
||||
final PlayersNameProvider playersSuggestions,
|
||||
final AudienceConverter audienceConverter,
|
||||
final AudienceExtractor<A> audienceExtractor,
|
||||
final PermissionTester permissionChecker
|
||||
) {
|
||||
// Inspired by MiniMotd command implementation (MIT licenced)
|
||||
class WrappingExecutor implements Command<A> {
|
||||
private final PlaceholderCommandExecutor executor;
|
||||
|
||||
private WrappingExecutor(final PlaceholderCommandExecutor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int run(final CommandContext<A> commandContext) {
|
||||
executor.execute(audienceExtractor.extract(commandContext.getSource()));
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// Command Nodes
|
||||
final RootNode rootNode = new RootNode(permissionChecker);
|
||||
final ExpansionsNode expansionsNode = new ExpansionsNode(permissionChecker);
|
||||
final HelpNode helpNode = new HelpNode(permissionChecker);
|
||||
final ParseNode parseNode = new ParseNode(playersSuggestions, audienceConverter, permissionChecker);
|
||||
final ParseRelNode parseRelNode = new ParseRelNode(playersSuggestions, audienceConverter, permissionChecker);
|
||||
|
||||
return LiteralArgumentBuilder.<A>literal(command)
|
||||
.requires(src -> rootNode.hasPermission(audienceExtractor.extract(src)))
|
||||
.executes(new WrappingExecutor(rootNode::execute))
|
||||
.then(LiteralArgumentBuilder.<A>literal("expansions")
|
||||
.requires(src -> expansionsNode.hasPermission(audienceExtractor.extract(src)))
|
||||
.executes(new WrappingExecutor(expansionsNode::showExpansions))
|
||||
.build()
|
||||
)
|
||||
.then(LiteralArgumentBuilder.<A>literal("help")
|
||||
.executes(new WrappingExecutor(helpNode::execute))
|
||||
.requires(src -> helpNode.hasPermission(audienceExtractor.extract(src)))
|
||||
)
|
||||
.then(LiteralArgumentBuilder.<A>literal("parse")
|
||||
.requires(src -> parseNode.hasPermission(audienceExtractor.extract(src)))
|
||||
.then(RequiredArgumentBuilder.<A, String>argument("source", StringArgumentType.word())
|
||||
.suggests(new BrigadierSuggestionProvider<>(parseNode))
|
||||
.then(RequiredArgumentBuilder.<A, String>argument("message", StringArgumentType.greedyString())
|
||||
.executes(ctx -> {
|
||||
final Audience audience = audienceExtractor.extract(ctx.getSource());
|
||||
final String source = StringArgumentType.getString(ctx, "source");
|
||||
final String message = StringArgumentType.getString(ctx, "message");
|
||||
|
||||
parseNode.parseString(audience, source, message);
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(LiteralArgumentBuilder.<A>literal("parserel")
|
||||
.requires(src -> parseRelNode.hasPermission(audienceExtractor.extract(src)))
|
||||
.then(RequiredArgumentBuilder.<A, String>argument("source", StringArgumentType.word())
|
||||
.suggests(new BrigadierSuggestionProvider<>(parseRelNode))
|
||||
.then(RequiredArgumentBuilder.<A, String>argument("relational", StringArgumentType.word())
|
||||
.suggests(new BrigadierSuggestionProvider<>(parseRelNode))
|
||||
.then(RequiredArgumentBuilder.<A, String>argument("message", StringArgumentType.greedyString())
|
||||
.executes(ctx -> {
|
||||
final Audience audience = audienceExtractor.extract(ctx.getSource());
|
||||
final String source = StringArgumentType.getString(ctx, "source");
|
||||
final String relational = StringArgumentType.getString(ctx, "source");
|
||||
final String message = StringArgumentType.getString(ctx, "message");
|
||||
|
||||
parseRelNode.parseString(audience, source, relational, message);
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package io.github.miniplaceholders.common.command.brigadier;
|
||||
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import io.github.miniplaceholders.common.command.node.PlayerCompleterNode;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@NullMarked
|
||||
public record BrigadierSuggestionProvider<A>(PlayerCompleterNode playerSuggestions) implements SuggestionProvider<A> {
|
||||
@Override
|
||||
public CompletableFuture<Suggestions> getSuggestions(final CommandContext<A> context, final SuggestionsBuilder builder) {
|
||||
this.playerSuggestions.providePlayerSuggestions().forEach(builder::suggest);
|
||||
return builder.buildFuture();
|
||||
}
|
||||
}
|
||||
+48
-53
@@ -2,69 +2,64 @@ package io.github.miniplaceholders.common.command.node;
|
||||
|
||||
import io.github.miniplaceholders.api.Expansion;
|
||||
import io.github.miniplaceholders.api.MiniPlaceholders;
|
||||
import io.github.miniplaceholders.common.command.PermissionTester;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static io.github.miniplaceholders.common.command.PlaceholdersCommand.FOOTER;
|
||||
import static net.kyori.adventure.text.minimessage.MiniMessage.miniMessage;
|
||||
import static io.github.miniplaceholders.common.command.CommandConstants.*;
|
||||
|
||||
@NullMarked
|
||||
public record ExpansionsNode(PermissionTester permissionTester) implements Node {
|
||||
public void showExpansions(final Audience audience) {
|
||||
final TextComponent.Builder builder = Component.text()
|
||||
.append(EXPANSIONS_TITLE);
|
||||
final Collection<Expansion> expansions = MiniPlaceholders.expansionsAvailable();
|
||||
if (expansions.isEmpty()) {
|
||||
// In virtually all installations, there will always be some expansion installed,
|
||||
// so there is no need to cache this component in that case
|
||||
builder.append(NON_INSTALLED_EXPANSIONS.get());
|
||||
} else {
|
||||
builder.append(expansions.stream()
|
||||
.map(expansion -> {
|
||||
final TextComponent.Builder expansionMetaBuilder = Component.text();
|
||||
final String expansionName = expansion.name();
|
||||
final String expansionAuthor = expansion.author();
|
||||
final String expansionVersion = expansion.version();
|
||||
|
||||
expansionMetaBuilder.append(Component.text(expansionName, NamedTextColor.GRAY));
|
||||
if (expansionAuthor != null) {
|
||||
expansionMetaBuilder.appendNewline()
|
||||
.append(Component.text("Author: ", TextColor.color(0x29fbff)))
|
||||
.append(Component.text(expansionAuthor, NamedTextColor.GRAY));
|
||||
}
|
||||
if (expansionVersion != null) {
|
||||
expansionMetaBuilder.appendNewline()
|
||||
.append(Component.text("Version: ", TextColor.color(0xff7b61)))
|
||||
.append(Component.text(expansionVersion, NamedTextColor.GRAY));
|
||||
}
|
||||
return Component.text()
|
||||
.content(expansion.name())
|
||||
.hoverEvent(expansionMetaBuilder.build())
|
||||
.build();
|
||||
}).collect(Component.toComponent(Component.text(" | ", NamedTextColor.DARK_GRAY))));
|
||||
}
|
||||
builder.appendNewline().append(FOOTER);
|
||||
audience.sendMessage(builder.build());
|
||||
}
|
||||
|
||||
public final class ExpansionsNode<S extends Audience> implements Node<S> {
|
||||
@Override
|
||||
public Command.Builder<S> apply(Command.Builder<S> rootBuilder) {
|
||||
return rootBuilder.literal("expansions")
|
||||
.permission("miniplaceholders.command.expansions")
|
||||
.handler(handler -> {
|
||||
TextComponent.Builder builder = Component.text()
|
||||
.appendNewline()
|
||||
.append(miniMessage().deserialize(
|
||||
"<gradient:aqua:white:aqua><st><b> </st> <gradient:#4d8bff:#a4ff96>MiniPlaceholders</gradient> Expansions <st><b> </gradient>"
|
||||
))
|
||||
.appendNewline();
|
||||
final Collection<Expansion> expansions = MiniPlaceholders.expansionsAvailable();
|
||||
if (expansions.isEmpty()) {
|
||||
builder.append(miniMessage().deserialize("""
|
||||
<aqua>It seems that you don't have any <#a1ff4a>Expansion</#a1ff4a> installed yet,
|
||||
You can find the <#a1ff4a>Expansion</#a1ff4a> you want here"""))
|
||||
.appendSpace()
|
||||
.append(Component.text()
|
||||
.content("[MiniPlaceholders Expansions]")
|
||||
.color(NamedTextColor.BLUE)
|
||||
.clickEvent(ClickEvent.openUrl("https://github.com/MiniPlaceholders/MiniPlaceholders/wiki/Placeholders"))
|
||||
.hoverEvent(Component.text("Search Expansions", NamedTextColor.GOLD)));
|
||||
} else {
|
||||
builder.append(expansions.stream()
|
||||
.map(expansion -> {
|
||||
final TextComponent.Builder expansionMetaBuilder = Component.text();
|
||||
final String expansionName = expansion.name();
|
||||
final String expansionAuthor = expansion.author();
|
||||
final String expansionVersion = expansion.version();
|
||||
public boolean hasPermission(Audience audience) {
|
||||
return permissionTester.permissionValue(audience, permission()).toBooleanOrElse(false);
|
||||
}
|
||||
|
||||
expansionMetaBuilder.append(Component.text(expansionName, NamedTextColor.GRAY));
|
||||
if (expansionAuthor != null) {
|
||||
expansionMetaBuilder.appendNewline()
|
||||
.append(Component.text("Author: ", TextColor.color(0x29fbff)))
|
||||
.append(Component.text(expansionAuthor, NamedTextColor.GRAY));
|
||||
}
|
||||
if (expansionVersion != null){
|
||||
expansionMetaBuilder.appendNewline()
|
||||
.append(Component.text("Version: ", TextColor.color(0xff7b61)))
|
||||
.append(Component.text(expansionVersion, NamedTextColor.GRAY));
|
||||
}
|
||||
return Component.text()
|
||||
.content(expansion.name())
|
||||
.hoverEvent(expansionMetaBuilder.build())
|
||||
.build();
|
||||
}).collect(Component.toComponent(Component.text(" | "))));
|
||||
}
|
||||
builder.appendNewline().append(FOOTER);
|
||||
handler.sender().sendMessage(builder.build());
|
||||
});
|
||||
@Override
|
||||
public String permission() {
|
||||
return "miniplaceholders.command.expansions";
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,24 @@
|
||||
package io.github.miniplaceholders.common.command.node;
|
||||
|
||||
import io.github.miniplaceholders.common.command.PermissionTester;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import static io.github.miniplaceholders.common.command.PlaceholdersCommand.FOOTER;
|
||||
import static io.github.miniplaceholders.common.command.PlaceholdersCommand.HEADER;
|
||||
import static net.kyori.adventure.text.Component.newline;
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
import static net.kyori.adventure.text.minimessage.MiniMessage.miniMessage;
|
||||
import static io.github.miniplaceholders.common.command.CommandConstants.HELP;
|
||||
|
||||
public final class HelpNode<S extends Audience> implements Node<S> {
|
||||
private static final Component HELP = text()
|
||||
.append(newline(), HEADER)
|
||||
.append(newline(), miniMessage().deserialize(
|
||||
"<gradient:#9694ff:#5269ff>Commands:</gradient>"))
|
||||
.append(newline(), miniMessage().deserialize(
|
||||
"<gradient:aqua:#94d1ff>/miniplaceholders</gradient> <aqua>help</aqua>"))
|
||||
.append(newline(), miniMessage().deserialize(
|
||||
"<gradient:aqua:#94d1ff>/miniplaceholders</gradient> <aqua>parse</aqua> <#8fadff><player | me></#8fadff> <#99ffb6><player></#99ffb6>"))
|
||||
.append(newline(), miniMessage().deserialize(
|
||||
"<gradient:aqua:#94d1ff>/miniplaceholders</gradient> <aqua>expansions</aqua>"))
|
||||
.append(newline(), FOOTER)
|
||||
.build();
|
||||
@NullMarked
|
||||
public record HelpNode(PermissionTester permissionChecker) implements Node {
|
||||
public void execute(final Audience audience) {
|
||||
audience.sendMessage(HELP.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command.Builder<S> apply(Command.Builder<S> rootBuilder) {
|
||||
return rootBuilder.literal("help")
|
||||
.permission("miniplaceholders.command.help")
|
||||
.handler(handler -> handler.sender().sendMessage(HELP));
|
||||
public boolean hasPermission(Audience audience) {
|
||||
return permissionChecker.permissionValue(audience, permission()).toBooleanOrElse(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String permission() {
|
||||
return "miniplaceholders.command.help";
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
package io.github.miniplaceholders.common.command.node;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
public sealed interface Node<S extends Audience> permits ExpansionsNode, HelpNode, ParseNode, RootNode {
|
||||
Command.Builder<S> apply(Command.Builder<S> rootBuilder);
|
||||
@NullMarked
|
||||
public sealed interface Node permits ExpansionsNode, HelpNode, ParseNode, ParseRelNode, RootNode {
|
||||
boolean hasPermission(Audience audience);
|
||||
|
||||
String permission();
|
||||
}
|
||||
+41
-47
@@ -2,15 +2,12 @@ package io.github.miniplaceholders.common.command.node;
|
||||
|
||||
import io.github.miniplaceholders.api.MiniPlaceholders;
|
||||
import io.github.miniplaceholders.common.command.AudienceConverter;
|
||||
import io.github.miniplaceholders.common.command.PlayerSuggestions;
|
||||
import io.github.miniplaceholders.common.command.PermissionTester;
|
||||
import io.github.miniplaceholders.common.command.PlayersNameProvider;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.component.CommandComponent;
|
||||
import org.incendo.cloud.component.TypedCommandComponent;
|
||||
import org.incendo.cloud.description.Description;
|
||||
import org.incendo.cloud.parser.standard.StringParser;
|
||||
import org.incendo.cloud.suggestion.SuggestionProvider;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -18,48 +15,45 @@ import static net.kyori.adventure.text.Component.text;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.RED;
|
||||
import static net.kyori.adventure.text.minimessage.MiniMessage.miniMessage;
|
||||
|
||||
public record ParseNode<S extends Audience>(
|
||||
PlayerSuggestions playerSuggestions,
|
||||
AudienceConverter audienceConverter
|
||||
) implements Node<S> {
|
||||
@NullMarked
|
||||
public record ParseNode(
|
||||
PlayersNameProvider playersNameProvider,
|
||||
AudienceConverter audienceConverter,
|
||||
PermissionTester permissionChecker
|
||||
) implements Node, PlayerCompleterNode {
|
||||
public void parseString(final Audience sender, final String providedSource, final String providedString) {
|
||||
final Audience source = switch (providedSource) {
|
||||
case "me" -> sender;
|
||||
case "--null" -> Audience.empty();
|
||||
default -> audienceConverter.convert(providedSource);
|
||||
};
|
||||
if (source == null) {
|
||||
sender.sendMessage(text("You must specify a valid player", RED));
|
||||
return;
|
||||
}
|
||||
|
||||
final TagResolver resolver = source == Audience.empty()
|
||||
? MiniPlaceholders.globalPlaceholders()
|
||||
: MiniPlaceholders.audienceGlobalPlaceholders();
|
||||
|
||||
final Component parsed = miniMessage().deserialize(providedString, source, resolver);
|
||||
sender.sendMessage(parsed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command.Builder<S> apply(Command.Builder<S> rootBuilder) {
|
||||
final TypedCommandComponent<S, String> sourceArgument = CommandComponent.<S, String>ofType(String.class, "source")
|
||||
.parser(StringParser.stringParser(StringParser.StringMode.SINGLE))
|
||||
.description(Description.of("The source from which the message will be parsed"))
|
||||
.suggestionProvider(SuggestionProvider.blockingStrings((ctx, st) -> {
|
||||
final List<String> suggestions = playerSuggestions.suggest();
|
||||
suggestions.add("me");
|
||||
return suggestions;
|
||||
}))
|
||||
.build();
|
||||
final TypedCommandComponent<S, String> stringArgument = CommandComponent.<S, String>ofType(String.class, "message")
|
||||
.parser(StringParser.greedyStringParser())
|
||||
.description(Description.of("Message to be parsed"))
|
||||
.build();
|
||||
public boolean hasPermission(final Audience audience) {
|
||||
return permissionChecker.permissionValue(audience, permission()).toBooleanOrElse(false);
|
||||
}
|
||||
|
||||
return rootBuilder.literal("parse")
|
||||
.argument(sourceArgument)
|
||||
.argument(stringArgument)
|
||||
.permission("miniplaceholders.command.parse")
|
||||
.handler(handler -> {
|
||||
final String source = handler.get(sourceArgument);
|
||||
@Override
|
||||
public String permission() {
|
||||
return "miniplaceholders.command.parse";
|
||||
}
|
||||
|
||||
final Audience objective = "me".equals(source)
|
||||
? handler.sender()
|
||||
: audienceConverter.convert(source);
|
||||
if (objective == null){
|
||||
handler.sender().sendMessage(text("You must specify a valid player", RED));
|
||||
return;
|
||||
}
|
||||
final String toParse = handler.get(stringArgument);
|
||||
|
||||
final Component parsed = miniMessage().deserialize(
|
||||
toParse,
|
||||
objective,
|
||||
MiniPlaceholders.audienceGlobalPlaceholders()
|
||||
);
|
||||
handler.sender().sendMessage(parsed);
|
||||
});
|
||||
@Override
|
||||
public List<String> providePlayerSuggestions() {
|
||||
final List<String> suggestions = PlayerCompleterNode.super.providePlayerSuggestions();
|
||||
suggestions.add("--null");
|
||||
return suggestions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package io.github.miniplaceholders.common.command.node;
|
||||
|
||||
import io.github.miniplaceholders.api.MiniPlaceholders;
|
||||
import io.github.miniplaceholders.api.types.RelationalAudience;
|
||||
import io.github.miniplaceholders.common.command.AudienceConverter;
|
||||
import io.github.miniplaceholders.common.command.PermissionTester;
|
||||
import io.github.miniplaceholders.common.command.PlayersNameProvider;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.RED;
|
||||
import static net.kyori.adventure.text.minimessage.MiniMessage.miniMessage;
|
||||
|
||||
@NullMarked
|
||||
public record ParseRelNode(
|
||||
PlayersNameProvider playersNameProvider,
|
||||
AudienceConverter audienceConverter,
|
||||
PermissionTester permissionChecker
|
||||
) implements Node, PlayerCompleterNode {
|
||||
|
||||
public void parseString(final Audience sender, final String source, final String relational, final String toParse) {
|
||||
final Audience senderTarget = "me".equals(source)
|
||||
? sender
|
||||
: audienceConverter.convert(source);
|
||||
if (senderTarget == null) {
|
||||
sender.sendMessage(text("You must specify a valid player", RED));
|
||||
return;
|
||||
}
|
||||
|
||||
final Audience relationalTarget = "me".equals(relational)
|
||||
? sender
|
||||
: audienceConverter.convert(relational);
|
||||
if (relationalTarget == null) {
|
||||
sender.sendMessage(text("You must specify a valid relational player", RED));
|
||||
return;
|
||||
}
|
||||
|
||||
final RelationalAudience<Audience> relationalAudience = RelationalAudience.from(senderTarget, relationalTarget);
|
||||
|
||||
final Component parsed = miniMessage().deserialize(
|
||||
toParse,
|
||||
relationalAudience,
|
||||
MiniPlaceholders.relationalGlobalPlaceholders()
|
||||
);
|
||||
sender.sendMessage(parsed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Audience audience) {
|
||||
return permissionChecker.permissionValue(audience, permission()).toBooleanOrElse(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String permission() {
|
||||
return "miniplaceholders.command.parse";
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package io.github.miniplaceholders.common.command.node;
|
||||
|
||||
import io.github.miniplaceholders.common.command.PlayersNameProvider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PlayerCompleterNode {
|
||||
default List<String> providePlayerSuggestions() {
|
||||
final List<String> suggestions = playersNameProvider().provide();
|
||||
suggestions.add("me");
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
PlayersNameProvider playersNameProvider();
|
||||
}
|
||||
@@ -1,52 +1,26 @@
|
||||
package io.github.miniplaceholders.common.command.node;
|
||||
|
||||
import io.github.miniplaceholders.common.PluginConstants;
|
||||
import io.github.miniplaceholders.common.command.PermissionTester;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.permission.PermissionChecker;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.util.TriState;
|
||||
import net.william278.desertwell.about.AboutMenu;
|
||||
import net.william278.desertwell.util.Version;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.permission.Permission;
|
||||
import org.incendo.cloud.permission.PermissionResult;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import static io.github.miniplaceholders.common.command.PlaceholdersCommand.TITLE;
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
import static io.github.miniplaceholders.common.command.CommandConstants.INFO;
|
||||
|
||||
public record RootNode<S extends Audience>(PermissionTester<S> hasPermission) implements Node<S> {
|
||||
private static final Component INFO = AboutMenu.builder()
|
||||
.title(TITLE)
|
||||
.description(text("MiniMessage Component-based Placeholders for Paper, Folia, Fabric, Velocity and Sponge platforms"))
|
||||
.credits("Author", AboutMenu.Credit.of("4drian3d").url("https://github.com/4drian3d"))
|
||||
.credits("Contributors",
|
||||
AboutMenu.Credit.of("Sliman4"),
|
||||
AboutMenu.Credit.of("Stampede2011"),
|
||||
AboutMenu.Credit.of("powercasgamer")
|
||||
)
|
||||
.buttons(
|
||||
AboutMenu.Link.of("https://github.com/MiniPlaceholders/MiniPlaceholders/wiki/User-Getting-Started").text("Documentation").icon("⛏"),
|
||||
AboutMenu.Link.of("https://discord.gg/5NMMzK5mAn").text("Discord").color(TextColor.color(0x7289da)).icon("⭐"),
|
||||
AboutMenu.Link.of("https://modrinth.com/plugin/miniplaceholders").text("Downloads").color(TextColor.color(0xff496e)).icon("↓")
|
||||
).version(Version.fromString(PluginConstants.VERSION))
|
||||
.build()
|
||||
.toComponent();
|
||||
@NullMarked
|
||||
public record RootNode(PermissionTester permissionChecker) implements Node {
|
||||
|
||||
public void execute(Audience audience) {
|
||||
audience.sendMessage(INFO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command.Builder<S> apply(Command.Builder<S> rootBuilder) {
|
||||
return rootBuilder
|
||||
.permission(src -> {
|
||||
if (hasPermission != null) {
|
||||
return PermissionResult.of(hasPermission.hasPermission(src, "miniplaceholders.command"), Permission.permission("miniplaceholders.command"));
|
||||
}
|
||||
return PermissionResult.of(src.get(PermissionChecker.POINTER)
|
||||
.map(checker -> checker.value("miniplaceholders.command"))
|
||||
.orElse(TriState.FALSE) != TriState.FALSE,
|
||||
Permission.permission("miniplaceholders.command")
|
||||
);
|
||||
})
|
||||
.handler(handler -> handler.sender().sendMessage(INFO));
|
||||
public boolean hasPermission(Audience audience) {
|
||||
return permissionChecker.permissionValue(audience, permission()) != TriState.FALSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String permission() {
|
||||
return "miniplaceholders.command";
|
||||
}
|
||||
}
|
||||
+13
-15
@@ -1,6 +1,7 @@
|
||||
package io.github.miniplaceholders.common.loader;
|
||||
|
||||
import io.github.miniplaceholders.api.provider.ExpansionProvider;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
@@ -17,9 +18,10 @@ import java.util.Properties;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
|
||||
@NullMarked
|
||||
public final class ExpansionProviderLoader {
|
||||
|
||||
public static List<ExpansionProvider> loadProvidersFromFolder(final Path folferPath) throws Exception {
|
||||
public static List<Class<?>> loadProvidersFromFolder(final Path folferPath) throws Exception {
|
||||
if (Files.notExists(folferPath)) {
|
||||
try {
|
||||
Files.createDirectories(folferPath);
|
||||
@@ -30,7 +32,7 @@ public final class ExpansionProviderLoader {
|
||||
}
|
||||
try (final DirectoryStream<Path> stream = Files.newDirectoryStream(folferPath,
|
||||
filtered -> Files.isRegularFile(filtered) && filtered.toString().endsWith(".jar"))) {
|
||||
final List<ExpansionProvider> providerList = new ArrayList<>();
|
||||
final List<Class<?>> providerList = new ArrayList<>();
|
||||
for (final Path possibleProviderPath : stream) {
|
||||
loadPossibleProviderFromPath(possibleProviderPath, providerList);
|
||||
}
|
||||
@@ -40,7 +42,7 @@ public final class ExpansionProviderLoader {
|
||||
|
||||
private static void loadPossibleProviderFromPath(
|
||||
final Path filePath,
|
||||
final List<ExpansionProvider> providers
|
||||
final List<Class<?>> providers
|
||||
) throws Exception {
|
||||
String mainClassName = null;
|
||||
try (final JarInputStream jarStream = new JarInputStream(Files.newInputStream(filePath))) {
|
||||
@@ -56,9 +58,7 @@ public final class ExpansionProviderLoader {
|
||||
mainClassName = properties.getProperty("provider-class");
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
throw new IOException(
|
||||
"Unable to read expansion_provider.properties from " + filePath + "file",
|
||||
e);
|
||||
throw new IOException("Unable to read expansion_provider.properties from " + filePath + "file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,13 +72,15 @@ public final class ExpansionProviderLoader {
|
||||
|
||||
private static void loadFoundProvider(
|
||||
final String providerClass,
|
||||
final List<ExpansionProvider> providers,
|
||||
final List<Class<?>> providers,
|
||||
final Path providerPath
|
||||
) throws Exception {
|
||||
//noinspection resource
|
||||
final URLClassLoader classLoader = new URLClassLoader(new URL[] {
|
||||
providerPath.toUri().toURL(),
|
||||
}, ExpansionProviderLoader.class.getClassLoader());
|
||||
final URLClassLoader classLoader = new URLClassLoader(
|
||||
"MiniPlaceholders ClassLoader",
|
||||
new URL[] { providerPath.toUri().toURL() },
|
||||
ExpansionProviderLoader.class.getClassLoader()
|
||||
);
|
||||
Class<?> mainClass;
|
||||
try {
|
||||
mainClass = classLoader.loadClass(providerClass);
|
||||
@@ -88,10 +90,6 @@ public final class ExpansionProviderLoader {
|
||||
if (!ExpansionProvider.class.isAssignableFrom(mainClass) || mainClass.isInterface()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
providers.add((ExpansionProvider) mainClass.getConstructors()[0].newInstance());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to create expansion provider from file " + providerPath, e);
|
||||
}
|
||||
providers.add(mainClass);
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
package io.github.miniplaceholders.common.loader;
|
||||
|
||||
import io.github.miniplaceholders.api.provider.LoadRequirement;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
public record FailedToLoadExpansion(LoadRequirement requirement) {
|
||||
public record FailedToLoadExpansion(@NonNull LoadRequirement requirement) {
|
||||
}
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
package io.github.miniplaceholders.common.loader;
|
||||
|
||||
import io.github.miniplaceholders.api.Expansion;
|
||||
import io.github.miniplaceholders.api.provider.ExpansionProvider;
|
||||
import io.github.miniplaceholders.api.provider.LoadRequirement;
|
||||
|
||||
public record ProviderLoadResult(Expansion expansion, FailedToLoadExpansion failed) {
|
||||
public static ProviderLoadResult ofLoaded(Expansion expansion) {
|
||||
return new ProviderLoadResult(expansion, null);
|
||||
public record ProviderLoadResult(ExpansionProvider provider, FailedToLoadExpansion failed) {
|
||||
public static ProviderLoadResult ofLoaded(ExpansionProvider provider) {
|
||||
return new ProviderLoadResult(provider, null);
|
||||
}
|
||||
|
||||
public static ProviderLoadResult ofFailed(LoadRequirement requirement) {
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package io.github.miniplaceholders.common.metrics;
|
||||
|
||||
import io.github.miniplaceholders.api.MiniPlaceholders;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public final class LoadedExpansionsMetric implements Callable<Integer> {
|
||||
@Override
|
||||
public Integer call() {
|
||||
return MiniPlaceholders.expansionsAvailable().size();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ plugins {
|
||||
alias(libs.plugins.blossom)
|
||||
}
|
||||
|
||||
version = "1.0.0"
|
||||
version = "1.3.5"
|
||||
|
||||
dependencies {
|
||||
compileOnly(projects.miniplaceholdersApi)
|
||||
|
||||
+34
-24
@@ -3,34 +3,44 @@ package io.miniplaceholders.provider.example;
|
||||
import io.github.miniplaceholders.api.Expansion;
|
||||
import io.github.miniplaceholders.api.provider.ExpansionProvider;
|
||||
import io.github.miniplaceholders.api.provider.LoadRequirement;
|
||||
import io.github.miniplaceholders.api.provider.PlatformData;
|
||||
import io.github.miniplaceholders.api.types.Platform;
|
||||
import io.github.miniplaceholders.provider.example.ExpansionConstants;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import team.unnamed.inject.Inject;
|
||||
|
||||
public final class ExampleProvider implements ExpansionProvider {
|
||||
// For advanced usage only
|
||||
@team.unnamed.inject.Inject
|
||||
private io.github.miniplaceholders.api.provider.PlatformData platformData;
|
||||
public record ExampleProvider(PlatformData platformData) implements ExpansionProvider {
|
||||
@Inject
|
||||
public ExampleProvider {}
|
||||
|
||||
@Override
|
||||
public Expansion provideExpansion() {
|
||||
@Override
|
||||
public Expansion provideExpansion() {
|
||||
return Expansion.builder("example")
|
||||
.author("MiniPlaceholders Contributors")
|
||||
.globalPlaceholder("test", (queue, context) ->
|
||||
Tag.preProcessParsed("""
|
||||
Platform Instance Class: %s
|
||||
MiniPlaceholders Instance Class: %s
|
||||
""".formatted(
|
||||
platformData.serverInstance(),
|
||||
platformData.complementInstance()
|
||||
)))
|
||||
.version(ExpansionConstants.VERSION)
|
||||
.build();
|
||||
}
|
||||
|
||||
return Expansion.builder("example")
|
||||
.version("2.0.0")
|
||||
.author("MiniPlaceholders Contributors")
|
||||
.globalPlaceholder("test", (queue, context) ->
|
||||
Tag.preProcessParsed("""
|
||||
Platform Instance Class: %s
|
||||
MiniPlaceholders Instance Class: %s
|
||||
""".formatted(
|
||||
platformData.serverInstance(),
|
||||
platformData.complementInstance())))
|
||||
.version(ExpansionConstants.VERSION)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoadRequirement loadRequirement() {
|
||||
return LoadRequirement.allOf(LoadRequirement.allOf(LoadRequirement.platform(Platform.VELOCITY)));
|
||||
}
|
||||
@Override
|
||||
public LoadRequirement loadRequirement() {
|
||||
return LoadRequirement.anyOf(
|
||||
LoadRequirement.platform(Platform.SPONGE),
|
||||
LoadRequirement.allOf(
|
||||
LoadRequirement.requiredComplement(
|
||||
"MiniPlaceholders",
|
||||
"miniplaceholders"
|
||||
),
|
||||
LoadRequirement.platform(Platform.PAPER)
|
||||
),
|
||||
LoadRequirement.requiredClass("io.github.miniplaceholders.common.command.node.PlayerCompleterNode")
|
||||
);
|
||||
}
|
||||
}
|
||||
+32
-5
@@ -1,3 +1,7 @@
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
import kotlin.io.path.deleteIfExists
|
||||
|
||||
plugins {
|
||||
id("miniplaceholders.auto.module")
|
||||
id("quiet-fabric-loom")
|
||||
@@ -16,9 +20,6 @@ dependencies {
|
||||
includeDependency(libs.adventure.serializer.legacy)
|
||||
includeDependency(libs.adventure.minimessage)
|
||||
includeDependency(libs.luckopermissionsapi)
|
||||
includeDependency(libs.cloud.fabric)
|
||||
includeDependency(libs.cloud.core)
|
||||
includeDependency(libs.cloud.extras)
|
||||
includeDependency(libs.desertwell)
|
||||
includeDependency(libs.unnamedinject)
|
||||
|
||||
@@ -41,8 +42,6 @@ fun DependencyHandlerScope.includeDependency(dependency: Any) {
|
||||
include(dependency)
|
||||
}
|
||||
|
||||
|
||||
|
||||
tasks {
|
||||
val projectVersion = project.version
|
||||
val rootDir = project.rootDir
|
||||
@@ -60,6 +59,34 @@ tasks {
|
||||
shadowJar {
|
||||
configurations = listOf(shade)
|
||||
}
|
||||
// I know it's exactly the same logic for all modules,
|
||||
// but for some reason in this module it only works
|
||||
// if it's declared in the same project configuration
|
||||
// and not with a plugin like with all other projects...
|
||||
// ¯\_(ツ)_/¯
|
||||
runServer {
|
||||
val exampleExpansionProviderProject = project(":miniplaceholders-example-expansion-provider")
|
||||
val exampleExpansionJarTask = exampleExpansionProviderProject.tasks.named<Jar>("jar")
|
||||
dependsOn(exampleExpansionJarTask)
|
||||
doFirst {
|
||||
val expansionsDirectory = projectDir.resolve("run/config/miniplaceholders/expansions").toPath()
|
||||
if (Files.exists(expansionsDirectory)) {
|
||||
Files.newDirectoryStream(expansionsDirectory).use {
|
||||
it.forEach { file ->
|
||||
file.deleteIfExists()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Files.createDirectories(expansionsDirectory)
|
||||
}
|
||||
val exampleExpansionFile = exampleExpansionJarTask.get().archiveFile.get().asFile.toPath()
|
||||
Files.copy(
|
||||
exampleExpansionFile,
|
||||
expansionsDirectory.resolve(exampleExpansionFile.fileName),
|
||||
StandardCopyOption.REPLACE_EXISTING
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
|
||||
@@ -1,80 +1,86 @@
|
||||
package io.github.miniplaceholders.fabric;
|
||||
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import io.github.miniplaceholders.common.PlaceholdersPlugin;
|
||||
import io.github.miniplaceholders.common.command.PlaceholdersCommand;
|
||||
import io.github.miniplaceholders.common.command.brigadier.BrigadierCommandProvider;
|
||||
import io.github.miniplaceholders.connect.InternalPlatform;
|
||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.api.DedicatedServerModInitializer;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
||||
import net.kyori.adventure.util.TriState;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.incendo.cloud.SenderMapper;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.fabric.FabricServerCommandManager;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class FabricMod implements ModInitializer, PlaceholdersPlugin {
|
||||
private final ComponentLogger componentLogger = ComponentLogger.logger("miniplaceholders");
|
||||
private MinecraftServer minecraftServer;
|
||||
public final class FabricMod implements DedicatedServerModInitializer, PlaceholdersPlugin {
|
||||
private final ComponentLogger componentLogger = ComponentLogger.logger("miniplaceholders");
|
||||
private MinecraftServer minecraftServer;
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
componentLogger.info("Starting MiniPlaceholders Fabric");
|
||||
InternalPlatform.platform(InternalPlatform.FABRIC);
|
||||
@Override
|
||||
public void onInitializeServer() {
|
||||
componentLogger.info("Starting MiniPlaceholders Fabric");
|
||||
InternalPlatform.platform(InternalPlatform.FABRIC);
|
||||
|
||||
ServerLifecycleEvents.SERVER_STARTING.register(minecraftServer -> {
|
||||
this.minecraftServer = minecraftServer;
|
||||
try {
|
||||
final Path expansionsFolder = FabricLoader.getInstance().getConfigDir()
|
||||
.resolve("miniplaceholders").resolve("expansions");
|
||||
this.loadProvidedExpansions(expansionsFolder);
|
||||
} catch (Throwable e) {
|
||||
componentLogger.error("Unable to load expansion providers", e);
|
||||
}
|
||||
});
|
||||
ServerLifecycleEvents.SERVER_STARTING.register(minecraftServer -> {
|
||||
this.minecraftServer = minecraftServer;
|
||||
try {
|
||||
final Path expansionsFolder = FabricLoader.getInstance().getConfigDir()
|
||||
.resolve("miniplaceholders").resolve("expansions");
|
||||
this.loadProvidedExpansions(expansionsFolder);
|
||||
} catch (Throwable e) {
|
||||
componentLogger.error("Unable to load expansion providers", e);
|
||||
}
|
||||
});
|
||||
|
||||
this.registerPlatformCommand();
|
||||
}
|
||||
this.registerPlatformCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerPlatformCommand() {
|
||||
final FabricServerCommandManager<CommandSourceStack> commandManager = new FabricServerCommandManager<>(
|
||||
ExecutionCoordinator.simpleCoordinator(),
|
||||
SenderMapper.identity()
|
||||
);
|
||||
PlaceholdersCommand.<CommandSourceStack>builder()
|
||||
.hasPermissionCheck((source, permission) -> Permissions.check(source, permission, 4))
|
||||
.toAudience(string -> this.minecraftServer.getPlayerList().getPlayerByName(string))
|
||||
.playerSuggestions(() -> new ArrayList<>(List.of(this.minecraftServer.getPlayerNames())))
|
||||
.manager(commandManager)
|
||||
.command("miniplaceholders")
|
||||
.build()
|
||||
.register();
|
||||
}
|
||||
@Override
|
||||
public void registerPlatformCommand() {
|
||||
final LiteralCommandNode<CommandSourceStack> node = BrigadierCommandProvider.provideCommand(
|
||||
"miniplaceholders",
|
||||
() -> new ArrayList<>(List.of(this.minecraftServer.getPlayerNames())),
|
||||
string -> this.minecraftServer.getPlayerList().getPlayerByName(string),
|
||||
aud -> aud,
|
||||
(audience, permission) -> {
|
||||
final CommandSourceStack commandSourceStack = (CommandSourceStack) audience;
|
||||
return switch (Permissions.getPermissionValue(commandSourceStack, permission)) {
|
||||
case TRUE -> TriState.TRUE;
|
||||
case FALSE -> TriState.FALSE;
|
||||
case DEFAULT -> commandSourceStack.hasPermission(3) ? TriState.TRUE : TriState.NOT_SET;
|
||||
};
|
||||
}
|
||||
);
|
||||
CommandRegistrationCallback.EVENT.register(
|
||||
(dispatcher, ctx, selection) ->
|
||||
dispatcher.getRoot().addChild(node)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean platformHasComplementLoaded(String complementName) {
|
||||
return FabricLoader.getInstance().isModLoaded(complementName);
|
||||
}
|
||||
@Override
|
||||
public boolean platformHasComplementLoaded(String complementName) {
|
||||
return FabricLoader.getInstance().isModLoaded(complementName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logError(Component component) {
|
||||
componentLogger.error(component);
|
||||
}
|
||||
@Override
|
||||
public void logError(Component component) {
|
||||
componentLogger.error(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logInfo(Component component) {
|
||||
componentLogger.info(component);
|
||||
}
|
||||
@Override
|
||||
public void logInfo(Component component) {
|
||||
componentLogger.info(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object platformServerInstance() {
|
||||
return this.minecraftServer;
|
||||
}
|
||||
@Override
|
||||
public Object platformServerInstance() {
|
||||
return this.minecraftServer;
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,14 @@
|
||||
"4drian3d"
|
||||
],
|
||||
"contact": {
|
||||
"homepage": "https://github.com/MiniPlaceholders/MiniPlaceholders",
|
||||
"homepage": "https://miniplaceholders.github.io/",
|
||||
"sources": "https://github.com/MiniPlaceholders/MiniPlaceholders",
|
||||
"issues": "https://github.com/MiniPlaceholders/MiniPlaceholders/issues"
|
||||
},
|
||||
"license": "Apache-2",
|
||||
"environment": "server",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"server": [
|
||||
"io.github.miniplaceholders.fabric.FabricMod"
|
||||
]
|
||||
},
|
||||
@@ -23,9 +23,8 @@
|
||||
"fabricloader": ">=0.14.19",
|
||||
"fabric": "*",
|
||||
"java": ">=21",
|
||||
"cloud": "*",
|
||||
"adventure-platform-fabric": "*",
|
||||
"minecraft": ">=1.21.6",
|
||||
"fabric-permissions-api-v0": "*"
|
||||
"adventure-platform-fabric": "~6.6.0",
|
||||
"minecraft": ">=1.21.6 <=1.21.8",
|
||||
"fabric-permissions-api-v0": "~0.4.1"
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
group = io.github.miniplaceholders
|
||||
version = 3.0.1
|
||||
version = 3.1.0
|
||||
description = MiniMessage Component-based Placeholders API
|
||||
|
||||
org.gradle.jvmargs=-Xmx2G
|
||||
|
||||
+16
-17
@@ -6,23 +6,21 @@ velocity = "3.4.0-SNAPSHOT"
|
||||
paper = "1.21.8-R0.1-SNAPSHOT"
|
||||
minecraft = "1.21.8"
|
||||
|
||||
runtask = "2.3.1"
|
||||
runtask = "3.0.1"
|
||||
blossom = "2.1.0"
|
||||
shadow = "9.0.2"
|
||||
shadow = "9.2.2"
|
||||
jmh = "0.7.3"
|
||||
dokka = "2.0.0"
|
||||
|
||||
cloud = "2.0.0"
|
||||
cloud-minecraft = "2.0.0-SNAPSHOT"
|
||||
cloud-minecraft-modded = "2.0.0-SNAPSHOT"
|
||||
adventure = "4.24.0"
|
||||
adventureModded = "6.6.0"
|
||||
kotlin = "2.2.20-RC"
|
||||
kotlin = "2.2.20"
|
||||
|
||||
fabric-api = "0.132.0+1.21.8"
|
||||
fabric-loader = "0.17.2"
|
||||
fabric-api = "0.134.0+1.21.8"
|
||||
fabric-loader = "0.17.3"
|
||||
|
||||
desertwell = "2.0.4"
|
||||
bstats = "3.1.0"
|
||||
|
||||
[libraries]
|
||||
|
||||
@@ -40,22 +38,23 @@ adventure-platform-fabric = { group = "net.kyori", name = "adventure-platform-fa
|
||||
adventure-serializer-legacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" }
|
||||
adventure-serializer-plain = { group = "net.kyori", name = "adventure-text-serializer-plain", version.ref = "adventure" }
|
||||
|
||||
cloud-core = { group = "org.incendo", name = "cloud-core", version.ref = "cloud" }
|
||||
cloud-velocity = { group = "org.incendo", name = "cloud-velocity", version.ref = "cloud-minecraft" }
|
||||
cloud-paper = { group = "org.incendo", name = "cloud-paper", version.ref = "cloud-minecraft" }
|
||||
cloud-fabric = { group = "org.incendo", name = "cloud-fabric", version.ref = "cloud-minecraft-modded" }
|
||||
cloud-extras = { group = "org.incendo", name = "cloud-minecraft-extras", version.ref = "cloud-minecraft" }
|
||||
|
||||
plugin-shadow = { module = "com.gradleup.shadow:shadow-gradle-plugin", version.ref = "shadow" }
|
||||
plugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
plugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
plugin-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" }
|
||||
plugin-runtask = { module = "xyz.jpenilla.run-velocity:xyz.jpenilla.run-velocity.gradle.plugin", version.ref = "runtask" }
|
||||
|
||||
desertwell = { group = "net.william278", name = "DesertWell", version.ref = "desertwell" }
|
||||
|
||||
junit-bom = "org.junit:junit-bom:5.13.4"
|
||||
junit-bom = "org.junit:junit-bom:6.0.0"
|
||||
jspecify = "org.jspecify:jspecify:1.0.0"
|
||||
|
||||
unnamedinject = "team.unnamed:inject:2.0.1"
|
||||
brigadier = "com.mojang:brigadier:1.0.500"
|
||||
|
||||
bstats-core = { group = "org.bstats", name = "bstats-base", version.ref = "bstats" }
|
||||
bstats-velocity = { group = "org.bstats", name = "bstats-velocity", version.ref = "bstats" }
|
||||
bstats-sponge = { group = "org.bstats", name = "bstats-sponge", version.ref = "bstats" }
|
||||
bstats-bukkit = { group = "org.bstats", name = "bstats-bukkit", version.ref = "bstats" }
|
||||
|
||||
[plugins]
|
||||
|
||||
@@ -64,5 +63,5 @@ runvelocity = { id = "xyz.jpenilla.run-velocity", version.ref = "runtask" }
|
||||
blossom = { id = "net.kyori.blossom", version.ref = "blossom" }
|
||||
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
|
||||
jmh = { id = "me.champeau.jmh", version.ref = "jmh" }
|
||||
idea-ext = { id = "org.jetbrains.gradle.plugin.idea-ext", version = "1.2" }
|
||||
idea-ext = { id = "org.jetbrains.gradle.plugin.idea-ext", version = "1.3" }
|
||||
dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -114,7 +114,6 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -172,7 +171,6 @@ fi
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
@@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
|
||||
Vendored
+1
-2
@@ -70,11 +70,10 @@ goto fail
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id("miniplaceholders.auto.module")
|
||||
id("miniplaceholders.shadow")
|
||||
id("miniplaceholders.runtask")
|
||||
alias(libs.plugins.runpaper)
|
||||
}
|
||||
|
||||
@@ -9,16 +10,17 @@ dependencies {
|
||||
implementation(projects.miniplaceholdersCommon)
|
||||
implementation(projects.miniplaceholdersApi)
|
||||
implementation(projects.miniplaceholdersConnect)
|
||||
implementation(libs.cloud.paper)
|
||||
|
||||
implementation(libs.bstats.bukkit)
|
||||
}
|
||||
|
||||
tasks {
|
||||
runServer {
|
||||
jvmArgs("-Dcom.mojang.eula.agree=true")
|
||||
minecraftVersion(libs.versions.minecraft.get())
|
||||
}
|
||||
val projectVersion = project.version
|
||||
processResources {
|
||||
//val version = project.version
|
||||
filesMatching("paper-plugin.yml") {
|
||||
expand("version" to projectVersion)
|
||||
}
|
||||
|
||||
@@ -1,51 +1,48 @@
|
||||
package io.github.miniplaceholders.paper;
|
||||
|
||||
import io.github.miniplaceholders.common.command.PlaceholdersCommand;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import io.github.miniplaceholders.common.command.brigadier.BrigadierCommandProvider;
|
||||
import io.github.miniplaceholders.connect.InternalPlatform;
|
||||
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
||||
import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.audience.ForwardingAudience;
|
||||
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
|
||||
import net.kyori.adventure.util.TriState;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.incendo.cloud.SenderMapper;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.paper.PaperCommandManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings({"unused", "UnstableApiUsage"})
|
||||
@NullMarked
|
||||
public final class PaperBootstrap implements PluginBootstrap {
|
||||
@Override
|
||||
public void bootstrap(@NotNull BootstrapContext bootstrapContext) {
|
||||
public void bootstrap(final BootstrapContext bootstrapContext) {
|
||||
InternalPlatform.platform(InternalPlatform.PAPER);
|
||||
PaperCommandManager<SourceWrapper> commandManager = PaperCommandManager
|
||||
.builder(SenderMapper.create(SourceWrapper::new, SourceWrapper::stack))
|
||||
.executionCoordinator(ExecutionCoordinator.simpleCoordinator())
|
||||
.buildBootstrapped(bootstrapContext);
|
||||
final LiteralCommandNode<CommandSourceStack> command = BrigadierCommandProvider.provideCommand(
|
||||
"miniplaceholders",
|
||||
() -> Bukkit.getServer()
|
||||
.getOnlinePlayers()
|
||||
.stream()
|
||||
.map(Player::getName)
|
||||
.collect(Collectors.toCollection(ArrayList::new)),
|
||||
string -> Bukkit.getServer().getPlayer(string),
|
||||
CommandSourceStack::getSender,
|
||||
(audience, permission) -> {
|
||||
final CommandSender sender = (CommandSender) audience;
|
||||
final TriState triState = sender.permissionValue(permission);
|
||||
return triState == TriState.NOT_SET
|
||||
? sender.isOp() ? TriState.TRUE : TriState.NOT_SET
|
||||
: triState;
|
||||
}
|
||||
);
|
||||
bootstrapContext.getLifecycleManager()
|
||||
.registerEventHandler(LifecycleEvents.COMMANDS,
|
||||
commands -> commands.registrar().register(bootstrapContext.getPluginMeta(), command, "", List.of()));
|
||||
|
||||
PlaceholdersCommand.<SourceWrapper>builder()
|
||||
.playerSuggestions(() -> Bukkit.getServer().getOnlinePlayers()
|
||||
.stream()
|
||||
.map(Player::getName)
|
||||
.collect(Collectors.toCollection(ArrayList::new)))
|
||||
.toAudience(st -> Bukkit.getServer().getPlayer(st))
|
||||
.hasPermissionCheck((aud, p) -> aud.stack.getSender().hasPermission(p))
|
||||
.manager(commandManager)
|
||||
.command("miniplaceholders")
|
||||
.build()
|
||||
.register();
|
||||
|
||||
}
|
||||
|
||||
public record SourceWrapper(CommandSourceStack stack) implements ForwardingAudience.Single {
|
||||
|
||||
@Override
|
||||
public @NotNull Audience audience() {
|
||||
return this.stack.getSender();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
package io.github.miniplaceholders.paper;
|
||||
|
||||
import io.github.miniplaceholders.common.PlaceholdersPlugin;
|
||||
import io.github.miniplaceholders.common.metrics.LoadedExpansionsMetric;
|
||||
import io.github.miniplaceholders.paper.listener.ServerFinishedLoadListener;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bstats.charts.SingleLineChart;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
@@ -15,11 +19,9 @@ public final class PaperPlugin extends JavaPlugin implements PlaceholdersPlugin
|
||||
final ComponentLogger componentLogger = getComponentLogger();
|
||||
componentLogger.info(text("Starting MiniPlaceholders Paper", NamedTextColor.GREEN));
|
||||
|
||||
try {
|
||||
this.loadProvidedExpansions(getDataPath().resolve("expansions"));
|
||||
} catch (Throwable e) {
|
||||
componentLogger.error("Unable to load expansion providers", e);
|
||||
}
|
||||
new ServerFinishedLoadListener(this).register();
|
||||
final Metrics metrics = new Metrics(this, 27515);
|
||||
metrics.addCustomChart(new SingleLineChart("loaded_expansions", new LoadedExpansionsMetric()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package io.github.miniplaceholders.paper.listener;
|
||||
|
||||
import io.github.miniplaceholders.paper.PaperPlugin;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.ServerLoadEvent;
|
||||
import org.bukkit.plugin.EventExecutor;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
public record ServerFinishedLoadListener(PaperPlugin plugin) implements Listener, EventExecutor {
|
||||
|
||||
public void register() {
|
||||
plugin.getServer()
|
||||
.getPluginManager()
|
||||
.registerEvent(ServerLoadEvent.class, this, EventPriority.HIGH, this, plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final @NonNull Listener listener, final @NonNull Event event) {
|
||||
final ServerLoadEvent loadEvent = (ServerLoadEvent) event;
|
||||
if (loadEvent.getType() != ServerLoadEvent.LoadType.STARTUP) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
plugin.loadProvidedExpansions(plugin.getDataPath().resolve("expansions"));
|
||||
} catch (Throwable e) {
|
||||
plugin.getComponentLogger().error("Unable to load expansion providers", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -37,10 +37,10 @@ dependencyResolutionManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("quiet-fabric-loom") version "1.11.324"
|
||||
id("quiet-fabric-loom") version "1.11.325"
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
|
||||
id("com.vanniktech.maven.publish") version "0.34.0" apply false
|
||||
kotlin("jvm") version "2.2.20-RC" apply false
|
||||
kotlin("jvm") version "2.2.20" apply false
|
||||
}
|
||||
|
||||
arrayOf(
|
||||
|
||||
+33
-3
@@ -1,5 +1,8 @@
|
||||
import org.spongepowered.gradle.plugin.config.PluginLoaders
|
||||
import org.spongepowered.plugin.metadata.model.PluginDependency
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
import kotlin.io.path.deleteIfExists
|
||||
|
||||
plugins {
|
||||
id("miniplaceholders.auto.module")
|
||||
@@ -8,11 +11,12 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.miniplaceholdersCommon) {
|
||||
exclude(group = "org.incendo")
|
||||
}
|
||||
implementation(projects.miniplaceholdersCommon)
|
||||
implementation(projects.miniplaceholdersApi)
|
||||
implementation(projects.miniplaceholdersConnect)
|
||||
|
||||
compileOnly(libs.jspecify)
|
||||
implementation(libs.bstats.sponge)
|
||||
}
|
||||
|
||||
sponge {
|
||||
@@ -41,3 +45,29 @@ sponge {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
runServer {
|
||||
val exampleExpansionProviderProject = project(":miniplaceholders-example-expansion-provider")
|
||||
val exampleExpansionJarTask = exampleExpansionProviderProject.tasks.named<Jar>("jar")
|
||||
dependsOn(exampleExpansionJarTask)
|
||||
doFirst {
|
||||
val expansionsDirectory = projectDir.resolve("run/config/miniplaceholders/expansions").toPath()
|
||||
if (Files.exists(expansionsDirectory)) {
|
||||
Files.newDirectoryStream(expansionsDirectory).use {
|
||||
it.forEach { file ->
|
||||
file.deleteIfExists()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Files.createDirectories(expansionsDirectory)
|
||||
}
|
||||
val exampleExpansionFile = exampleExpansionJarTask.get().archiveFile.get().asFile.toPath()
|
||||
Files.copy(
|
||||
exampleExpansionFile,
|
||||
expansionsDirectory.resolve(exampleExpansionFile.fileName),
|
||||
StandardCopyOption.REPLACE_EXISTING
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,72 +2,88 @@ package io.github.miniplaceholders.sponge;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import io.github.miniplaceholders.common.PlaceholdersPlugin;
|
||||
import io.github.miniplaceholders.common.metrics.LoadedExpansionsMetric;
|
||||
import io.github.miniplaceholders.connect.InternalPlatform;
|
||||
import io.github.miniplaceholders.sponge.command.SpongeCommand;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bstats.charts.SingleLineChart;
|
||||
import org.bstats.sponge.Metrics;
|
||||
import org.spongepowered.api.Server;
|
||||
import org.spongepowered.api.command.Command;
|
||||
import org.spongepowered.api.config.ConfigDir;
|
||||
import org.spongepowered.api.event.Listener;
|
||||
import org.spongepowered.api.event.lifecycle.RegisterCommandEvent;
|
||||
import org.spongepowered.api.event.lifecycle.StartedEngineEvent;
|
||||
import org.spongepowered.api.event.lifecycle.StartingEngineEvent;
|
||||
import org.spongepowered.plugin.PluginContainer;
|
||||
import org.spongepowered.plugin.builtin.jvm.Plugin;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Plugin("miniplaceholders")
|
||||
public class SpongePlugin implements PlaceholdersPlugin {
|
||||
|
||||
@Inject
|
||||
private Logger logger;
|
||||
@Inject
|
||||
@ConfigDir(sharedRoot = false)
|
||||
private Path configDir;
|
||||
@Inject
|
||||
private Logger logger;
|
||||
@Inject
|
||||
@ConfigDir(sharedRoot = false)
|
||||
private Path configDir;
|
||||
@Inject
|
||||
private PluginContainer pluginContainer;
|
||||
@Inject
|
||||
private Metrics.Factory factory;
|
||||
|
||||
private Server server;
|
||||
private Server server;
|
||||
private Metrics metrics;
|
||||
|
||||
@Listener
|
||||
public void onServerStart(final StartingEngineEvent<Server> event) {
|
||||
this.server = event.engine();
|
||||
logger.info("Starting MiniPlaceholders Sponge");
|
||||
InternalPlatform.platform(InternalPlatform.SPONGE);
|
||||
@Listener
|
||||
public void onServerStart(final StartingEngineEvent<Server> event) {
|
||||
this.server = event.engine();
|
||||
InternalPlatform.platform(InternalPlatform.SPONGE);
|
||||
logger.info("Starting MiniPlaceholders Sponge");
|
||||
|
||||
try {
|
||||
this.loadProvidedExpansions(configDir.resolve("expansions"));
|
||||
} catch (Throwable e) {
|
||||
logger.error("Unable to load expansion providers", e);
|
||||
}
|
||||
this.metrics = factory.make(27517);
|
||||
}
|
||||
|
||||
@Listener
|
||||
public void onLateServerStart(final StartedEngineEvent<Server> event) {
|
||||
try {
|
||||
this.loadProvidedExpansions(configDir.resolve("expansions"));
|
||||
} catch (Throwable e) {
|
||||
logger.error("Unable to load expansion providers", e);
|
||||
}
|
||||
|
||||
private final AtomicInteger registration = new AtomicInteger(0);
|
||||
// bstats sponge weird initialization workaround
|
||||
this.metrics.startup(null);
|
||||
this.metrics.addCustomChart(new SingleLineChart("expansions_loaded", new LoadedExpansionsMetric()));
|
||||
}
|
||||
|
||||
@Listener
|
||||
public void onCommandRegister(final RegisterCommandEvent<Command.Parameterized> event) {
|
||||
if (registration.getAndIncrement() == 0) {
|
||||
this.registerPlatformCommand();
|
||||
}
|
||||
}
|
||||
@Listener
|
||||
public void onCommandRegister(final RegisterCommandEvent<Command.Parameterized> event) {
|
||||
event.register(pluginContainer, SpongeCommand.provideCommand(), "miniplaceholders");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean platformHasComplementLoaded(String complementName) {
|
||||
return server.game().pluginManager().plugin(complementName).isPresent();
|
||||
}
|
||||
@Override
|
||||
public boolean platformHasComplementLoaded(String complementName) {
|
||||
return server.game().pluginManager().plugin(complementName).isPresent();
|
||||
}
|
||||
|
||||
// TODO: Replace this with some implementation of a ComponentLogger
|
||||
@Override
|
||||
public void logError(Component component) {
|
||||
logger.error(PlainTextComponentSerializer.plainText().serialize(component));
|
||||
}
|
||||
// TODO: Replace this with some implementation of a ComponentLogger
|
||||
@Override
|
||||
public void logError(Component component) {
|
||||
logger.error(PlainTextComponentSerializer.plainText().serialize(component));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logInfo(Component component) {
|
||||
logger.info(PlainTextComponentSerializer.plainText().serialize(component));
|
||||
}
|
||||
@Override
|
||||
public void logInfo(Component component) {
|
||||
logger.info(PlainTextComponentSerializer.plainText().serialize(component));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object platformServerInstance() {
|
||||
return this.server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object platformServerInstance() {
|
||||
return this.server;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package io.github.miniplaceholders.sponge.command;
|
||||
|
||||
import io.github.miniplaceholders.common.command.*;
|
||||
import io.github.miniplaceholders.common.command.node.*;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.command.*;
|
||||
import org.spongepowered.api.command.parameter.CommandContext;
|
||||
import org.spongepowered.api.command.parameter.Parameter;
|
||||
import org.spongepowered.api.entity.living.player.User;
|
||||
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
|
||||
import org.spongepowered.api.util.Tristate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@NullMarked
|
||||
public final class SpongeCommand {
|
||||
public static Command.Parameterized provideCommand() {
|
||||
final AudienceExtractor<CommandCause> audienceExtractor = CommandCause::audience;
|
||||
final PermissionTester permissionTester = PermissionTester.NO_OP; // Not really used here
|
||||
final PlayersNameProvider playerSuggestions = () -> Sponge.server().onlinePlayers()
|
||||
.stream()
|
||||
.map(ServerPlayer::user)
|
||||
.map(User::name)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
final AudienceConverter audienceConverter = string -> Sponge.server().player(string).orElse(null);
|
||||
|
||||
// Command Nodes
|
||||
final RootNode rootNode = new RootNode(permissionTester);
|
||||
final ExpansionsNode expansionsNode = new ExpansionsNode(permissionTester);
|
||||
final ParseNode parseNode = new ParseNode(playerSuggestions, audienceConverter, permissionTester);
|
||||
final ParseRelNode parseRelNode = new ParseRelNode(playerSuggestions, audienceConverter, permissionTester);
|
||||
final HelpNode helpNode = new HelpNode(permissionTester);
|
||||
|
||||
final Parameter.Value<String> sourceParameter = Parameter.string().key("source")
|
||||
.completer((context, currentInput) -> parseNode.providePlayerSuggestions()
|
||||
.stream()
|
||||
.map(CommandCompletion::of)
|
||||
.toList()
|
||||
).build();
|
||||
final Parameter.Value<String> relationalSourceParameter = Parameter.string().key("relational")
|
||||
.completer((context, currentInput) -> parseNode.providePlayerSuggestions()
|
||||
.stream()
|
||||
.map(CommandCompletion::of)
|
||||
.toList()
|
||||
).build();
|
||||
final Parameter.Value<String> messageParameter = Parameter.remainingJoinedStrings().key("message").build();
|
||||
|
||||
return Command.builder()
|
||||
.executionRequirements(src -> src.permissionValue(rootNode.permission()) != Tristate.FALSE)
|
||||
.executor(new WrappingExecutor(rootNode::execute))
|
||||
.addChildren(Map.of(
|
||||
List.of("expansions"), Command.builder()
|
||||
.permission(expansionsNode.permission())
|
||||
.executor(new WrappingExecutor(expansionsNode::showExpansions))
|
||||
.build(),
|
||||
List.of("help"), Command.builder()
|
||||
.permission(helpNode.permission())
|
||||
.executor(new WrappingExecutor(helpNode::execute))
|
||||
.build(),
|
||||
List.of("parse"), Command.builder()
|
||||
.permission(parseNode.permission())
|
||||
.addParameter(sourceParameter)
|
||||
.addParameter(messageParameter)
|
||||
.executor(ctx -> {
|
||||
final Audience executor = audienceExtractor.extract(ctx.cause());
|
||||
final String source = ctx.requireOne(sourceParameter);
|
||||
final String message = ctx.requireOne(messageParameter);
|
||||
|
||||
parseNode.parseString(executor, source, message);
|
||||
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build(),
|
||||
List.of("parserel"), Command.builder()
|
||||
.permission(parseRelNode.permission())
|
||||
.addParameter(sourceParameter)
|
||||
.addParameter(relationalSourceParameter)
|
||||
.addParameter(messageParameter)
|
||||
.executor(ctx -> {
|
||||
final Audience executor = audienceExtractor.extract(ctx.cause());
|
||||
final String source = ctx.requireOne(sourceParameter);
|
||||
final String relational = ctx.requireOne(relationalSourceParameter);
|
||||
final String message = ctx.requireOne(messageParameter);
|
||||
|
||||
parseRelNode.parseString(executor, source, relational, message);
|
||||
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build()
|
||||
))
|
||||
.build();
|
||||
}
|
||||
|
||||
private record WrappingExecutor(PlaceholderCommandExecutor executor) implements CommandExecutor {
|
||||
@Override
|
||||
public CommandResult execute(CommandContext context) {
|
||||
executor.execute(context.cause().audience());
|
||||
return CommandResult.success();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id("miniplaceholders.shadow")
|
||||
id("miniplaceholders.auto.module")
|
||||
id("miniplaceholders.runtask")
|
||||
alias(libs.plugins.runvelocity)
|
||||
}
|
||||
|
||||
@@ -10,7 +11,8 @@ dependencies {
|
||||
implementation(projects.miniplaceholdersCommon)
|
||||
implementation(projects.miniplaceholdersApi)
|
||||
implementation(projects.miniplaceholdersConnect)
|
||||
implementation(libs.cloud.velocity)
|
||||
|
||||
implementation(libs.bstats.velocity)
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package io.github.miniplaceholders.velocity;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import com.velocitypowered.api.command.BrigadierCommand;
|
||||
import com.velocitypowered.api.command.CommandManager;
|
||||
import com.velocitypowered.api.command.CommandMeta;
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
@@ -13,97 +14,96 @@ import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import io.github.miniplaceholders.common.PlaceholdersPlugin;
|
||||
import io.github.miniplaceholders.common.PluginConstants;
|
||||
import io.github.miniplaceholders.common.command.PlaceholdersCommand;
|
||||
import io.github.miniplaceholders.common.command.brigadier.BrigadierCommandProvider;
|
||||
import io.github.miniplaceholders.common.metrics.LoadedExpansionsMetric;
|
||||
import io.github.miniplaceholders.connect.InternalPlatform;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
||||
import org.incendo.cloud.SenderMapper;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.velocity.CloudInjectionModule;
|
||||
import org.incendo.cloud.velocity.VelocityCommandManager;
|
||||
import org.bstats.charts.SingleLineChart;
|
||||
import org.bstats.velocity.Metrics;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Plugin(
|
||||
name = "MiniPlaceholders",
|
||||
id = "miniplaceholders",
|
||||
version = PluginConstants.VERSION,
|
||||
authors = {"MiniPlaceholders Contributors", "4drian3d"},
|
||||
description = "MiniMessage Component-based Placeholders API"
|
||||
name = "MiniPlaceholders",
|
||||
id = "miniplaceholders",
|
||||
version = PluginConstants.VERSION,
|
||||
authors = {"MiniPlaceholders Contributors", "4drian3d"},
|
||||
description = "MiniMessage Component-based Placeholders API"
|
||||
)
|
||||
public final class VelocityPlugin implements PlaceholdersPlugin {
|
||||
@Inject
|
||||
private Injector injector;
|
||||
@Inject
|
||||
@DataDirectory
|
||||
private Path dataDirectory;
|
||||
@Inject
|
||||
private ProxyServer proxyServer;
|
||||
@Inject
|
||||
private ComponentLogger componentLogger;
|
||||
@Inject
|
||||
@DataDirectory
|
||||
private Path dataDirectory;
|
||||
@Inject
|
||||
private ProxyServer proxyServer;
|
||||
@Inject
|
||||
private CommandManager commandManager;
|
||||
@Inject
|
||||
private ComponentLogger componentLogger;
|
||||
@Inject
|
||||
private Metrics.Factory metricsFactory;
|
||||
|
||||
@Subscribe(priority = 999)
|
||||
public void onEarlyProxyInitialize(final ProxyInitializeEvent event) {
|
||||
componentLogger.info(Component.text("Starting MiniPlaceholders Velocity", NamedTextColor.GREEN));
|
||||
@Subscribe(priority = 999)
|
||||
public void onEarlyProxyInitialize(final ProxyInitializeEvent event) {
|
||||
InternalPlatform.platform(InternalPlatform.VELOCITY);
|
||||
componentLogger.info(Component.text("Starting MiniPlaceholders Velocity", NamedTextColor.GREEN));
|
||||
|
||||
InternalPlatform.platform(InternalPlatform.VELOCITY);
|
||||
this.registerPlatformCommand();
|
||||
|
||||
this.registerPlatformCommand();
|
||||
final Metrics metrics = metricsFactory.make(this, 27516);
|
||||
metrics.addCustomChart(new SingleLineChart("expansions_count", new LoadedExpansionsMetric()));
|
||||
}
|
||||
|
||||
@Subscribe(priority = -404)
|
||||
public void onLateProxyInitialize(final ProxyInitializeEvent event) {
|
||||
try {
|
||||
this.loadProvidedExpansions(dataDirectory.resolve("expansions"));
|
||||
} catch (Throwable e) {
|
||||
componentLogger.error("Unable to load expansion providers", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(priority = -404)
|
||||
public void onLateProxyInitialize(final ProxyInitializeEvent event) {
|
||||
try {
|
||||
this.loadProvidedExpansions(dataDirectory.resolve("expansions"));
|
||||
} catch (Throwable e) {
|
||||
componentLogger.error("Unable to load expansion providers", e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void registerPlatformCommand() {
|
||||
final LiteralCommandNode<CommandSource> node = BrigadierCommandProvider.provideCommand(
|
||||
"vminiplaceholders",
|
||||
() -> this.proxyServer.getAllPlayers()
|
||||
.stream()
|
||||
.map(Player::getUsername)
|
||||
.collect(Collectors.toCollection(ArrayList::new)),
|
||||
str -> this.proxyServer.getPlayer(str).orElse(null),
|
||||
aud -> aud,
|
||||
(audience, permission) -> ((CommandSource) audience).getPermissionValue(permission)
|
||||
.toAdventureTriState()
|
||||
);
|
||||
final BrigadierCommand command = new BrigadierCommand(node);
|
||||
final CommandMeta meta = this.commandManager.metaBuilder(command)
|
||||
.plugin(this)
|
||||
.build();
|
||||
this.commandManager.register(meta, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerPlatformCommand() {
|
||||
injector = injector.createChildInjector(
|
||||
new CloudInjectionModule<>(
|
||||
CommandSource.class,
|
||||
ExecutionCoordinator.simpleCoordinator(),
|
||||
SenderMapper.identity()
|
||||
)
|
||||
);
|
||||
final VelocityCommandManager<CommandSource> commandManager = injector.getInstance(
|
||||
Key.get(new TypeLiteral<>() {
|
||||
})
|
||||
);
|
||||
PlaceholdersCommand.<CommandSource>builder()
|
||||
.playerSuggestions(() -> proxyServer.getAllPlayers()
|
||||
.stream()
|
||||
.map(Player::getUsername)
|
||||
.collect(Collectors.toCollection(ArrayList::new)))
|
||||
.toAudience(st -> proxyServer.getPlayer(st).orElse(null))
|
||||
.command("vminiplaceholders")
|
||||
.manager(commandManager)
|
||||
.build().register();
|
||||
}
|
||||
@Override
|
||||
public boolean platformHasComplementLoaded(String complementName) {
|
||||
return this.proxyServer.getPluginManager().isLoaded(complementName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean platformHasComplementLoaded(String complementName) {
|
||||
return this.proxyServer.getPluginManager().isLoaded(complementName);
|
||||
}
|
||||
@Override
|
||||
public void logError(Component component) {
|
||||
componentLogger.error(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logError(Component component) {
|
||||
componentLogger.error(component);
|
||||
}
|
||||
@Override
|
||||
public void logInfo(Component component) {
|
||||
componentLogger.info(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logInfo(Component component) {
|
||||
componentLogger.info(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object platformServerInstance() {
|
||||
return this.proxyServer;
|
||||
}
|
||||
@Override
|
||||
public Object platformServerInstance() {
|
||||
return this.proxyServer;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user