Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Service abstraction upgrade #2

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,10 @@ dependencies {
implementation("ch.qos.logback:logback-classic:1.4.8")

// APIs
api("dev.emortal.api:module-system:16353c8")
api("dev.emortal.api:module-system:e69aa43")
api("dev.emortal.api:agones-sdk:1.0.7")
api("dev.emortal.api:common-proto-sdk:da7a48c")
api("dev.emortal.api:live-config-parser:a9fc46f")
api("dev.emortal.api:kurushimi-sdk:82c14c3")
api("dev.emortal.api:common-proto-sdk:4135280")
api("dev.emortal.api:live-config-parser:89c56a9")

api("io.kubernetes:client-java:18.0.0")

Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import dev.emortal.api.modules.Module;
import dev.emortal.api.modules.ModuleData;
import dev.emortal.api.modules.ModuleEnvironment;
import dev.emortal.api.modules.env.ModuleEnvironment;
import net.minestom.server.MinecraftServer;
import net.minestom.server.event.Event;
import net.minestom.server.event.EventNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import dev.emortal.api.message.messagehandler.ChatMessageCreatedMessage;
import dev.emortal.api.model.messagehandler.ChatMessage;
import dev.emortal.api.modules.ModuleData;
import dev.emortal.api.modules.ModuleEnvironment;
import dev.emortal.api.modules.env.ModuleEnvironment;
import dev.emortal.api.utils.kafka.FriendlyKafkaProducer;
import dev.emortal.minestom.core.module.MinestomModule;
import dev.emortal.minestom.core.module.messaging.MessagingModule;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package dev.emortal.minestom.core.module.core;

import dev.emortal.api.modules.ModuleData;
import dev.emortal.api.modules.ModuleEnvironment;
import dev.emortal.api.modules.env.ModuleEnvironment;
import dev.emortal.api.service.badges.BadgeService;
import dev.emortal.api.utils.GrpcStubCollection;
import dev.emortal.api.utils.resolvers.PlayerResolver;
import dev.emortal.minestom.core.module.MinestomModule;
import dev.emortal.minestom.core.module.core.badge.BadgeCommand;
import dev.emortal.minestom.core.module.core.performance.PerformanceCommand;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.CommandManager;
import net.minestom.server.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@ModuleData(name = "core", required = false)
public final class CoreModule extends MinestomModule {
private static final Logger LOGGER = LoggerFactory.getLogger(CoreModule.class);

public CoreModule(@NotNull ModuleEnvironment environment) {
super(environment);
Expand All @@ -26,9 +32,15 @@ public boolean onLoad() {
return new PlayerResolver.CachedMcPlayer(player.getUuid(), player.getUsername(), player.isOnline());
});

var commandManager = MinecraftServer.getCommandManager();
CommandManager commandManager = MinecraftServer.getCommandManager();
commandManager.register(new PerformanceCommand(this.eventNode));
commandManager.register(new BadgeCommand());

BadgeService badgeService = GrpcStubCollection.getBadgeManagerService().orElse(null);
if (badgeService != null) {
commandManager.register(new BadgeCommand(badgeService));
} else {
LOGGER.warn("Badge service unavailable. Badges will not work.");
}

return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package dev.emortal.minestom.core.module.core.badge;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.rpc.Status;
import dev.emortal.api.grpc.badge.BadgeManagerGrpc;
import dev.emortal.api.grpc.badge.BadgeManagerProto;
import dev.emortal.api.grpc.mcplayer.McPlayerProto;
import dev.emortal.api.model.mcplayer.McPlayer;
import dev.emortal.api.utils.GrpcStubCollection;
import dev.emortal.minestom.core.utils.command.ExtraConditions;
import dev.emortal.api.service.badges.AddBadgeToPlayerResult;
import dev.emortal.api.service.badges.BadgeService;
import dev.emortal.api.service.badges.RemoveBadgeFromPlayerResult;
import dev.emortal.api.service.mcplayer.McPlayerService;
import dev.emortal.minestom.core.utils.command.argument.ArgumentBadge;
import dev.emortal.minestom.core.utils.command.argument.ArgumentMcPlayer;
import io.grpc.protobuf.StatusProto;
import io.grpc.StatusRuntimeException;
import net.kyori.adventure.text.Component;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.Command;
Expand All @@ -22,123 +18,69 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ForkJoinPool;
import java.util.UUID;
import java.util.function.Supplier;

public final class BadgeAdminSubcommand extends Command {
final class BadgeAdminSubcommand extends Command {
private static final Logger LOGGER = LoggerFactory.getLogger(BadgeAdminSubcommand.class);

private final BadgeManagerGrpc.BadgeManagerFutureStub badgeManager;
private final BadgeService badgeService;

public BadgeAdminSubcommand(@NotNull BadgeManagerGrpc.BadgeManagerFutureStub badgeManager) {
BadgeAdminSubcommand(@NotNull BadgeService badgeService, @NotNull McPlayerService mcPlayerService) {
super("admin");
this.badgeManager = badgeManager;
this.badgeService = badgeService;

this.setCondition(ExtraConditions.hasPermission("command.badge.admin"));
this.setCondition((sender, $) -> sender.hasPermission("command.badge.admin"));

var addArgument = new ArgumentLiteral("add");
var removeArgument = new ArgumentLiteral("remove");
var playerArgument = ArgumentMcPlayer.create("player",
GrpcStubCollection.getPlayerService().orElse(null),
McPlayerProto.SearchPlayersByUsernameRequest.FilterMethod.NONE
);
var badgeArgument = ArgumentBadge.create(badgeManager, "badge", false);
var playerArgument = ArgumentMcPlayer.create("player", mcPlayerService, McPlayerProto.SearchPlayersByUsernameRequest.FilterMethod.NONE);
var badgeArgument = ArgumentBadge.create(badgeService, "badge", false);

this.addSyntax(this::executeAddBadgeToPlayer, addArgument, playerArgument, badgeArgument);
this.addSyntax(this::executeRemoveBadgeFromPlayer, removeArgument, playerArgument, badgeArgument);
}

private void executeAddBadgeToPlayer(CommandSender sender, CommandContext context) {
CompletableFuture<McPlayer> playerFuture = context.get("player");
private void executeAddBadgeToPlayer(@NotNull CommandSender sender, @NotNull CommandContext context) {
McPlayer player = getPlayer(context);
String badgeId = context.get("badge");

playerFuture.thenAccept(mcPlayer -> {
var request = BadgeManagerProto.AddBadgeToPlayerRequest.newBuilder()
.setBadgeId(badgeId)
.setPlayerId(mcPlayer.getId())
.build();

Futures.addCallback(this.badgeManager.addBadgeToPlayer(request), new AddBadgeToPlayerCallback(sender), ForkJoinPool.commonPool());
});
}

private record AddBadgeToPlayerCallback(@NotNull CommandSender sender) implements FutureCallback<BadgeManagerProto.AddBadgeToPlayerResponse> {

@Override
public void onSuccess(@NotNull BadgeManagerProto.AddBadgeToPlayerResponse result) {
this.sender.sendMessage(Component.text("Added badge to player"));
AddBadgeToPlayerResult result;
try {
result = this.badgeService.addBadgeToPlayer(UUID.fromString(player.getId()), badgeId);
} catch (StatusRuntimeException exception) {
LOGGER.error("Failed to add badge to player", exception);
sender.sendMessage(Component.text("Failed to add badge to player"));
return;
}

@Override
public void onFailure(@NotNull Throwable throwable) {
Status status = StatusProto.fromThrowable(throwable);
if (status == null || status.getDetailsCount() == 0) {
LOGGER.error("Failed to add badge to player", throwable);
return;
}

final BadgeManagerProto.AddBadgeToPlayerErrorResponse response;
try {
response = status.getDetails(0).unpack(BadgeManagerProto.AddBadgeToPlayerErrorResponse.class);
} catch (InvalidProtocolBufferException exception) {
LOGGER.error("Failed to add badge to player", exception);
return;
}

switch (response.getReason()) {
case PLAYER_ALREADY_HAS_BADGE -> this.sender.sendMessage(Component.text("Player already has that badge"));
default -> {
LOGGER.error("Failed to add badge to player", throwable);
this.sender.sendMessage(Component.text("Failed to add badge to player"));
}
}
switch (result) {
case SUCCESS -> sender.sendMessage(Component.text("Added badge to player"));
case PLAYER_ALREADY_HAS_BADGE -> sender.sendMessage(Component.text("Player already has that badge"));
}
}

private void executeRemoveBadgeFromPlayer(CommandSender sender, CommandContext context) {
CompletableFuture<McPlayer> playerFuture = context.get("player");
private void executeRemoveBadgeFromPlayer(@NotNull CommandSender sender, @NotNull CommandContext context) {
McPlayer player = getPlayer(context);
String badgeId = context.get("badge");

playerFuture.thenAccept(mcPlayer -> {
var request = BadgeManagerProto.RemoveBadgeFromPlayerRequest.newBuilder()
.setBadgeId(badgeId)
.setPlayerId(mcPlayer.getId())
.build();

Futures.addCallback(this.badgeManager.removeBadgeFromPlayer(request), new RemoveBadgeFromPlayerCallback(sender), ForkJoinPool.commonPool());
});
}

private record RemoveBadgeFromPlayerCallback(@NotNull CommandSender sender) implements FutureCallback<BadgeManagerProto.RemoveBadgeFromPlayerResponse> {

@Override
public void onSuccess(@NotNull BadgeManagerProto.RemoveBadgeFromPlayerResponse result) {
this.sender.sendMessage(Component.text("Removed badge from player"));
RemoveBadgeFromPlayerResult result;
try {
result = this.badgeService.removeBadgeFromPlayer(UUID.fromString(player.getId()), badgeId);
} catch (StatusRuntimeException exception) {
LOGGER.error("Failed to remove badge from player", exception);
sender.sendMessage(Component.text("Failed to remove badge from player"));
return;
}

@Override
public void onFailure(@NotNull Throwable throwable) {
Status status = StatusProto.fromThrowable(throwable);
if (status == null || status.getDetailsCount() == 0) {
LOGGER.error("Failed to remove badge from player", throwable);
return;
}

final BadgeManagerProto.RemoveBadgeFromPlayerErrorResponse response;
try {
response = status.getDetails(0).unpack(BadgeManagerProto.RemoveBadgeFromPlayerErrorResponse.class);
} catch (InvalidProtocolBufferException exception) {
LOGGER.error("Failed to remove badge from player", exception);
return;
}

switch (response.getReason()) {
case PLAYER_DOESNT_HAVE_BADGE -> this.sender.sendMessage(Component.text("Player doesn't have that badge"));
default -> {
LOGGER.error("Failed to remove badge from player", throwable);
this.sender.sendMessage(Component.text("Failed to remove badge from player"));
}
}
switch (result) {
case SUCCESS -> sender.sendMessage(Component.text("Removed badge from player"));
case PLAYER_DOESNT_HAVE_BADGE -> sender.sendMessage(Component.text("Player doesn't have that badge"));
}
}

private static @NotNull McPlayer getPlayer(@NotNull CommandContext context) {
Supplier<McPlayer> supplier = context.get("player");
return supplier.get();
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
package dev.emortal.minestom.core.module.core.badge;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.rpc.Status;
import dev.emortal.api.grpc.badge.BadgeManagerGrpc;
import dev.emortal.api.grpc.badge.BadgeManagerProto;
import dev.emortal.api.service.badges.BadgeService;
import dev.emortal.api.service.badges.SetActiveBadgeResult;
import dev.emortal.api.service.mcplayer.McPlayerService;
import dev.emortal.api.utils.GrpcStubCollection;
import dev.emortal.minestom.core.utils.command.argument.ArgumentBadge;
import io.grpc.protobuf.StatusProto;
import io.grpc.StatusRuntimeException;
import net.kyori.adventure.text.Component;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.Command;
Expand All @@ -20,69 +17,46 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ForkJoinPool;

public final class BadgeCommand extends Command {
private static final Logger LOGGER = LoggerFactory.getLogger(BadgeCommand.class);

private final BadgeManagerGrpc.BadgeManagerFutureStub badgeManager = GrpcStubCollection.getBadgeManagerService().orElse(null);
private final BadgeService badgeService;

public BadgeCommand() {
public BadgeCommand(@NotNull BadgeService badgeService) {
super("badge");
this.badgeService = badgeService;

this.setCondition(Conditions::playerOnly);
this.setDefaultExecutor((sender, context) -> new BadgeGui((Player) sender));
this.setDefaultExecutor((sender, context) -> new BadgeGui((Player) sender, badgeService));

var setArgument = new ArgumentLiteral("set");
var badgeArgument = ArgumentBadge.create(this.badgeManager, "badge", true);

var badgeArgument = ArgumentBadge.create(this.badgeService, "badge", true);
this.addConditionalSyntax(Conditions::playerOnly, this::executeSetCurrentBadge, setArgument, badgeArgument);
this.addSubcommand(new BadgeAdminSubcommand(this.badgeManager));

McPlayerService mcPlayerService = GrpcStubCollection.getPlayerService().orElse(null);
if (mcPlayerService != null) {
this.addSubcommand(new BadgeAdminSubcommand(this.badgeService, mcPlayerService));
} else {
LOGGER.warn("MC player service unavailable. Badge admin command will not be registered.");
}
}

private void executeSetCurrentBadge(CommandSender sender, CommandContext context) {
String badgeId = context.get("badge");
Player player = (Player) sender;

var request = BadgeManagerProto.SetActivePlayerBadgeRequest.newBuilder()
.setBadgeId(badgeId)
.setPlayerId(player.getUuid().toString())
.build();

Futures.addCallback(this.badgeManager.setActivePlayerBadge(request), new SetCurrentBadgeCallback(sender, badgeId), ForkJoinPool.commonPool());
}

private record SetCurrentBadgeCallback(@NotNull CommandSender sender,
@NotNull String badgeId) implements FutureCallback<BadgeManagerProto.SetActivePlayerBadgeResponse> {

@Override
public void onSuccess(@NotNull BadgeManagerProto.SetActivePlayerBadgeResponse result) {
this.sender.sendMessage(Component.text("Set your badge to " + this.badgeId));
SetActiveBadgeResult result;
try {
result = this.badgeService.setActiveBadge(player.getUuid(), badgeId);
} catch (StatusRuntimeException exception) {
LOGGER.error("Failed to set badge", exception);
sender.sendMessage(Component.text("Failed to set badge"));
return;
}

@Override
public void onFailure(@NotNull Throwable throwable) {
Status status = StatusProto.fromThrowable(throwable);
if (status == null || status.getDetailsCount() == 0) {
LOGGER.error("Failed to set badge", throwable);
return;
}

final BadgeManagerProto.SetActivePlayerBadgeErrorResponse response;
try {
response = status.getDetails(0).unpack(BadgeManagerProto.SetActivePlayerBadgeErrorResponse.class);
} catch (InvalidProtocolBufferException exception) {
LOGGER.error("Failed to set badge", throwable);
return;
}

switch (response.getReason()) {
case PLAYER_DOESNT_HAVE_BADGE -> this.sender.sendMessage(Component.text("You don't have that badge"));
default -> {
LOGGER.error("Failed to set badge", throwable);
this.sender.sendMessage(Component.text("Failed to set badge"));
}
}
switch (result) {
case SUCCESS -> sender.sendMessage(Component.text("Set your badge to " + badgeId));
case PLAYER_DOESNT_HAVE_BADGE -> sender.sendMessage(Component.text("You don't have that badge"));
}
}
}
Loading