Skip to content

Commit b94fa95

Browse files
authored
GH-55 Support for multiple paper versions with dependency injector. (Resolve #54)
1 parent a1d6360 commit b94fa95

File tree

5 files changed

+178
-4
lines changed

5 files changed

+178
-4
lines changed

build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ project(":chat-formatter") {
5353

5454
dependencies {
5555
// Spigot API
56-
compileOnly("org.spigotmc:spigot-api:1.19.2-R0.1-SNAPSHOT")
56+
compileOnly("org.spigotmc:spigot-api:1.19.3-R0.1-SNAPSHOT")
5757

5858
// Kyori Adventure & MiniMessage
5959
implementation("net.kyori:adventure-platform-bukkit:4.2.0")
@@ -115,7 +115,7 @@ project(":paper-support") {
115115

116116
dependencies {
117117
compileOnly(project(":chat-formatter"))
118-
compileOnly("io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT")
118+
compileOnly("io.papermc.paper:paper-api:1.19.3-R0.1-SNAPSHOT")
119119
}
120120

121121
tasks.withType<ShadowJar> {

paper-support/src/com/eternalcode/formatter/paper/ChatPaperPreparatory.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package com.eternalcode.formatter.paper;
22

3+
import com.eternalcode.formatter.paper.adventure.PaperSignedMessage;
4+
import com.eternalcode.formatter.paper.injector.DependencyInjector;
35
import com.eternalcode.formatter.preparatory.ChatPreparatory;
46
import com.eternalcode.formatter.preparatory.ChatPrepareResult;
57
import io.papermc.paper.chat.ChatRenderer;
68
import io.papermc.paper.event.player.AsyncChatEvent;
79
import net.kyori.adventure.audience.Audience;
810
import net.kyori.adventure.audience.ForwardingAudience;
11+
import net.kyori.adventure.chat.SignedMessage;
12+
import net.kyori.adventure.identity.Identity;
913
import net.kyori.adventure.text.Component;
1014
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
1115
import org.bukkit.entity.Player;
@@ -16,7 +20,8 @@
1620

1721
class ChatPaperPreparatory implements ChatPreparatory {
1822

19-
private final static GsonComponentSerializer GSON = GsonComponentSerializer.gson();
23+
private static final GsonComponentSerializer GSON = GsonComponentSerializer.gson();
24+
2025
private final PluginManager pluginManager;
2126

2227
ChatPaperPreparatory(PluginManager pluginManager) {
@@ -28,7 +33,16 @@ public ChatPrepareResult prepare(Player player, Set<Player> receivers, String js
2833
ChatRenderer renderer = (source, sourceDisplayName, ignoredMessage, viewer) -> GSON.deserialize(jsonFormat);
2934
Component messageComponent = Component.text(message);
3035
HashSet<Audience> audiences = new HashSet<>(receivers);
31-
AsyncChatEvent event = new AsyncChatEvent(true, player, audiences, renderer, messageComponent, messageComponent);
36+
37+
DependencyInjector injector = new DependencyInjector()
38+
.register(boolean.class, true)
39+
.register(Player.class, player)
40+
.register(Set.class, audiences)
41+
.register(ChatRenderer.class, renderer)
42+
.register(Component.class, messageComponent)
43+
.register(SignedMessage.class, new PaperSignedMessage(messageComponent, Identity.identity(player.getUniqueId())));
44+
45+
AsyncChatEvent event = injector.newInstance(AsyncChatEvent.class);
3246

3347
event.setCancelled(canceled);
3448
this.pluginManager.callEvent(event);
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.eternalcode.formatter.paper.adventure;
2+
3+
import net.kyori.adventure.chat.SignedMessage;
4+
import net.kyori.adventure.identity.Identity;
5+
import net.kyori.adventure.text.Component;
6+
import org.jetbrains.annotations.NotNull;
7+
import org.jetbrains.annotations.Nullable;
8+
9+
import java.security.SecureRandom;
10+
import java.time.Instant;
11+
12+
public class PaperSignedMessage implements SignedMessage {
13+
14+
private static final SecureRandom RANDOM = new SecureRandom();
15+
16+
private final Instant instant;
17+
private final long salt;
18+
private final Component unsignedContent;
19+
private final String message;
20+
private final Identity identity;
21+
22+
public PaperSignedMessage(Component unsignedContent, Identity identity) {
23+
this.identity = identity;
24+
this.instant = Instant.now();
25+
this.salt = RANDOM.nextLong();
26+
this.unsignedContent = unsignedContent;
27+
this.message = "-";
28+
}
29+
30+
@Override
31+
public @NotNull Instant timestamp() {
32+
return this.instant;
33+
}
34+
35+
@Override
36+
public long salt() {
37+
return this.salt;
38+
}
39+
40+
@Override
41+
public Signature signature() {
42+
return null;
43+
}
44+
45+
@Override
46+
public @Nullable Component unsignedContent() {
47+
return this.unsignedContent;
48+
}
49+
50+
@Override
51+
public @NotNull String message() {
52+
return this.message;
53+
}
54+
55+
@Override
56+
public @NotNull Identity identity() {
57+
return identity;
58+
}
59+
60+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.eternalcode.formatter.paper.injector;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
class DependencyContainer<T> {
7+
8+
private final T value;
9+
private final List<T> extraValues = new ArrayList<>();
10+
11+
DependencyContainer(T value) {
12+
this.value = value;
13+
}
14+
15+
public void addExtraValue(T value) {
16+
this.extraValues.add(value);
17+
}
18+
19+
public T getExtraOrNormal(int index) {
20+
if (index == 0) {
21+
return this.value;
22+
}
23+
24+
if (index >= this.extraValues.size()) {
25+
if (this.extraValues.isEmpty()) {
26+
return this.value;
27+
}
28+
29+
return this.extraValues.get(this.extraValues.size() - 1);
30+
}
31+
32+
return this.extraValues.get(index);
33+
}
34+
35+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.eternalcode.formatter.paper.injector;
2+
3+
import java.lang.reflect.Constructor;
4+
import java.util.ArrayList;
5+
import java.util.HashMap;
6+
import java.util.List;
7+
import java.util.Map;
8+
9+
public class DependencyInjector {
10+
11+
private final Map<Class<?>, DependencyContainer<?>> dependencies = new HashMap<>();
12+
13+
@SuppressWarnings("unchecked")
14+
public <T> DependencyInjector register(Class<T> clazz, T instance) {
15+
DependencyContainer<T> container = (DependencyContainer<T>) this.dependencies.get(clazz);
16+
17+
if (container == null) {
18+
this.dependencies.put(clazz, new DependencyContainer<>(instance));
19+
return this;
20+
}
21+
22+
container.addExtraValue(instance);
23+
return this;
24+
}
25+
26+
public <T> T newInstance(Class<T> clazz) {
27+
for (Constructor<?> constructor : clazz.getConstructors()) {
28+
List<Object> parameters = new ArrayList<>();
29+
Map<Class<?>, Integer> parameterCount = new HashMap<>();
30+
31+
for (Class<?> parameterType : constructor.getParameterTypes()) {
32+
parameters.add(this.getDependency(parameterType, parameterCount.getOrDefault(parameterType, 0)));
33+
parameterCount.merge(parameterType, 1, Integer::sum);
34+
}
35+
36+
try {
37+
return clazz.cast(constructor.newInstance(parameters.toArray(new Object[0])));
38+
} catch (ReflectiveOperationException e) {
39+
throw new IllegalStateException("Failed to instantiate " + clazz, e);
40+
}
41+
}
42+
43+
throw new IllegalStateException("No constructor found for " + clazz);
44+
}
45+
46+
@SuppressWarnings("unchecked")
47+
private <T> T getDependency(Class<T> clazz, int index) {
48+
DependencyContainer<?> container = this.dependencies.get(clazz);
49+
50+
if (container != null) {
51+
return (T) container.getExtraOrNormal(index);
52+
}
53+
54+
for (Map.Entry<Class<?>, DependencyContainer<?>> entry : this.dependencies.entrySet()) {
55+
Class<?> key = entry.getKey();
56+
57+
if (clazz.isAssignableFrom(key)) {
58+
return (T) entry.getValue().getExtraOrNormal(index);
59+
}
60+
}
61+
62+
throw new IllegalStateException("No dependency found for " + clazz);
63+
}
64+
65+
}

0 commit comments

Comments
 (0)