From 5069f43551890cd9431a373bc16113e5f69f9eb6 Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Tue, 22 Sep 2026 20:03:40 +1000 Subject: [PATCH 1/4] Machine lib now has a way for other mods to expose their team systems for machine lib to use. Vanilla minecraft teams is the default however if a mod has a better team system and wishes to use it with machine lib they can now register their team system with machine lib and then machine libs config allows using that specific team system. --- build.gradle.kts | 1 + .../machinelib/api/config/Config.java | 12 ++ .../configuration/SecuritySettings.java | 5 +- .../api/machine/security/TeamSystem.java | 51 ++++++ .../api/machine/security/TeamSystems.java | 149 ++++++++++++++++++ .../client/impl/compat/ClothConfigScreen.java | 6 + .../machinelib/impl/MachineLib.java | 10 ++ .../impl/command/MachineLibCommands.java | 109 +++++++++++++ .../impl/config/MachineLibConfig.java | 20 +++ .../machine/security/VanillaTeamSystem.java | 68 ++++++++ .../assets/machinelib/lang/en_us.json | 4 +- 11 files changed, 433 insertions(+), 2 deletions(-) create mode 100644 src/main/java/dev/galacticraft/machinelib/api/machine/security/TeamSystem.java create mode 100644 src/main/java/dev/galacticraft/machinelib/api/machine/security/TeamSystems.java create mode 100644 src/main/java/dev/galacticraft/machinelib/impl/command/MachineLibCommands.java create mode 100644 src/main/java/dev/galacticraft/machinelib/impl/machine/security/VanillaTeamSystem.java diff --git a/build.gradle.kts b/build.gradle.kts index b7e6e49a..f728c4b5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -187,6 +187,7 @@ dependencies { listOf( "fabric-api-base", + "fabric-command-api-v2", "fabric-api-lookup-api-v1", "fabric-data-attachment-api-v1", "fabric-gametest-api-v1", diff --git a/src/main/java/dev/galacticraft/machinelib/api/config/Config.java b/src/main/java/dev/galacticraft/machinelib/api/config/Config.java index c0be9961..c43fccaa 100644 --- a/src/main/java/dev/galacticraft/machinelib/api/config/Config.java +++ b/src/main/java/dev/galacticraft/machinelib/api/config/Config.java @@ -72,6 +72,18 @@ static Config loadFrom(File file) { */ void getFluidUnits(FluidUnits units); + /** + * {@return the id of the team system used by MachineLib security} + */ + String teamSystem(); + + /** + * Sets the team system used by MachineLib security. + * + * @param teamSystem the registered team system id + */ + void setTeamSystem(String teamSystem); + /** * Copies the state of the provided config into this config. * diff --git a/src/main/java/dev/galacticraft/machinelib/api/machine/configuration/SecuritySettings.java b/src/main/java/dev/galacticraft/machinelib/api/machine/configuration/SecuritySettings.java index be6c4efd..c312dcc6 100644 --- a/src/main/java/dev/galacticraft/machinelib/api/machine/configuration/SecuritySettings.java +++ b/src/main/java/dev/galacticraft/machinelib/api/machine/configuration/SecuritySettings.java @@ -22,6 +22,7 @@ package dev.galacticraft.machinelib.api.machine.configuration; +import dev.galacticraft.machinelib.api.machine.security.TeamSystems; import dev.galacticraft.machinelib.api.misc.DeltaPacketSerializable; import dev.galacticraft.machinelib.api.misc.PacketSerializable; import dev.galacticraft.machinelib.api.misc.Serializable; @@ -134,7 +135,9 @@ public boolean hasAccess( return switch (accessLevel) { case PUBLIC -> true; - case TEAM -> this.isOwner(player); // todo: teams + case TEAM -> this.isOwner(player) + || this.owner != null + && TeamSystems.areTeammates(this.owner, player); case PRIVATE -> this.isOwner(player); }; diff --git a/src/main/java/dev/galacticraft/machinelib/api/machine/security/TeamSystem.java b/src/main/java/dev/galacticraft/machinelib/api/machine/security/TeamSystem.java new file mode 100644 index 00000000..8aaeba0a --- /dev/null +++ b/src/main/java/dev/galacticraft/machinelib/api/machine/security/TeamSystem.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021-2026 Team Galacticraft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package dev.galacticraft.machinelib.api.machine.security; + +import net.minecraft.world.entity.player.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Provides team membership information for MachineLib security checks. + * + *

Implementations are registered through {@link TeamSystems}. MachineLib + * selects one registered implementation using its {@code teamSystem} config + * option.

+ */ +@FunctionalInterface +public interface TeamSystem { + /** + * Determines whether the supplied player is considered a teammate of the + * machine owner. + * + *

The owner check itself is performed by MachineLib before this method is + * called. Implementations therefore only need to determine team membership.

+ * + * @param owner the UUID of the machine owner + * @param player the player attempting to access the machine + * @return whether the player is a teammate of the owner + */ + boolean areTeammates(@NotNull UUID owner, @NotNull Player player); +} \ No newline at end of file diff --git a/src/main/java/dev/galacticraft/machinelib/api/machine/security/TeamSystems.java b/src/main/java/dev/galacticraft/machinelib/api/machine/security/TeamSystems.java new file mode 100644 index 00000000..3b479ec0 --- /dev/null +++ b/src/main/java/dev/galacticraft/machinelib/api/machine/security/TeamSystems.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2021-2026 Team Galacticraft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package dev.galacticraft.machinelib.api.machine.security; + +import dev.galacticraft.machinelib.impl.MachineLib; +import net.minecraft.world.entity.player.Player; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.regex.Pattern; + +/** + * Registry for team systems exposed to MachineLib. + * + *

A mod may register its team implementation during initialization and a + * modpack may then select it using MachineLib's {@code teamSystem} config + * option.

+ */ +public final class TeamSystems { + /** + * The identifier of MachineLib's built-in vanilla team implementation. + */ + public static final String MINECRAFT = "minecraft"; + + private static final Pattern VALID_ID = Pattern.compile("[a-z0-9_.-]+"); + private static final Map SYSTEMS = new LinkedHashMap<>(); + + private TeamSystems() {} + + /** + * Registers a team system. + * + *

It is recommended that mods use their mod id as the team system id.

+ * + * @param id the unique team system id + * @param system the team system implementation + * @throws IllegalArgumentException if the id is invalid or already registered + */ + public static void register(@NotNull String id, @NotNull TeamSystem system) { + if (!VALID_ID.matcher(id).matches()) { + throw new IllegalArgumentException("Invalid team system id: " + id); + } + + if (SYSTEMS.putIfAbsent(id, system) != null) { + throw new IllegalArgumentException("Team system already registered: " + id); + } + } + + /** + * {@return whether a team system with the supplied id is registered} + * + * @param id the team system id + */ + @Contract(pure = true) + public static boolean isRegistered(@NotNull String id) { + return SYSTEMS.containsKey(id); + } + + /** + * Returns a registered team system. + * + * @param id the team system id + * @return the registered implementation, or {@code null} if none exists + */ + @Contract(pure = true) + public static @Nullable TeamSystem get(@NotNull String id) { + return SYSTEMS.get(id); + } + + /** + * {@return an immutable ordered set containing all registered team system ids} + */ + @Contract(pure = true) + public static @NotNull Set getRegisteredIds() { + return Collections.unmodifiableSet(SYSTEMS.keySet()); + } + + /** + * {@return an immutable ordered view of all registered team systems} + */ + @Contract(pure = true) + public static @NotNull Map getRegistered() { + return Collections.unmodifiableMap(SYSTEMS); + } + + /** + * Determines whether the supplied player is a teammate of the owner using + * the currently configured team system. + * + *

If the configured implementation is unavailable, the built-in + * {@value #MINECRAFT} implementation is used. If that implementation is also + * unavailable, access is denied.

+ * + * @param owner the machine owner + * @param player the player attempting access + * @return whether the configured team system considers them teammates + */ + public static boolean areTeammates( + @NotNull UUID owner, + @NotNull Player player + ) { + TeamSystem system = getConfigured(); + + return system != null && system.areTeammates(owner, player); + } + + /** + * Returns the currently configured team system, falling back to vanilla. + * + * @return the active team system, or {@code null} if no usable implementation + * is registered + */ + public static @Nullable TeamSystem getConfigured() { + String configured = MachineLib.CONFIG.teamSystem(); + TeamSystem system = SYSTEMS.get(configured); + + if (system != null) { + return system; + } + + return SYSTEMS.get(MINECRAFT); + } +} \ No newline at end of file diff --git a/src/main/java/dev/galacticraft/machinelib/client/impl/compat/ClothConfigScreen.java b/src/main/java/dev/galacticraft/machinelib/client/impl/compat/ClothConfigScreen.java index c245cf5e..e40af126 100644 --- a/src/main/java/dev/galacticraft/machinelib/client/impl/compat/ClothConfigScreen.java +++ b/src/main/java/dev/galacticraft/machinelib/client/impl/compat/ClothConfigScreen.java @@ -50,6 +50,12 @@ public static Screen factory(Screen screen) { .setEnumNameProvider(v -> ((Config.FluidUnits) v).getName()) .build() ); + general.addEntry(entryBuilder.startStrField(Component.translatable("ui.machinelib.config.team_system"), MachineLib.CONFIG.teamSystem()) + .setSaveConsumer(MachineLib.CONFIG::setTeamSystem) + .setDefaultValue(Config.DEFAULT.teamSystem()) + .setTooltip(Component.translatable("ui.machinelib.config.team_system.tooltip")) + .build() + ); // ConfigCategory debug = builder.getOrCreateCategory(Component.translatable("ui.machinelib.config.category.debug")); return builder.build(); diff --git a/src/main/java/dev/galacticraft/machinelib/impl/MachineLib.java b/src/main/java/dev/galacticraft/machinelib/impl/MachineLib.java index 260b9b94..38c0b3fa 100644 --- a/src/main/java/dev/galacticraft/machinelib/impl/MachineLib.java +++ b/src/main/java/dev/galacticraft/machinelib/impl/MachineLib.java @@ -24,6 +24,9 @@ import dev.galacticraft.machinelib.api.component.MLDataComponents; import dev.galacticraft.machinelib.api.config.Config; +import dev.galacticraft.machinelib.api.machine.security.TeamSystems; +import dev.galacticraft.machinelib.impl.command.MachineLibCommands; +import dev.galacticraft.machinelib.impl.machine.security.VanillaTeamSystem; import dev.galacticraft.machinelib.impl.network.MachineLibPackets; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariantAttributes; @@ -39,6 +42,13 @@ public final class MachineLib implements ModInitializer { @Override public void onInitialize() { + TeamSystems.register( + TeamSystems.MINECRAFT, + VanillaTeamSystem.INSTANCE + ); + + MachineLibCommands.register(); + MachineLibPackets.registerChannels(); MachineLibPackets.registerServer(); MLDataComponents.init(); diff --git a/src/main/java/dev/galacticraft/machinelib/impl/command/MachineLibCommands.java b/src/main/java/dev/galacticraft/machinelib/impl/command/MachineLibCommands.java new file mode 100644 index 00000000..c3abadcf --- /dev/null +++ b/src/main/java/dev/galacticraft/machinelib/impl/command/MachineLibCommands.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2021-2026 Team Galacticraft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package dev.galacticraft.machinelib.impl.command; + +import dev.galacticraft.machinelib.api.machine.security.TeamSystems; +import dev.galacticraft.machinelib.impl.MachineLib; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.minecraft.ChatFormatting; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public final class MachineLibCommands { + private MachineLibCommands() {} + + public static void register() { + CommandRegistrationCallback.EVENT.register( + (dispatcher, registryAccess, environment) -> + dispatcher.register( + Commands.literal("machinelib") + .then( + Commands.literal("exposedTeamSystems") + .executes(context -> { + String configured = + MachineLib.CONFIG.teamSystem(); + + context.getSource().sendSuccess( + () -> Component.literal( + "Registered MachineLib team systems:" + ), + false + ); + + for (String id : + TeamSystems.getRegisteredIds()) { + boolean active = + id.equals(configured) + || !TeamSystems.isRegistered(configured) + && id.equals(TeamSystems.MINECRAFT); + + Component message = + Component.literal( + " - " + id + ); + + if (active) { + message = message.copy() + .append( + Component.literal( + " [ACTIVE]" + ).withStyle( + ChatFormatting.GREEN + ) + ); + } + + Component finalMessage = message; + + context.getSource().sendSuccess( + () -> finalMessage, + false + ); + } + + if (!TeamSystems.isRegistered(configured)) { + context.getSource().sendSuccess( + () -> Component.literal( + "Configured team system '" + + configured + + "' is not registered; using '" + + TeamSystems.MINECRAFT + + "'." + ).withStyle( + ChatFormatting.YELLOW + ), + false + ); + } + + return TeamSystems + .getRegisteredIds() + .size(); + }) + ) + ) + ); + } +} \ No newline at end of file diff --git a/src/main/java/dev/galacticraft/machinelib/impl/config/MachineLibConfig.java b/src/main/java/dev/galacticraft/machinelib/impl/config/MachineLibConfig.java index 9fb6c686..2e5fd0b8 100644 --- a/src/main/java/dev/galacticraft/machinelib/impl/config/MachineLibConfig.java +++ b/src/main/java/dev/galacticraft/machinelib/impl/config/MachineLibConfig.java @@ -44,6 +44,9 @@ public class MachineLibConfig implements Config { @Expose public FluidUnits fluidUnits = FluidUnits.MILLIBUCKET; + @Expose + public String teamSystem = "minecraft"; + public MachineLibConfig(@Nullable File file) { this.file = file; @@ -77,10 +80,27 @@ public void getFluidUnits(FluidUnits units) { this.fluidUnits = units; } + @Override + public String teamSystem() { + if (this.teamSystem == null || this.teamSystem.isBlank()) { + return "minecraft"; + } + + return this.teamSystem; + } + + @Override + public void setTeamSystem(String teamSystem) { + this.teamSystem = teamSystem == null || teamSystem.isBlank() + ? "minecraft" + : teamSystem; + } + @Override public void copyFrom(Config config) { this.enableColoredVanillaFluidNames = config.enableColoredVanillaFluidNames(); this.fluidUnits = config.fluidUnits(); + this.teamSystem = config.teamSystem(); } @Override diff --git a/src/main/java/dev/galacticraft/machinelib/impl/machine/security/VanillaTeamSystem.java b/src/main/java/dev/galacticraft/machinelib/impl/machine/security/VanillaTeamSystem.java new file mode 100644 index 00000000..dfcc22ee --- /dev/null +++ b/src/main/java/dev/galacticraft/machinelib/impl/machine/security/VanillaTeamSystem.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2021-2026 Team Galacticraft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package dev.galacticraft.machinelib.impl.machine.security; + +import com.mojang.authlib.GameProfile; +import dev.galacticraft.machinelib.api.machine.security.TeamSystem; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.scores.PlayerTeam; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; +import java.util.UUID; + +/** + * Team system backed by vanilla Minecraft scoreboard teams ({@code /team}). + */ +@ApiStatus.Internal +public final class VanillaTeamSystem implements TeamSystem { + public static final VanillaTeamSystem INSTANCE = new VanillaTeamSystem(); + + private VanillaTeamSystem() {} + + @Override + public boolean areTeammates( + @NotNull UUID owner, + @NotNull Player player + ) { + MinecraftServer server = player.getServer(); + + if (server == null) { + return false; + } + + Optional ownerProfile = server.getProfileCache().get(owner); + + if (ownerProfile.isEmpty()) { + return false; + } + + PlayerTeam ownerTeam = server.getScoreboard().getPlayersTeam( + ownerProfile.get().getName() + ); + + return ownerTeam != null && ownerTeam == player.getTeam(); + } +} \ No newline at end of file diff --git a/src/main/resources/assets/machinelib/lang/en_us.json b/src/main/resources/assets/machinelib/lang/en_us.json index 81dc9318..5f4946db 100644 --- a/src/main/resources/assets/machinelib/lang/en_us.json +++ b/src/main/resources/assets/machinelib/lang/en_us.json @@ -58,5 +58,7 @@ "ui.machinelib.config.enable_colored_vanilla_fluid_names": "Enable Colored Vanilla Fluid Names", "ui.machinelib.config.fluid_display_mode": "Fluid Display Mode", "ui.machinelib.config.fluid_display_mode.millibucket": "Millibucket", - "ui.machinelib.config.fluid_display_mode.raw": "Raw" + "ui.machinelib.config.fluid_display_mode.raw": "Raw", + "ui.machinelib.config.team_system": "Team System", + "ui.machinelib.config.team_system.tooltip": "Registered team system used by machines set to Team access." } \ No newline at end of file From 5052e875fa91ee1e743c9af222019015de58d358 Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Tue, 22 Sep 2026 20:23:07 +1000 Subject: [PATCH 2/4] Make the config for the team system a dropdown instead of a text box to simplify usability. --- .../client/impl/compat/ClothConfigScreen.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/dev/galacticraft/machinelib/client/impl/compat/ClothConfigScreen.java b/src/main/java/dev/galacticraft/machinelib/client/impl/compat/ClothConfigScreen.java index 30b80bf5..9d8f0112 100644 --- a/src/main/java/dev/galacticraft/machinelib/client/impl/compat/ClothConfigScreen.java +++ b/src/main/java/dev/galacticraft/machinelib/client/impl/compat/ClothConfigScreen.java @@ -23,13 +23,17 @@ package dev.galacticraft.machinelib.client.impl.compat; import dev.galacticraft.machinelib.api.config.Config; +import dev.galacticraft.machinelib.api.machine.security.TeamSystems; import dev.galacticraft.machinelib.impl.MachineLib; import me.shedaniel.clothconfig2.api.ConfigBuilder; import me.shedaniel.clothconfig2.api.ConfigCategory; import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; +import me.shedaniel.clothconfig2.impl.builders.DropdownMenuBuilder; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; +import java.util.ArrayList; + public class ClothConfigScreen { public static Screen factory(Screen screen) { final ConfigBuilder builder = ConfigBuilder.create(); @@ -50,9 +54,13 @@ public static Screen factory(Screen screen) { .setEnumNameProvider(v -> ((Config.FluidUnits) v).getName()) .build() ); - general.addEntry(entryBuilder.startStrField(Component.translatable("ui.machinelib.config.team_system"), MachineLib.CONFIG.teamSystem()) - .setSaveConsumer(MachineLib.CONFIG::setTeamSystem) + String configuredTeamSystem = MachineLib.CONFIG.teamSystem(); + String displayedTeamSystem = TeamSystems.isRegistered(configuredTeamSystem) ? configuredTeamSystem : TeamSystems.MINECRAFT; + general.addEntry(entryBuilder.startDropdownMenu(Component.translatable("ui.machinelib.config.team_system"), DropdownMenuBuilder.TopCellElementBuilder.of(displayedTeamSystem, value -> value), DropdownMenuBuilder.CellCreatorBuilder.of(value -> Component.literal(value))) + .setSelections(new ArrayList<>(TeamSystems.getRegisteredIds())) .setDefaultValue(Config.DEFAULT.teamSystem()) + .setSuggestionMode(false) + .setSaveConsumer(MachineLib.CONFIG::setTeamSystem) .setTooltip(Component.translatable("ui.machinelib.config.team_system.tooltip")) .build() ); From 0035f4f0167286e98f5b2e873a7849f994795cc5 Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Wed, 23 Sep 2026 09:24:14 +1000 Subject: [PATCH 3/4] Revised to fix small issues --- build.gradle.kts | 2 +- .../impl/command/MachineLibCommands.java | 96 +++++++------------ .../impl/config/MachineLibConfig.java | 9 +- .../machine/security/VanillaTeamSystem.java | 9 +- 4 files changed, 50 insertions(+), 66 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f728c4b5..96a8c3f8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -187,8 +187,8 @@ dependencies { listOf( "fabric-api-base", - "fabric-command-api-v2", "fabric-api-lookup-api-v1", + "fabric-command-api-v2", "fabric-data-attachment-api-v1", "fabric-gametest-api-v1", "fabric-item-api-v1", diff --git a/src/main/java/dev/galacticraft/machinelib/impl/command/MachineLibCommands.java b/src/main/java/dev/galacticraft/machinelib/impl/command/MachineLibCommands.java index c3abadcf..0a30f378 100644 --- a/src/main/java/dev/galacticraft/machinelib/impl/command/MachineLibCommands.java +++ b/src/main/java/dev/galacticraft/machinelib/impl/command/MachineLibCommands.java @@ -36,74 +36,52 @@ private MachineLibCommands() {} public static void register() { CommandRegistrationCallback.EVENT.register( - (dispatcher, registryAccess, environment) -> - dispatcher.register( - Commands.literal("machinelib") - .then( - Commands.literal("exposedTeamSystems") - .executes(context -> { - String configured = - MachineLib.CONFIG.teamSystem(); + (dispatcher, registryAccess, environment) -> dispatcher.register( + Commands.literal("machinelib").then( + Commands.literal("exposedTeamSystems").executes(context -> { + String configured = MachineLib.CONFIG.teamSystem(); + boolean configuredRegistered = TeamSystems.isRegistered(configured); - context.getSource().sendSuccess( - () -> Component.literal( - "Registered MachineLib team systems:" - ), - false - ); + context.getSource().sendSuccess( + () -> Component.literal("Registered MachineLib team systems:"), + false + ); - for (String id : - TeamSystems.getRegisteredIds()) { - boolean active = - id.equals(configured) - || !TeamSystems.isRegistered(configured) - && id.equals(TeamSystems.MINECRAFT); + for (String id : TeamSystems.getRegisteredIds()) { + boolean active = id.equals(configured) + || !configuredRegistered && id.equals(TeamSystems.MINECRAFT); - Component message = - Component.literal( - " - " + id - ); + Component message = Component.literal(" - " + id); - if (active) { - message = message.copy() - .append( - Component.literal( - " [ACTIVE]" - ).withStyle( - ChatFormatting.GREEN - ) - ); - } + if (active) { + message = message.copy().append( + Component.literal(" [ACTIVE]") + .withStyle(ChatFormatting.GREEN) + ); + } - Component finalMessage = message; + Component finalMessage = message; - context.getSource().sendSuccess( - () -> finalMessage, - false - ); - } + context.getSource().sendSuccess(() -> finalMessage, false); + } - if (!TeamSystems.isRegistered(configured)) { - context.getSource().sendSuccess( - () -> Component.literal( - "Configured team system '" - + configured - + "' is not registered; using '" - + TeamSystems.MINECRAFT - + "'." - ).withStyle( - ChatFormatting.YELLOW - ), - false - ); - } + if (!configuredRegistered) { + context.getSource().sendSuccess( + () -> Component.literal( + String.format( + "Configured team system '%s' is not registered; using '%s'.", + configured, + TeamSystems.MINECRAFT + ) + ).withStyle(ChatFormatting.YELLOW), + false + ); + } - return TeamSystems - .getRegisteredIds() - .size(); - }) - ) + return TeamSystems.getRegisteredIds().size(); + }) ) + ) ); } } \ No newline at end of file diff --git a/src/main/java/dev/galacticraft/machinelib/impl/config/MachineLibConfig.java b/src/main/java/dev/galacticraft/machinelib/impl/config/MachineLibConfig.java index 826df190..f7099dff 100644 --- a/src/main/java/dev/galacticraft/machinelib/impl/config/MachineLibConfig.java +++ b/src/main/java/dev/galacticraft/machinelib/impl/config/MachineLibConfig.java @@ -27,6 +27,7 @@ import com.google.gson.annotations.Expose; import dev.galacticraft.machinelib.api.config.Config; import dev.galacticraft.machinelib.impl.MachineLib; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; @@ -80,7 +81,7 @@ public void setFluidUnits(FluidUnits units) { this.fluidUnits = units; } - @Override + @Override @NotNull public String teamSystem() { if (this.teamSystem == null || this.teamSystem.isBlank()) { return "minecraft"; @@ -90,10 +91,8 @@ public String teamSystem() { } @Override - public void setTeamSystem(String teamSystem) { - this.teamSystem = teamSystem == null || teamSystem.isBlank() - ? "minecraft" - : teamSystem; + public void setTeamSystem(@Nullable String teamSystem) { + this.teamSystem = ((teamSystem == null || teamSystem.isBlank()) ? "minecraft" : teamSystem); } @Override diff --git a/src/main/java/dev/galacticraft/machinelib/impl/machine/security/VanillaTeamSystem.java b/src/main/java/dev/galacticraft/machinelib/impl/machine/security/VanillaTeamSystem.java index dfcc22ee..e92e25f0 100644 --- a/src/main/java/dev/galacticraft/machinelib/impl/machine/security/VanillaTeamSystem.java +++ b/src/main/java/dev/galacticraft/machinelib/impl/machine/security/VanillaTeamSystem.java @@ -25,6 +25,7 @@ import com.mojang.authlib.GameProfile; import dev.galacticraft.machinelib.api.machine.security.TeamSystem; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.players.GameProfileCache; import net.minecraft.world.entity.player.Player; import net.minecraft.world.scores.PlayerTeam; import org.jetbrains.annotations.ApiStatus; @@ -53,7 +54,13 @@ public boolean areTeammates( return false; } - Optional ownerProfile = server.getProfileCache().get(owner); + GameProfileCache cache = server.getProfileCache(); + + if (cache == null) { + return false; + } + + Optional ownerProfile = cache.get(owner); if (ownerProfile.isEmpty()) { return false; From af4a463df5dcccc1a5968558d879c4fed1cdc860 Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Wed, 23 Sep 2026 09:32:48 +1000 Subject: [PATCH 4/4] I broke something --- .../galacticraft/machinelib/impl/config/MachineLibConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dev/galacticraft/machinelib/impl/config/MachineLibConfig.java b/src/main/java/dev/galacticraft/machinelib/impl/config/MachineLibConfig.java index a29a89f1..9da2f949 100644 --- a/src/main/java/dev/galacticraft/machinelib/impl/config/MachineLibConfig.java +++ b/src/main/java/dev/galacticraft/machinelib/impl/config/MachineLibConfig.java @@ -98,7 +98,7 @@ public void setTeamSystem(@Nullable String teamSystem) { @Override public void copyFrom(Config config) { this.enableColoredVanillaFluidNames = config.enableColoredVanillaFluidNames(); - this.fluidUnits = config.getFluidUnits(); + this.fluidUnits = config.fluidUnits(); this.teamSystem = config.teamSystem(); }