Skip to content

Commit

Permalink
GH-55 Support for multiple paper versions with dependency injector. (R…
Browse files Browse the repository at this point in the history
…esolve #54)
  • Loading branch information
Rollczi authored Dec 30, 2022
1 parent a1d6360 commit b94fa95
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 4 deletions.
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ project(":chat-formatter") {

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

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

dependencies {
compileOnly(project(":chat-formatter"))
compileOnly("io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.19.3-R0.1-SNAPSHOT")
}

tasks.withType<ShadowJar> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.eternalcode.formatter.paper;

import com.eternalcode.formatter.paper.adventure.PaperSignedMessage;
import com.eternalcode.formatter.paper.injector.DependencyInjector;
import com.eternalcode.formatter.preparatory.ChatPreparatory;
import com.eternalcode.formatter.preparatory.ChatPrepareResult;
import io.papermc.paper.chat.ChatRenderer;
import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.audience.ForwardingAudience;
import net.kyori.adventure.chat.SignedMessage;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import org.bukkit.entity.Player;
Expand All @@ -16,7 +20,8 @@

class ChatPaperPreparatory implements ChatPreparatory {

private final static GsonComponentSerializer GSON = GsonComponentSerializer.gson();
private static final GsonComponentSerializer GSON = GsonComponentSerializer.gson();

private final PluginManager pluginManager;

ChatPaperPreparatory(PluginManager pluginManager) {
Expand All @@ -28,7 +33,16 @@ public ChatPrepareResult prepare(Player player, Set<Player> receivers, String js
ChatRenderer renderer = (source, sourceDisplayName, ignoredMessage, viewer) -> GSON.deserialize(jsonFormat);
Component messageComponent = Component.text(message);
HashSet<Audience> audiences = new HashSet<>(receivers);
AsyncChatEvent event = new AsyncChatEvent(true, player, audiences, renderer, messageComponent, messageComponent);

DependencyInjector injector = new DependencyInjector()
.register(boolean.class, true)
.register(Player.class, player)
.register(Set.class, audiences)
.register(ChatRenderer.class, renderer)
.register(Component.class, messageComponent)
.register(SignedMessage.class, new PaperSignedMessage(messageComponent, Identity.identity(player.getUniqueId())));

AsyncChatEvent event = injector.newInstance(AsyncChatEvent.class);

event.setCancelled(canceled);
this.pluginManager.callEvent(event);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.eternalcode.formatter.paper.adventure;

import net.kyori.adventure.chat.SignedMessage;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.security.SecureRandom;
import java.time.Instant;

public class PaperSignedMessage implements SignedMessage {

private static final SecureRandom RANDOM = new SecureRandom();

private final Instant instant;
private final long salt;
private final Component unsignedContent;
private final String message;
private final Identity identity;

public PaperSignedMessage(Component unsignedContent, Identity identity) {
this.identity = identity;
this.instant = Instant.now();
this.salt = RANDOM.nextLong();
this.unsignedContent = unsignedContent;
this.message = "-";
}

@Override
public @NotNull Instant timestamp() {
return this.instant;
}

@Override
public long salt() {
return this.salt;
}

@Override
public Signature signature() {
return null;
}

@Override
public @Nullable Component unsignedContent() {
return this.unsignedContent;
}

@Override
public @NotNull String message() {
return this.message;
}

@Override
public @NotNull Identity identity() {
return identity;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.eternalcode.formatter.paper.injector;

import java.util.ArrayList;
import java.util.List;

class DependencyContainer<T> {

private final T value;
private final List<T> extraValues = new ArrayList<>();

DependencyContainer(T value) {
this.value = value;
}

public void addExtraValue(T value) {
this.extraValues.add(value);
}

public T getExtraOrNormal(int index) {
if (index == 0) {
return this.value;
}

if (index >= this.extraValues.size()) {
if (this.extraValues.isEmpty()) {
return this.value;
}

return this.extraValues.get(this.extraValues.size() - 1);
}

return this.extraValues.get(index);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.eternalcode.formatter.paper.injector;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DependencyInjector {

private final Map<Class<?>, DependencyContainer<?>> dependencies = new HashMap<>();

@SuppressWarnings("unchecked")
public <T> DependencyInjector register(Class<T> clazz, T instance) {
DependencyContainer<T> container = (DependencyContainer<T>) this.dependencies.get(clazz);

if (container == null) {
this.dependencies.put(clazz, new DependencyContainer<>(instance));
return this;
}

container.addExtraValue(instance);
return this;
}

public <T> T newInstance(Class<T> clazz) {
for (Constructor<?> constructor : clazz.getConstructors()) {
List<Object> parameters = new ArrayList<>();
Map<Class<?>, Integer> parameterCount = new HashMap<>();

for (Class<?> parameterType : constructor.getParameterTypes()) {
parameters.add(this.getDependency(parameterType, parameterCount.getOrDefault(parameterType, 0)));
parameterCount.merge(parameterType, 1, Integer::sum);
}

try {
return clazz.cast(constructor.newInstance(parameters.toArray(new Object[0])));
} catch (ReflectiveOperationException e) {
throw new IllegalStateException("Failed to instantiate " + clazz, e);
}
}

throw new IllegalStateException("No constructor found for " + clazz);
}

@SuppressWarnings("unchecked")
private <T> T getDependency(Class<T> clazz, int index) {
DependencyContainer<?> container = this.dependencies.get(clazz);

if (container != null) {
return (T) container.getExtraOrNormal(index);
}

for (Map.Entry<Class<?>, DependencyContainer<?>> entry : this.dependencies.entrySet()) {
Class<?> key = entry.getKey();

if (clazz.isAssignableFrom(key)) {
return (T) entry.getValue().getExtraOrNormal(index);
}
}

throw new IllegalStateException("No dependency found for " + clazz);
}

}

0 comments on commit b94fa95

Please sign in to comment.