Skip to content

Commit

Permalink
Update to 3.0.0 (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugman76 authored Dec 14, 2024
2 parents ef12558 + 751a2da commit 73c3b44
Show file tree
Hide file tree
Showing 147 changed files with 3,052 additions and 970 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,5 @@ run/

# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar

/src/main/resources/data/*/plasmid/game/test.json
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# 🍏 UHC

UHC (abbreviation for Ultra HardCore) is a popular Minecraft survival minigame that can be played alone or with a team.
This mod also includes UHCRun, a variant of UHC that tweaks the game in many ways to make it 2x faster.
This mod includes:
* **UHC**, the classic UHC experience.
* **UHCRun**, a variant that tweaks the game in many ways to make it 2x faster.
* **DoubleRunner**, a variant that makes it even faster than UHCRun.

UHC is one of the minigames made for the [Nucleoid Project](https://nucleoid.xyz/), an effort to build an open source ecosystem for server-side Minecraft minigames.
You may even be interested in playing some of them over on our testing Minecraft server at `nucleoid.xyz`!
Expand All @@ -13,7 +16,7 @@ UHC can be installed on a client or a server. As this is a multiplayer minigame

⚠ UHC **needs** the following mods to be installed:
- Plasmid: [GitHub](https://github.com/NucleoidMC/plasmid) / [Modrinth](https://modrinth.com/mod/plasmid)
- Fabric API: [GitHub](https://github.com/FabricMC/fabric) / [CurseForge](https://www.curseforge.com/minecraft/mc-mods/fabric-api) / [Modrinth](https://modrinth.com/mod/fabric-api)
- Fabric API: [GitHub](https://github.com/FabricMC/fabric) / [Modrinth](https://modrinth.com/mod/fabric-api) / [CurseForge](https://www.curseforge.com/minecraft/mc-mods/fabric-api)

## Usage

Expand All @@ -26,6 +29,7 @@ To configure UHC, or to contribute to the project, visit [the official documenta
## Credits

- [Hugman](https://github.com/Hugman76) - Development
- [Samagames](https://www.samagames.net/) - Original concept of UHCRun & DoubleRunner

### 🌐 Translations
| Language | Translators |
Expand Down
10 changes: 5 additions & 5 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
org.gradle.jvmargs=-Xmx1G

# Mod Properties
mod_version=2.4.0
mod_version=3.0.0
maven_group=com.hugman
archives_base_name=uhc

# Fabric Properties
# check these on https://fabricmc.net/develop/
minecraft_version=1.21.3
yarn_mappings=1.21.3+build.2
minecraft_version=1.21.4
yarn_mappings=1.21.4+build.1
loader_version=0.16.9
fabric_version=0.108.0+1.21.3
fabric_version=0.111.0+1.21.4

# check this on https://nucleoid.xyz/use/
plasmid_version=0.6.0-SNAPSHOT+1.21.3
plasmid_version=0.6.3-SNAPSHOT+1.21.4
109 changes: 109 additions & 0 deletions src/main/java/com/hugman/text/Messenger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.hugman.text;

import com.hugman.uhc.game.ModuleManager;
import com.hugman.uhc.module.Module;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.HoverEvent;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.text.Texts;
import net.minecraft.util.Formatting;
import xyz.nucleoid.plasmid.api.game.GameSpacePlayers;

/**
* Sends messages to players in a game.
*/
public class Messenger {
public static final String SYMBOL_SKULL = "☠";
public static final String SYMBOL_MODULE = "✨";
public static final String SYMBOL_SHIELD = "🛡";
public static final String SYMBOL_SWORD = "🗡";

private final GameSpacePlayers players;

public Messenger(GameSpacePlayers players) {
this.players = players;
}

public void sound(SoundEvent sound, float volume, float pitch) {
players.playSound(sound, SoundCategory.PLAYERS, volume, pitch);
}

public void info(String symbol, String s, Object... args) {
players.sendMessage(build(symbol, s, Formatting.YELLOW, args));
}

public void info(String s, Object... args) {
players.sendMessage(build(s, Formatting.YELLOW, args));
}

public void danger(String symbol, String s, Object... args) {
players.sendMessage(build(symbol, s, Formatting.RED, args));
}

public void danger(String s, Object... args) {
players.sendMessage(build(s, Formatting.RED, args));
}

public void elimination(ServerPlayerEntity player) {
players.sendMessage(buildElimination(player));
players.playSound(SoundEvents.ENTITY_WITHER_SPAWN);
}

public void death(DamageSource source, ServerPlayerEntity player) {
players.sendMessage(buildDeath(source, player));
players.playSound(SoundEvents.ENTITY_WITHER_SPAWN);
}

public void moduleAnnouncement(String message, RegistryEntry<Module> module, Formatting formatting) {
players.sendMessage(buildModuleAnnouncement(message, module, formatting));
}

public void moduleList(ModuleManager moduleManager) {
if (!moduleManager.isEmpty()) {
players.sendMessage(buildModuleList(moduleManager));
players.playSound(SoundEvents.ENTITY_ITEM_PICKUP);
}
}

private static Text build(String symbol, String s, Formatting f, Object... args) {
return Text.literal(symbol).append(" ").append(Text.translatable(s, args)).formatted(f);
}

private static Text build(String s, Formatting f, Object... args) {
return Text.translatable(s, args).formatted(f);
}

private static Text buildDeath(DamageSource source, ServerPlayerEntity player) {
return Text.literal("\n").append(SYMBOL_SKULL).append(" ").append(source.getDeathMessage(player).copy()).append("!\n").formatted(Formatting.DARK_RED);
}

private static Text buildElimination(ServerPlayerEntity player) {
return Text.literal("\n").append(SYMBOL_SKULL).append(" ").append(Text.translatable("text.uhc.player_eliminated", player.getDisplayName())).append("\n").formatted(Formatting.DARK_RED);
}

private static Text buildModuleAnnouncement(String message, RegistryEntry<Module> module, Formatting formatting) {
return Text.literal("\n\n").append(SYMBOL_MODULE).append(" ").append(Text.translatable(message, moduleSnippet(module.value())).formatted(formatting)).append("\n\n");
}

private static Text buildModuleList(ModuleManager manager) {
var text = Text.literal("\n").append(Text.translatable("text.uhc.enabled_modules").formatted(Formatting.GOLD));
manager.forEach(module -> text.append(Text.literal("\n - ").formatted(Formatting.WHITE)).append(moduleSnippet(module)));
text.append("\n");
return text;
}


private static Text moduleSnippet(Module module) {
var style = Style.EMPTY;
if (module.description().isPresent()) {
style = style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, module.description().get().copy()));
}
return Texts.bracketed(module.name()).setStyle(style.withColor(module.color()));
}
}
6 changes: 3 additions & 3 deletions src/main/java/com/hugman/uhc/UHC.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

UHCRegistryKeys.registerDynamics();

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

public static Identifier id(String path) {
Expand Down
110 changes: 76 additions & 34 deletions src/main/java/com/hugman/uhc/command/ModulesCommand.java
Original file line number Diff line number Diff line change
@@ -1,69 +1,111 @@
package com.hugman.uhc.command;

import com.hugman.uhc.config.UHCConfig;
import com.hugman.uhc.command.argument.UHCModuleArgument;
import com.hugman.uhc.game.ModuleManager;
import com.hugman.uhc.module.Module;
import com.hugman.uhc.module.ModuleEvents;
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 eu.pb4.sgui.api.elements.GuiElementBuilder;
import eu.pb4.sgui.api.gui.SimpleGui;
import net.minecraft.registry.Registries;
import net.minecraft.registry.entry.RegistryEntryList;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import xyz.nucleoid.plasmid.api.game.GameSpace;
import xyz.nucleoid.plasmid.api.game.GameSpaceManager;
import xyz.nucleoid.stimuli.EventInvokers;
import xyz.nucleoid.stimuli.Stimuli;

import java.util.Objects;

public class ModulesCommand {
public static final SimpleCommandExceptionType NO_MODULES_ACTIVATED = new SimpleCommandExceptionType(Text.translatable("command.uhc.modules.no_modules_activated"));
private static final SimpleCommandExceptionType NO_MANAGER_ACTIVATED = new SimpleCommandExceptionType(Text.translatable("command.modules.no_manager"));
private static final SimpleCommandExceptionType NO_MODULES_ACTIVATED = new SimpleCommandExceptionType(Text.translatable("command.modules.no_modules_activated"));
private static final SimpleCommandExceptionType ALREADY_ENABLED = new SimpleCommandExceptionType(Text.translatable("command.modules.already_enabled"));
private static final SimpleCommandExceptionType ALREADY_DISABLED = new SimpleCommandExceptionType(Text.translatable("command.modules.already_disabled"));

private static final String MODULE_ARG = "module";

public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(
CommandManager.literal("modules")
.requires(ModulesCommand::isSourceInUHC)
.executes(ModulesCommand::displayModules));
.requires(ModulesCommand::supportsModules)
.executes(ModulesCommand::displayModules)
.then(CommandManager.literal("enable")
.requires(source -> source.hasPermissionLevel(2))
.then(UHCModuleArgument.argumentFromDisabled("module")
.executes(context -> enableModule(context, UHCModuleArgument.get(context, MODULE_ARG)))))
.then(CommandManager.literal("disable")
.requires(source -> source.hasPermissionLevel(2))
.then(UHCModuleArgument.argumentFromEnabled("module")
.executes(context -> disableModule(context, UHCModuleArgument.get(context, MODULE_ARG)))))
);
}

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

private static int displayModules(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
ServerCommandSource source = context.getSource();
RegistryEntryList<Module> moduleEntries = ((UHCConfig) Objects.requireNonNull(GameSpaceManager.get().byWorld(source.getWorld())).getMetadata().sourceConfig().value().config()).modules();
if (moduleEntries.size() != 0) {
ScreenHandlerType<?> type = Registries.SCREEN_HANDLER.get(Identifier.of("generic_9x" + MathHelper.clamp(1, MathHelper.ceil((float) moduleEntries.size() / 9), 6)));
SimpleGui gui = new SimpleGui(type, source.getPlayer(), false);
gui.setTitle(Text.translatable("ui.uhc.modules.title"));
int i = 0;
for (var moduleEntry : moduleEntries) {
var module = moduleEntry.value();
GuiElementBuilder elementBuilder = new GuiElementBuilder(module.icon())
.setName(Text.translatable(module.translation()).formatted(Formatting.BOLD).setStyle(Style.EMPTY.withColor(module.color())))
.hideDefaultTooltip();
for (String s : module.getDescriptionLines()) {
elementBuilder.addLoreLine(Text.literal("- ").append(Text.translatable(s)).formatted(Formatting.GRAY));
}
gui.setSlot(i++, elementBuilder);
}
gui.open();
var manager = Objects.requireNonNull(GameSpaceManager.get().byPlayer(source.getPlayer())).getAttachment(ModuleManager.ATTACHMENT);
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 space = Objects.requireNonNull(GameSpaceManager.get().byWorld(source.getWorld()));
var manager = space.getAttachment(ModuleManager.ATTACHMENT);
if (manager == null) {
throw NO_MANAGER_ACTIVATED.create();
}

if (manager.enableModule(module)) {
try (EventInvokers invokers = Stimuli.select().forCommandSource(context.getSource())) {
(invokers.get(ModuleEvents.ENABLE)).onEnable(module);
}

source.sendFeedback(() -> Text.translatable("command.modules.enable.success", module.value().name()), true);
return Command.SINGLE_SUCCESS;
} else {
throw ALREADY_ENABLED.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(ModuleManager.ATTACHMENT);
if (manager == null) {
throw NO_MANAGER_ACTIVATED.create();
}

if (manager.disableModule(module)) {
try (EventInvokers invokers = Stimuli.select().forCommandSource(context.getSource())) {
(invokers.get(ModuleEvents.DISABLE)).onDisable(module);
}

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

import com.hugman.uhc.game.ModuleManager;
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 xyz.nucleoid.plasmid.api.game.GameSpaceManager;

import java.util.ArrayList;
import java.util.Locale;
import java.util.Objects;

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

public static RequiredArgumentBuilder<ServerCommandSource, Identifier> argumentFromEnabled(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);
var manager = Objects.requireNonNull(GameSpaceManager.get().byWorld(ctx.getSource().getWorld())).getAttachment(ModuleManager.ATTACHMENT);
if (manager == null) {
return builder.buildFuture();
}
var enabledKeys = manager.keys();
CommandSource.forEachMatching(enabledKeys, remaining, RegistryKey::getValue, (key) -> registry.getOptional(key)
.ifPresent((entry) -> builder.suggest(key.getValue().toString(), entry.value().name())));
return builder.buildFuture();
});
}

public static RequiredArgumentBuilder<ServerCommandSource, Identifier> argumentFromDisabled(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);
var manager = Objects.requireNonNull(GameSpaceManager.get().byWorld(ctx.getSource().getWorld())).getAttachment(ModuleManager.ATTACHMENT);
var candidates = new ArrayList<>(registry.getKeys());
if (manager != null) {
candidates.removeAll(manager.keys());
}
CommandSource.forEachMatching(candidates, 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()));
}
}
Loading

0 comments on commit 73c3b44

Please sign in to comment.