Skip to content

Commit

Permalink
Make UHC modules toggleable mid-game
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugman76 committed Dec 5, 2024
1 parent 8fd8d9c commit 8a946e6
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 110 deletions.
4 changes: 2 additions & 2 deletions src/main/java/com/hugman/uhc/UHC.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.hugman.uhc;

import com.google.common.reflect.Reflection;
import com.hugman.uhc.command.ModulesCommand;
import com.hugman.uhc.command.UHCCommand;
import com.hugman.uhc.config.UHCGameConfig;
import com.hugman.uhc.game.phase.UHCWaiting;
import com.hugman.uhc.modifier.ModifierType;
Expand All @@ -25,7 +25,7 @@ public void onInitialize() {

UHCRegistryKeys.registerDynamics();

CommandRegistrationCallback.EVENT.register((dispatcher, dedicated, environment) -> ModulesCommand.register(dispatcher));
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> UHCCommand.register(dispatcher, registryAccess));
GameType.register(UHC.id("standard"), UHCGameConfig.CODEC, UHCWaiting::open);
}

Expand Down
85 changes: 0 additions & 85 deletions src/main/java/com/hugman/uhc/command/ModulesCommand.java

This file was deleted.

104 changes: 104 additions & 0 deletions src/main/java/com/hugman/uhc/command/UHCCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package com.hugman.uhc.command;

import com.hugman.uhc.command.argument.UHCModuleArgument;
import com.hugman.uhc.config.UHCGameConfig;
import com.hugman.uhc.game.UHCAttachments;
import com.hugman.uhc.module.Module;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.Text;
import xyz.nucleoid.plasmid.api.game.GameSpace;
import xyz.nucleoid.plasmid.api.game.GameSpaceManager;

import java.util.Objects;

public class UHCCommand {
private static final SimpleCommandExceptionType NO_MANAGER_ACTIVATED = new SimpleCommandExceptionType(Text.translatable("command.uhc.modules.no_manager"));
private static final SimpleCommandExceptionType NO_MODULES_ACTIVATED = new SimpleCommandExceptionType(Text.translatable("command.uhc.modules.no_modules_activated"));
private static final SimpleCommandExceptionType COULD_NOT_ACTIVATE_MODULE = new SimpleCommandExceptionType(Text.translatable("command.uhc.modules.enable.error"));

private static final String MODULE_ARG = "module";

public static void register(CommandDispatcher<ServerCommandSource> dispatcher, CommandRegistryAccess registryAccess) {
dispatcher.register(
CommandManager.literal("uhc")
.then(CommandManager.literal("create")
.requires(UHCCommand::isSourceNotInUHC)
.executes(context -> 0))
.then(CommandManager.literal("modules")
.requires(UHCCommand::isSourceInUHC) //TODO: check if there is a module manager
.executes(UHCCommand::displayModules)
.then(CommandManager.literal("enable")
.then(UHCModuleArgument.argument("module")
.executes(context -> enableModule(context, UHCModuleArgument.get(context, MODULE_ARG)))))
.then(CommandManager.literal("disable")
.then(UHCModuleArgument.argument("module") //TODO: only suggest enabled modules
.executes(context -> disableModule(context, UHCModuleArgument.get(context, MODULE_ARG))))))

);
}

public static boolean isSourceInUHC(ServerCommandSource source) {
GameSpace gameSpace = GameSpaceManager.get().byWorld(source.getWorld());
if (gameSpace != null) {
return gameSpace.getMetadata().sourceConfig().value().config() instanceof UHCGameConfig;
}
return false;
}

public static boolean isSourceNotInUHC(ServerCommandSource source) {
return !isSourceInUHC(source);
}

private static int displayModules(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
ServerCommandSource source = context.getSource();
var manager = Objects.requireNonNull(GameSpaceManager.get().byWorld(source.getWorld())).getAttachment(UHCAttachments.MODULE_MANAGER);
if (manager == null) {
throw NO_MANAGER_ACTIVATED.create();
}

if (!manager.isEmpty()) {
manager.buildGui(source.getPlayer()).open();
return Command.SINGLE_SUCCESS;
} else {
throw NO_MODULES_ACTIVATED.create();
}
}

private static int enableModule(CommandContext<ServerCommandSource> context, RegistryEntry<Module> module) throws CommandSyntaxException {
ServerCommandSource source = context.getSource();
var manager = Objects.requireNonNull(GameSpaceManager.get().byWorld(source.getWorld())).getAttachment(UHCAttachments.MODULE_MANAGER);
if (manager == null) {
throw NO_MANAGER_ACTIVATED.create();
}

if (manager.enableModule(module)) {
source.sendFeedback(() -> Text.translatable("command.uhc.modules.enable.success", module.value().name()), true);
return Command.SINGLE_SUCCESS;
} else {
throw COULD_NOT_ACTIVATE_MODULE.create();
}
}

private static int disableModule(CommandContext<ServerCommandSource> context, RegistryEntry<Module> module) throws CommandSyntaxException {
ServerCommandSource source = context.getSource();
var manager = Objects.requireNonNull(GameSpaceManager.get().byWorld(source.getWorld())).getAttachment(UHCAttachments.MODULE_MANAGER);
if (manager == null) {
throw NO_MANAGER_ACTIVATED.create();
}

if (manager.disableModule(module)) {
source.sendFeedback(() -> Text.translatable("command.uhc.modules.enable.success", module.value().name()), true);
return Command.SINGLE_SUCCESS;
} else {
throw COULD_NOT_ACTIVATE_MODULE.create();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.hugman.uhc.command.argument;

import com.hugman.uhc.module.Module;
import com.hugman.uhc.registry.UHCRegistryKeys;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import net.minecraft.command.CommandSource;
import net.minecraft.command.argument.IdentifierArgumentType;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;

import java.util.Locale;

public final class UHCModuleArgument {
private static final DynamicCommandExceptionType MODULE_NOT_FOUND = new DynamicCommandExceptionType((id) -> Text.stringifiedTranslatable("text.plasmid.game_config.game_not_found", id)); //TODO: change

public static RequiredArgumentBuilder<ServerCommandSource, Identifier> argument(String name) {
return CommandManager.argument(name, IdentifierArgumentType.identifier()).suggests((ctx, builder) -> {
Registry<Module> registry = ctx.getSource().getRegistryManager().getOrThrow(UHCRegistryKeys.MODULE);
String remaining = builder.getRemaining().toLowerCase(Locale.ROOT);
CommandSource.forEachMatching(registry.getKeys(), remaining, RegistryKey::getValue, (key) -> registry.getOptional(key)
.ifPresent((entry) -> builder.suggest(key.getValue().toString(), entry.value().name())));
return builder.buildFuture();
});
}

public static RegistryEntry.Reference<Module> get(CommandContext<ServerCommandSource> context, String name) throws CommandSyntaxException {
RegistryKey<Module> key = RegistryKey.of(UHCRegistryKeys.MODULE, IdentifierArgumentType.getIdentifier(context, name));
Registry<Module> registry = context.getSource().getRegistryManager().getOrThrow(UHCRegistryKeys.MODULE);
return registry.getOptional(key).orElseThrow(() -> MODULE_NOT_FOUND.create(key.getValue()));
}
}
112 changes: 107 additions & 5 deletions src/main/java/com/hugman/uhc/game/ModuleManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,37 @@
import com.hugman.uhc.modifier.Modifier;
import com.hugman.uhc.modifier.ModifierType;
import com.hugman.uhc.module.Module;
import eu.pb4.sgui.api.elements.GuiElementBuilder;
import eu.pb4.sgui.api.gui.SimpleGui;
import net.minecraft.registry.Registries;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.registry.entry.RegistryEntryList;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.*;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public final class ModuleManager {
private final List<RegistryEntry<Module>> modules;

public ModuleManager(List<RegistryEntry<Module>> modules) {
this.modules = new ArrayList<>(modules);
}

public ModuleManager(RegistryEntryList<Module> modules) {
this(modules.stream().toList());
}

public boolean isEmpty() {
return modules.isEmpty();
}

public record ModuleManager(
RegistryEntryList<Module> modules
) {
public List<Modifier> getModifiers() {
List<Modifier> modifiers = new ArrayList<>();
for (var moduleEntry : modules) {
Expand All @@ -21,10 +44,74 @@ public List<Modifier> getModifiers() {

public <V extends Modifier> List<V> getModifiers(ModifierType<V> type) {
//TODO: cache modules so it's quicker to sort by type
return filter(modules, type);
return ModuleManager.getModifiers(modules, type);
}

public boolean enableModule(RegistryEntry<Module> module) {
if (modules.contains(module)) {
return false;
}
//TODO: trigger the modifier (they may have something to do when enabled)
return modules.add(module);
}

public boolean disableModule(RegistryEntry<Module> module) {
if (!modules.contains(module)) {
return false;
}

//TODO: trigger the modifier (they may have something to do when disabled)
return modules.remove(module);
}

public static <V extends Modifier> List<V> filter(RegistryEntryList<Module> modules, ModifierType<V> type) {
/**
* Builds a GUI for the player to check the list of currently active modules
*
* @param player The player to build the GUI for
* @return The GUI
*/
public SimpleGui buildGui(ServerPlayerEntity player) {
ScreenHandlerType<?> type = Registries.SCREEN_HANDLER.get(Identifier.of("generic_9x" + MathHelper.clamp(1, MathHelper.ceil((float) modules.size() / 9), 6)));
SimpleGui gui = new SimpleGui(type, player, false);
gui.setTitle(Text.translatable("ui.uhc.modules.title"));
int i = 0;
for (var moduleEntry : modules) {
var module = moduleEntry.value();
GuiElementBuilder elementBuilder = new GuiElementBuilder(module.icon())
.setName(module.name().copy().formatted(Formatting.BOLD).setStyle(Style.EMPTY.withColor(module.color())))
.hideDefaultTooltip();
if (module.longDescription().isPresent()) {
for (Text line : module.longDescription().get()) {
elementBuilder.addLoreLine(Text.literal("- ").append(line).formatted(Formatting.GRAY));
}
} else if (module.description().isPresent()) {
elementBuilder.addLoreLine(Text.literal("- ").append(module.description().get()).formatted(Formatting.GRAY));
}
gui.setSlot(i++, elementBuilder);
}
return gui;
}

public MutableText buildChatMessage() {
var text = Text.literal("\n").append(Text.translatable("text.uhc.enabled_modules").formatted(Formatting.GOLD));
this.modules.forEach(moduleEntry -> {
var module = moduleEntry.value();
var style = Style.EMPTY;
if (module.description().isPresent()) {
style = style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, module.description().get().copy()));
}
text.append(Text.literal("\n - ").formatted(Formatting.WHITE)).append(Texts.bracketed(module.name()).setStyle(style.withColor(module.color())));
});
text.append("\n");
return text;
}

/**
* Filters a registry entry list of modules by type
*
* @return A list of modifiers of the specified type
*/
public static <V extends Modifier> List<V> getModifiers(List<RegistryEntry<Module>> modules, ModifierType<V> type) {
List<V> modifiers = new ArrayList<>();
for (var moduleEntry : modules) {
for (Modifier modifier : moduleEntry.value().modifiers()) {
Expand All @@ -35,4 +122,19 @@ public static <V extends Modifier> List<V> filter(RegistryEntryList<Module> modu
}
return modifiers;
}


public static <V extends Modifier> Stream<V> streamModifiers(Stream<RegistryEntry<Module>> modules, ModifierType<V> type) {
return modules
.map(RegistryEntry::value)
.flatMap(module -> module.modifiers().stream())
.filter(modifier -> modifier.getType() == type)
.map(modifier -> (V) modifier);
}

@Override
public String toString() {
return "ModuleManager[" +
"modules=" + modules + ']';
}
}
Loading

0 comments on commit 8a946e6

Please sign in to comment.