diff --git a/README.md b/README.md index 31180ee..cca89b0 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Versions are available on maven in the format `net.william278.uniform:ARTIFACT:VERSION`. See below for a table of supported platforms. -Note that Uniform versions omit the `v` prefix. Fabric versions are suffixed with the target Minecraft version (e.g. `1.1.9+1.21`) and also require Fabric API installed on the server. +Note that Uniform versions omit the `v` prefix. Fabric versions are suffixed with the target Minecraft version (e.g. `1.1.10+1.21`) and also require Fabric API installed on the server. Sponge versions are suffixed with the target Sponge API version (e.g. `1.1.10+11`). @@ -29,7 +29,7 @@ Note that Uniform versions omit the `v` prefix. Fabric versions are suffixed wit - + @@ -46,45 +46,50 @@ Note that Uniform versions omit the `v` prefix. Fabric versions are suffixed wit - + - + - + - - + - + - + + + + + + + - - + - + + - + - +
Platform ArtifactPlatform ver.Minecraft ver. Java ver. Uniform ver.
Supported Platforms
Bukkit/SpigotBukkit / Spigot uniform-bukkitmc 1.17.11.17.1 17
Paper uniform-papermc 1.17.1
VelocityVelocity (3.3.0) uniform-velocity3.3.01.8.9
FabricSponge (api 11)uniform-sponge=1.20.621
Fabric (1.20.1) uniform-fabric=mc 1.20.121=1.20.1
=mc 1.21Fabric (1.21)=1.21
Formerly Supported Platforms
FabricFabric (1.20.6) uniform-fabric=mc 1.20.6=1.20.6 21 v1.1.8
-Example: To target Uniform on Bukkit, the artifact is `net.william278.uniform:uniform-bukkit:1.1.9` (check that this version is up-to-date – make sure you target the latest available!). +Example: To target Uniform on Bukkit, the artifact is `net.william278.uniform:uniform-bukkit:1.1.10` (check that this version is up-to-date – make sure you target the latest available!). ## Setup Uniform is available [on Maven](https://repo.william278.net/#/releases/net/william278/uniform/). You can browse the Javadocs [here](https://repo.william278.net/javadoc/releases/net/william278/uniform/latest). @@ -99,7 +104,7 @@ repositories { } ``` -Then, add the dependency itself. Replace `VERSION` with the latest release version. (e.g., `1.0`) and `PLATFORM` with the platform you are targeting (e.g., `paper`). If you want to target pre-release "snapshot" versions (not recommended), you should use the `/snapshots` repository instead. +Then, add the dependency itself. Replace `VERSION` with the latest release version. (e.g., `1.1.10`) and `PLATFORM` with the platform you are targeting (e.g., `paper`). If you want to target pre-release "snapshot" versions (not recommended), you should use the `/snapshots` repository instead. ```groovy dependencies { diff --git a/build.gradle b/build.gradle index 3bf961d..e2b6981 100644 --- a/build.gradle +++ b/build.gradle @@ -209,6 +209,19 @@ subprojects { } } + if (['sponge-11'].contains(project.name)) { + publications { + mavenSponge11(MavenPublication) { + groupId = 'net.william278.uniform' + artifactId = 'uniform-sponge' + version = "${rootProject.version}+11" + artifact shadowJar + artifact sourcesJar + artifact javadocJar + } + } + } + } jar.dependsOn shadowJar diff --git a/settings.gradle b/settings.gradle index 0aef91d..6196c78 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,6 +12,7 @@ include( // Server Plugins 'paper', 'bukkit', + 'sponge-11', // Proxy Plugins 'velocity', diff --git a/sponge-11/build.gradle b/sponge-11/build.gradle new file mode 100644 index 0000000..45aa20a --- /dev/null +++ b/sponge-11/build.gradle @@ -0,0 +1,13 @@ +plugins { + id 'java-library' + id 'maven-publish' +} + +dependencies { + implementation project(path: ':common') + + compileOnly 'org.spongepowered:spongeapi:11.0.0' + compileOnly 'org.projectlombok:lombok:1.18.32' + + annotationProcessor 'org.projectlombok:lombok:1.18.32' +} diff --git a/sponge-11/src/main/java/net/william278/uniform/sponge/SpongeCommand.java b/sponge-11/src/main/java/net/william278/uniform/sponge/SpongeCommand.java new file mode 100644 index 0000000..54ff176 --- /dev/null +++ b/sponge-11/src/main/java/net/william278/uniform/sponge/SpongeCommand.java @@ -0,0 +1,146 @@ +/* + * This file is part of Uniform, licensed under the GNU General Public License v3.0. + * + * Copyright (c) Tofaa2 + * Copyright (c) William278 + * Copyright (c) contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.william278.uniform.sponge; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.william278.uniform.BaseCommand; +import net.william278.uniform.Command; +import net.william278.uniform.Permission; +import net.william278.uniform.Uniform; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.api.Game; +import org.spongepowered.api.command.Command.Raw; +import org.spongepowered.api.command.CommandCause; +import org.spongepowered.api.command.CommandCompletion; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.exception.CommandException; +import org.spongepowered.api.command.parameter.ArgumentReader; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@SuppressWarnings("unused") +public class SpongeCommand extends BaseCommand { + + private @Nullable Permission permission; + + public SpongeCommand(@NotNull Command command) { + super(command); + this.permission = command.getPermission().orElse(null); + } + + public SpongeCommand(@NotNull String name, @NotNull String description, @NotNull List aliases) { + super(name, description, aliases); + } + + public SpongeCommand(@NotNull String name, @NotNull List aliases) { + super(name, aliases); + } + + @NotNull + Impl getImpl() { + return new Impl(this); + } + + static final class Impl implements Raw { + + private static final int COMMAND_SUCCESS = com.mojang.brigadier.Command.SINGLE_SUCCESS; + private final CommandDispatcher dispatcher = new CommandDispatcher<>(); + private final SpongeCommand command; + private final @Nullable Permission permission; + + public Impl(@NotNull SpongeCommand command) { + this.dispatcher.register(command.createBuilder()); + this.command = command; + this.permission = command.permission; + } + + @Override + public CommandResult process(CommandCause cause, ArgumentReader.Mutable arguments) throws CommandException { + try { + return dispatcher.execute(arguments.immutable().remaining(), cause) == COMMAND_SUCCESS + ? CommandResult.success() + : CommandResult.error(Component.translatable("command.failed", NamedTextColor.RED)); + } catch (CommandSyntaxException e) { + throw new CommandException(Component + .translatable("command.context.parse_error", NamedTextColor.RED).arguments( + Component.text(e.getRawMessage().getString()), + Component.text(e.getCursor()), + Component.text(e.getContext()) + ), e, true); + } + } + + @Override + public List complete(CommandCause cause, ArgumentReader.Mutable arguments) throws CommandException { + return dispatcher.getCompletionSuggestions( + dispatcher.parse(arguments.remaining(), cause), + arguments.cursor() + ) + .thenApply(suggestions -> suggestions.getList().stream().map(s -> CommandCompletion.of( + s.getText(), Component.text(s.getTooltip().getString()) + )).toList()) + .join(); + } + + @Override + public boolean canExecute(CommandCause cause) { + if (permission == null) { + return true; + } + return new SpongeCommandUser(cause).checkPermission(permission); + } + + @Override + public Optional shortDescription(CommandCause cause) { + return Optional.of(Component.text(command.getDescription())); + } + + @Override + public Optional extendedDescription(CommandCause cause) { + return Optional.of(Component.text(command.getDescription())); + } + + @Override + public Component usage(CommandCause cause) { + return Component.text(dispatcher.getSmartUsage(dispatcher.getRoot(), cause) + .values().stream().map("/%s"::formatted).collect(Collectors.joining("\n"))); + } + + } + + @Override + public void addSubCommand(@NotNull Command command) { + addSubCommand(new SpongeCommand(command)); + } + + @Override + public Uniform getUniform() { + return SpongeUniform.INSTANCE; + } + +} diff --git a/sponge-11/src/main/java/net/william278/uniform/sponge/SpongeCommandUser.java b/sponge-11/src/main/java/net/william278/uniform/sponge/SpongeCommandUser.java new file mode 100644 index 0000000..fff98c0 --- /dev/null +++ b/sponge-11/src/main/java/net/william278/uniform/sponge/SpongeCommandUser.java @@ -0,0 +1,64 @@ +/* + * This file is part of Uniform, licensed under the GNU General Public License v3.0. + * + * Copyright (c) Tofaa2 + * Copyright (c) William278 + * Copyright (c) contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.william278.uniform.sponge; + +import net.kyori.adventure.audience.Audience; +import net.william278.uniform.CommandUser; +import net.william278.uniform.Permission; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.api.command.CommandCause; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.util.Tristate; + +import java.util.UUID; + +public record SpongeCommandUser(@NotNull CommandCause executor) implements CommandUser { + + @Override + @NotNull + public Audience getAudience() { + return executor.audience(); + } + + @Override + @Nullable + public String getName() { + return executor instanceof Player player ? player.name() : null; + } + + @Override + @Nullable + public UUID getUuid() { + return executor instanceof Player player ? player.uniqueId() : null; + } + + @Override + public boolean checkPermission(@NotNull Permission permission) { + final Tristate state = executor.permissionValue(permission.toString()); + if (state == Tristate.UNDEFINED && permission.defaultValue() == Permission.Default.IF_OP) { + return executor.hasPermission(permission.toString()); + } + return state == Tristate.TRUE; + } + +} diff --git a/sponge-11/src/main/java/net/william278/uniform/sponge/SpongeUniform.java b/sponge-11/src/main/java/net/william278/uniform/sponge/SpongeUniform.java new file mode 100644 index 0000000..aec6318 --- /dev/null +++ b/sponge-11/src/main/java/net/william278/uniform/sponge/SpongeUniform.java @@ -0,0 +1,106 @@ +/* + * This file is part of Uniform, licensed under the GNU General Public License v3.0. + * + * Copyright (c) Tofaa2 + * Copyright (c) William278 + * Copyright (c) contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.william278.uniform.sponge; + +import lombok.Getter; +import lombok.Setter; +import net.william278.uniform.BaseCommand; +import net.william278.uniform.Command; +import net.william278.uniform.CommandUser; +import net.william278.uniform.Uniform; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.api.Game; +import org.spongepowered.api.command.Command.Raw; +import org.spongepowered.api.command.CommandCause; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; +import org.spongepowered.plugin.PluginContainer; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Function; + +@SuppressWarnings("unused") +public final class SpongeUniform implements Uniform { + + static SpongeUniform INSTANCE; + + private final Set commands = new HashSet<>(); + private final PluginContainer plugin; + + @Getter + @Setter + Function commandUserSupplier = (cause) -> new SpongeCommandUser((CommandCause) cause); + + private SpongeUniform(@NotNull PluginContainer plugin, @NotNull Game game) { + this.plugin = plugin; + game.eventManager().registerListeners(plugin, this); + } + + /** + * Get the SpongeUniform instance for registering commands + * + * @param plugin The plugin container + * @param game The game instance + * @return The SpongeUniform instance + * @since 1.1.10 + */ + @NotNull + public static SpongeUniform getInstance(@NotNull PluginContainer plugin, @NotNull Game game) { + return INSTANCE != null ? INSTANCE : (INSTANCE = new SpongeUniform(plugin, game)); + } + + @Listener + public void onRegisterCommands(@NotNull RegisterCommandEvent event) { + commands.forEach(command -> event.register( + plugin, command.getImpl(), command.getName(), command.getAliases().toArray(String[]::new) + )); + } + + /** + * Register a command with the server's command manager + * + * @param commands The commands to register + * @param The command source type + * @param The command type + * @since 1.1.10 + */ + @SafeVarargs + @Override + public final > void register(T... commands) { + Arrays.stream(commands).map(c -> (SpongeCommand) c).forEach(this.commands::add); + } + + /** + * Register a command with the server's command manager + * + * @param commands The commands to register + * @since 1.1.10 + */ + @Override + public void register(Command... commands) { + register(Arrays.stream(commands).map(SpongeCommand::new).toArray(SpongeCommand[]::new)); + } + + +}