diff --git a/api-jvm-impl/build.gradle b/api-jvm-impl/build.gradle index 5daedbef..1fbf4aa1 100644 --- a/api-jvm-impl/build.gradle +++ b/api-jvm-impl/build.gradle @@ -1,7 +1,6 @@ dependencies { api project(':api-jvm') - implementation 'ch.vorburger.minecraft.osgi:api:1.0.0' implementation('com.spotify:futures-extra:4.0.0') { exclude group: 'com.google.guava' } diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/EventsImpl.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/EventsImpl.java index a982f428..4e56b210 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/EventsImpl.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/EventsImpl.java @@ -18,7 +18,6 @@ */ package ch.vorburger.minecraft.storeys.japi.impl; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.japi.Callback; import ch.vorburger.minecraft.storeys.japi.Events; import ch.vorburger.minecraft.storeys.japi.ReadingSpeed; @@ -30,13 +29,15 @@ import java.util.Collection; import java.util.Optional; import java.util.concurrent.ConcurrentLinkedQueue; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.CommandMapping; +import org.spongepowered.api.command.Command; import org.spongepowered.api.command.CommandResult; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.command.registrar.CommandRegistrar; +import org.spongepowered.plugin.PluginContainer; /** * {@link Events} implementation. @@ -49,7 +50,7 @@ class EventsImpl implements Events, Unregisterable { private static final Logger LOG = LoggerFactory.getLogger(EventsImpl.class); - private final PluginInstance plugin; + private final PluginContainer plugin; private final EventService eventService; // when made modifiable, then this should be per Player @@ -58,22 +59,28 @@ class EventsImpl implements Events, Unregisterable { private final Collection unregistrables = new ConcurrentLinkedQueue<>(); private final ActionPlayer player = new ActionPlayer(); - EventsImpl(PluginInstance plugin, EventService eventService) { + EventsImpl(PluginContainer plugin, EventService eventService) { this.plugin = plugin; this.eventService = eventService; } @Override public void whenCommand(String name, Callback callback) { - CommandSpec spec = CommandSpec.builder().executor((src, args) -> { - CommandExceptions.doOrThrow("/" + name, () -> invokeCallback(src, callback)); + final Command.Parameterized spec = Command.builder().executor((src) -> { + CommandExceptions.doOrThrow("/" + name, () -> invokeCallback(src.cause().audience(), callback)); return CommandResult.success(); }).build(); - Optional opt = Sponge.getCommandManager().register(plugin, spec, name); - if (!opt.isPresent()) { + final Optional> registrar = Sponge.server().commandManager().registrar(Command.Parameterized.class); + if (!registrar.isPresent()) { LOG.error("Could not register new command, because it's already present: /" + name); return; } - unregistrables.add(() -> Sponge.getCommandManager().removeMapping(opt.get())); + registrar.get().register(plugin, spec, name); + Sponge.server().onlinePlayers().forEach(p -> Sponge.server().commandManager().updateCommandTreeForPlayer(p)); + + //TODO unregister commands so that we can update them + unregistrables.add(() -> { + + }); } @Override public void whenPlayerJoins(Callback callback) { @@ -100,7 +107,7 @@ class EventsImpl implements Events, Unregisterable { ch.vorburger.minecraft.storeys.japi.impl.events.Callback otherCallback = invoker -> { invokeCallback(invoker, callback); }; - unregistrables.add(eventService.registerInteractEntity(entityName, otherCallback)); + unregistrables.add(eventService.registerInteractEntity(Component.text(entityName), otherCallback)); } @Override public void unregister() { @@ -109,9 +116,9 @@ class EventsImpl implements Events, Unregisterable { } } - private void invokeCallback(CommandSource source, Callback callback) throws Exception { + private void invokeCallback(Audience source, Callback callback) throws Exception { MinecraftJvmImpl m = new MinecraftJvmImpl(plugin, source); callback.invoke(m); - player.play(new ActionContextImpl(m.player(), readingSpeed), m.getActionList()); + player.play(new ActionContextImpl(source, readingSpeed), m.getActionList()); } } diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/MinecraftJvmImpl.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/MinecraftJvmImpl.java index d46faef6..33a7fea2 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/MinecraftJvmImpl.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/MinecraftJvmImpl.java @@ -18,7 +18,6 @@ */ package ch.vorburger.minecraft.storeys.japi.impl; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.japi.Action; import ch.vorburger.minecraft.storeys.japi.Events; import ch.vorburger.minecraft.storeys.japi.Minecraft; @@ -29,10 +28,12 @@ import ch.vorburger.minecraft.storeys.japi.impl.actions.TitleAction; import java.util.ArrayList; import java.util.List; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.CommandCause; import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.text.Text; +import org.spongepowered.plugin.PluginContainer; /** * {@link Minecraft} implementation. @@ -40,24 +41,24 @@ * *

The "lifecycle" of this is NOT a Singleton, * but one for each instance (not just kind of) of an event registered on {@link Events}, - * such as custom command, when right clicked, when player joined, when inside, etc. + * such as custom command, when right-clicked, when player joined, when inside, etc. */ class MinecraftJvmImpl implements Minecraft { - private final PluginInstance plugin; - private final CommandSource source; + private final PluginContainer plugin; + private final Audience source; private final ActionWaitHelper actionWaitHelper; private final List> actionList = new ArrayList<>(); - MinecraftJvmImpl(PluginInstance plugin, CommandSource source) { + MinecraftJvmImpl(PluginContainer plugin, Audience source) { this.source = source; this.plugin = plugin; this.actionWaitHelper = new ActionWaitHelper(plugin); } @Override public void cmd(String command) { - CommandAction action = new CommandAction(plugin, Sponge.getScheduler()); + CommandAction action = new CommandAction(plugin, Sponge.asyncScheduler()); action.setCommand(command); actionList.add(action); } @@ -72,7 +73,7 @@ class MinecraftJvmImpl implements Minecraft { Narrator narrator = new Narrator(plugin); NarrateAction action = new NarrateAction(narrator); action.setEntity(entity); - action.setText(Text.of(text)); + action.setText(Component.text(text)); actionList.add(action); } diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/Scripts.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/Scripts.java index d1fb9f10..b1859da8 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/Scripts.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/Scripts.java @@ -18,7 +18,6 @@ */ package ch.vorburger.minecraft.storeys.japi.impl; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.japi.Script; import ch.vorburger.minecraft.storeys.japi.impl.events.EventService; import java.util.Collection; @@ -26,15 +25,16 @@ import java.util.concurrent.ConcurrentHashMap; import javax.inject.Inject; import javax.inject.Singleton; +import org.spongepowered.plugin.PluginContainer; @Singleton public class Scripts { private final Map unregisterables = new ConcurrentHashMap<>(); - private final PluginInstance plugin; + private final PluginContainer plugin; private final EventService eventService; - @Inject public Scripts(PluginInstance plugin, EventService eventService) { + @Inject public Scripts(PluginContainer plugin, EventService eventService) { this.plugin = plugin; this.eventService = eventService; } diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/ActionContextImpl.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/ActionContextImpl.java index acce8410..58f2b069 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/ActionContextImpl.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/ActionContextImpl.java @@ -20,21 +20,22 @@ import ch.vorburger.minecraft.storeys.japi.ActionContext; import ch.vorburger.minecraft.storeys.japi.ReadingSpeed; -import org.spongepowered.api.command.CommandSource; +import net.kyori.adventure.audience.Audience; +import org.spongepowered.api.command.CommandCause; public final class ActionContextImpl implements ActionContext { - private final CommandSource commandSource; + private final Audience commandCause; private final ReadingSpeed readingSpeed; - public ActionContextImpl(CommandSource commandSource, ReadingSpeed readingSpeed) { + public ActionContextImpl(Audience commandCause, ReadingSpeed readingSpeed) { super(); - this.commandSource = commandSource; + this.commandCause = commandCause; this.readingSpeed = readingSpeed; } - public CommandSource getCommandSource() { - return commandSource; + public Audience getCommandCause() { + return commandCause; } public ReadingSpeed getReadingSpeed() { @@ -44,7 +45,7 @@ public ReadingSpeed getReadingSpeed() { @Override public int hashCode() { final int prime = 31; int result = 1; - result = (prime * result) + (commandSource == null ? 0 : commandSource.hashCode()); + result = (prime * result) + (commandCause == null ? 0 : commandCause.hashCode()); result = (prime * result) + (readingSpeed == null ? 0 : readingSpeed.hashCode()); return result; } @@ -60,11 +61,11 @@ public ReadingSpeed getReadingSpeed() { return false; } ActionContextImpl other = (ActionContextImpl) obj; - if (commandSource == null) { - if (other.commandSource != null) { + if (commandCause == null) { + if (other.commandCause != null) { return false; } - } else if (!commandSource.equals(other.commandSource)) { + } else if (!commandCause.equals(other.commandCause)) { return false; } if (readingSpeed == null) { @@ -74,7 +75,7 @@ public ReadingSpeed getReadingSpeed() { } @Override public String toString() { - return "ActionContext[commandSource=" + commandSource + ", readingSpeed=" + readingSpeed + "]"; + return "ActionContext[commandSource=" + commandCause + ", readingSpeed=" + readingSpeed + "]"; } } diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/ActionException.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/ActionException.java index 3973c96f..54e64f21 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/ActionException.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/ActionException.java @@ -18,28 +18,39 @@ */ package ch.vorburger.minecraft.storeys.japi.impl.actions; -import ch.vorburger.minecraft.storeys.japi.util.Texts; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.util.TextMessageException; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.NamedTextColor; -public class ActionException extends TextMessageException { +public class ActionException extends Exception { private static final long serialVersionUID = 6261204063265579413L; + private final TextComponent message; - public ActionException(Text message) { - super(message); + public ActionException(TextComponent message) { + this.message = (message); } - public ActionException(Text message, Throwable throwable) { - super(message, throwable); + public ActionException(TextComponent message, Throwable throwable) { + super(throwable); + this.message = message; } public ActionException(String message) { - this(Texts.inRed(message)); + this(Component.text(message).color(NamedTextColor.RED)); } public ActionException(String message, Throwable throwable) { - this(Texts.inRed(message), throwable); + this(Component.text(message).color(NamedTextColor.RED), throwable); + } + + public String getMessage() { + TextComponent message = getText(); + return message == null ? null : message.content(); + } + + public TextComponent getText() { + return this.message; } } diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/ActionWaitHelper.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/ActionWaitHelper.java index 22f5770e..2d4bcb25 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/ActionWaitHelper.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/ActionWaitHelper.java @@ -20,18 +20,18 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import javax.inject.Inject; import org.spongepowered.api.scheduler.Task; +import org.spongepowered.plugin.PluginContainer; public class ActionWaitHelper { - private final PluginInstance plugin; + private final PluginContainer plugin; - @Inject public ActionWaitHelper(PluginInstance plugin) { + @Inject public ActionWaitHelper(PluginContainer plugin) { this.plugin = plugin; } @@ -39,7 +39,7 @@ public CompletionStage executeAndWait(int msToWaitAfterRunning, Callable< CompletableFuture future = new CompletableFuture<>(); try { T returnValue = callable.call(); - Task.builder().async().execute(() -> future.complete(returnValue)).delay(msToWaitAfterRunning, MILLISECONDS).submit(plugin); + Task.builder().execute(() -> future.complete(returnValue)).delay(msToWaitAfterRunning, MILLISECONDS).plugin(plugin); } catch (Throwable throwable) { future.completeExceptionally(throwable); diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/CommandAction.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/CommandAction.java index 5130e373..360a3fb0 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/CommandAction.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/CommandAction.java @@ -20,15 +20,17 @@ import static java.util.Objects.requireNonNull; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.japi.ActionContext; -import java.util.StringJoiner; import javax.inject.Inject; +import net.kyori.adventure.audience.Audience; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.exception.CommandException; import org.spongepowered.api.scheduler.Scheduler; +import org.spongepowered.api.service.permission.Subject; +import org.spongepowered.plugin.PluginContainer; public class CommandAction extends MainThreadAction { @@ -39,7 +41,7 @@ public class CommandAction extends MainThreadAction { private String commandLineWithoutSlash; - @Inject public CommandAction(PluginInstance plugin, Scheduler scheduler) { + @Inject public CommandAction(PluginContainer plugin, Scheduler scheduler) { super(plugin, scheduler); } @@ -55,23 +57,27 @@ public CommandAction setCommand(String commandLine) { setCommand(param); } - @Override protected CommandResult executeInMainThread(ActionContext context) throws ActionException { - CommandResult result = Sponge.getCommandManager().process(context.getCommandSource(), - requireNonNull(commandLineWithoutSlash, "commandLineWithoutSlash")); - LOG.info("processed command \"/{}\" from source {} with result {}", commandLineWithoutSlash, context.getCommandSource(), - toString(result)); + @Override protected CommandResult executeInMainThread(ActionContext context) { + final CommandResult result; + try { + result = Sponge.server().commandManager().process((Subject & Audience) context.getCommandCause(), + requireNonNull(commandLineWithoutSlash, "commandLineWithoutSlash")); + } catch (CommandException e) { + throw new RuntimeException(e); + } + LOG.info("processed command \"/{}\" from source {} with result {}", commandLineWithoutSlash, context.getCommandCause(), result); return result; } - private String toString(CommandResult result) { - StringJoiner sj = new StringJoiner(", ", "{", "}"); - result.getAffectedBlocks().ifPresent(affectedBlocked -> sj.add("affectedBlocked: " + affectedBlocked)); - result.getAffectedEntities().ifPresent(affectedEntities -> sj.add("affectedEntities: " + affectedEntities)); - result.getAffectedItems().ifPresent(affectedItems -> sj.add("affectedItems: " + affectedItems)); - result.getQueryResult().ifPresent(queryResult -> sj.add("queryResult: " + queryResult)); - result.getSuccessCount().ifPresent(successCount -> sj.add("successCount: " + successCount)); - return sj.toString(); - } + // private String toString(CommandResult result) { + // StringJoiner sj = new StringJoiner(", ", "{", "}"); + // result.getAffectedBlocks().ifPresent(affectedBlocked -> sj.add("affectedBlocked: " + affectedBlocked)); + // result.getAffectedEntities().ifPresent(affectedEntities -> sj.add("affectedEntities: " + affectedEntities)); + // result.getAffectedItems().ifPresent(affectedItems -> sj.add("affectedItems: " + affectedItems)); + // result.getQueryResult().ifPresent(queryResult -> sj.add("queryResult: " + queryResult)); + // result.getSuccessCount().ifPresent(successCount -> sj.add("successCount: " + successCount)); + // return sj.toString(); + // } @Override public String toString() { return getClass().getSimpleName() + ": " + (commandLineWithoutSlash != null ? ("/" + commandLineWithoutSlash) : "null"); diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/MainThreadAction.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/MainThreadAction.java index 9f4b0661..a413c9c4 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/MainThreadAction.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/MainThreadAction.java @@ -18,7 +18,6 @@ */ package ch.vorburger.minecraft.storeys.japi.impl.actions; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.japi.Action; import ch.vorburger.minecraft.storeys.japi.ActionContext; import com.google.common.util.concurrent.ListenableFuture; @@ -27,7 +26,8 @@ import com.spotify.futures.CompletableFuturesExtra; import java.util.concurrent.CompletionStage; import org.spongepowered.api.scheduler.Scheduler; -import org.spongepowered.api.scheduler.SpongeExecutorService; +import org.spongepowered.api.scheduler.TaskExecutorService; +import org.spongepowered.plugin.PluginContainer; /** * Action which must run on the Game's main thread. Any actions that interact @@ -39,8 +39,8 @@ public abstract class MainThreadAction implements Action { private final ListeningScheduledExecutorService guavaifiedMinecraftExecutor; - protected MainThreadAction(PluginInstance plugin, Scheduler scheduler) { - SpongeExecutorService minecraftExecutor = scheduler.createSyncExecutor(plugin); + protected MainThreadAction(PluginContainer plugin, Scheduler scheduler) { + TaskExecutorService minecraftExecutor = scheduler.executor(plugin); guavaifiedMinecraftExecutor = MoreExecutors.listeningDecorator(minecraftExecutor); } diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/NamedObjects.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/NamedObjects.java index 926545b8..d6bd588b 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/NamedObjects.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/NamedObjects.java @@ -18,14 +18,13 @@ */ package ch.vorburger.minecraft.storeys.japi.impl.actions; -import static org.spongepowered.api.data.key.Keys.DISPLAY_NAME; - import java.util.Collection; import java.util.Optional; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongepowered.api.entity.Entity; -import org.spongepowered.api.world.extent.EntityUniverse; +import org.spongepowered.api.world.volume.entity.EntityVolume; public class NamedObjects { @@ -40,9 +39,9 @@ public class NamedObjects { private static final Logger LOG = LoggerFactory.getLogger(NamedObjects.class); - public Optional getEntity(EntityUniverse entityUniverse, String entityName) { - Collection entities = entityUniverse - .getEntities(entity -> entity.get(DISPLAY_NAME).filter(name -> entityName.equals(name.toPlain())).isPresent()); + public Optional getEntity(EntityVolume.Modifiable entityUniverse, String entityName) { + Collection entities = entityUniverse.entities().stream().filter(entity -> entityName.equals(entity.displayName().toString())).collect( + Collectors.toList()); // entities.removeIf(entity -> entity instanceof Player); if (entities.isEmpty()) { return Optional.empty(); diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/NarrateAction.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/NarrateAction.java index b3ff2f73..1c1469df 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/NarrateAction.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/NarrateAction.java @@ -26,7 +26,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; -import org.spongepowered.api.text.Text; +import net.kyori.adventure.text.Component; import org.spongepowered.api.world.Locatable; import org.spongepowered.api.world.World; @@ -55,15 +55,15 @@ public NarrateAction setEntity(String entityName) { } @Override public CompletionStage execute(ActionContext context) { - Locatable locatable = (Locatable) context.getCommandSource(); - World world = locatable.getWorld(); + Locatable locatable = (Locatable) context.getCommandCause(); + final World world = locatable.world(); - return narrator.narrate(world, requireNonNull(entityName, "entityName"), getText().toPlain(), context.getReadingSpeed()); + return narrator.narrate(world, requireNonNull(entityName, "entityName"), getText().content(), context.getReadingSpeed()); } @Override public boolean add(Action action) { if (action instanceof TextAction) { - this.setText(getText().concat(Text.NEW_LINE).concat(((TextAction) action).getText())); + this.setText(getText().append(Component.newline()).append(((TextAction) action).getText())); return true; } return false; diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/Narrator.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/Narrator.java index 75cfc455..f7295a5f 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/Narrator.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/Narrator.java @@ -19,21 +19,20 @@ package ch.vorburger.minecraft.storeys.japi.impl.actions; import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static org.spongepowered.api.data.key.Keys.CUSTOM_NAME_VISIBLE; -import static org.spongepowered.api.data.key.Keys.DISPLAY_NAME; +import static org.spongepowered.api.data.Keys.DISPLAY_NAME; +import static org.spongepowered.api.data.Keys.IS_CUSTOM_NAME_VISIBLE; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.japi.ReadingSpeed; import java.util.Iterator; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; -import java.util.function.Consumer; import javax.inject.Inject; +import net.kyori.adventure.text.Component; +import org.spongepowered.api.data.value.Value; import org.spongepowered.api.entity.Entity; import org.spongepowered.api.scheduler.Task; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.world.extent.EntityUniverse; +import org.spongepowered.api.world.volume.entity.EntityVolume; +import org.spongepowered.plugin.PluginContainer; public class Narrator { @@ -41,17 +40,17 @@ public class Narrator { private final NamedObjects namedObjects = new NamedObjects(); - private final PluginInstance plugin; + private final PluginContainer plugin; private final TextSplitter splitter = new TextSplitter(); private final int maxLength = 20; - @Inject public Narrator(PluginInstance plugin) { + @Inject public Narrator(PluginContainer plugin) { super(); this.plugin = plugin; } - public CompletionStage narrate(EntityUniverse entityUniverse, String entityName, String text, ReadingSpeed readingSpeed) { + public CompletionStage narrate(EntityVolume.Modifiable entityUniverse, String entityName, String text, ReadingSpeed readingSpeed) { Entity entity = namedObjects.getEntity(entityUniverse, entityName) .orElseThrow(() -> new IllegalArgumentException("No entity named: " + entityName)); return narrate(entity, text, readingSpeed); @@ -61,17 +60,17 @@ public CompletionStage narrate(Entity entity, String text, ReadingSpeed re CompletableFuture future = new CompletableFuture<>(); Task.builder().execute(new NarratorTask(entity, splitter.split(maxLength, text), future)) - .interval(readingSpeed.msToRead(maxLength), MILLISECONDS).submit(plugin); + .interval(readingSpeed.msToRead(maxLength), MILLISECONDS).plugin(plugin); return future; } - private static class NarratorTask implements Consumer { + private static class NarratorTask implements Runnable { private final Entity entity; private final Iterator splitText; private final CompletableFuture future; - private final Optional originalDisplayName; + private final Value.Mutable originalDisplayName; public NarratorTask(Entity entity, Iterable splitText, CompletableFuture future) { this.entity = entity; @@ -79,20 +78,20 @@ public NarratorTask(Entity entity, Iterable splitText, CompletableFuture this.future = future; // Make sure name can always be seen, even if we are not closely look at entity - entity.offer(CUSTOM_NAME_VISIBLE, true); + entity.offer(IS_CUSTOM_NAME_VISIBLE, true); - originalDisplayName = entity.get(DISPLAY_NAME); + originalDisplayName = entity.displayName(); } - @Override public void accept(Task task) { + @Override public void run() { if (splitText.hasNext()) { - entity.offer(DISPLAY_NAME, Text.of(splitText.next())); + entity.offer(DISPLAY_NAME, Component.text(splitText.next())); } else { - entity.offer(CUSTOM_NAME_VISIBLE, false); + entity.offer(IS_CUSTOM_NAME_VISIBLE, false); // Must reset name, so that NamedObjects can find Entity again next time (after restart) - entity.offer(DISPLAY_NAME, originalDisplayName.orElse(Text.EMPTY)); + entity.offer(DISPLAY_NAME, originalDisplayName.get()); future.complete(null); - task.cancel(); + // task.cancel(); } } } diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/TextAction.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/TextAction.java index 8669423c..95d17010 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/TextAction.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/TextAction.java @@ -21,29 +21,30 @@ import static java.util.Objects.requireNonNull; import ch.vorburger.minecraft.storeys.japi.Action; -import org.spongepowered.api.text.Text; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; public abstract class TextAction implements Action { - private Text text; + private TextComponent text; protected TextAction() { } - public Text getText() { + public TextComponent getText() { return requireNonNull(text, "text"); } - public TextAction setText(Text text) { + public TextAction setText(TextComponent text) { this.text = text; return this; } @Override public void setParameter(String param) { if (text == null) { - text = Text.of(param); + text = Component.text().content(param).build(); } else { - text = text.concat(Text.NEW_LINE).concat(Text.of(param)); + text = text.append(Component.newline().content(param)); } } diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/TitleAction.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/TitleAction.java index cb1e53fe..d419e2fb 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/TitleAction.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/actions/TitleAction.java @@ -22,25 +22,23 @@ import ch.vorburger.minecraft.storeys.japi.Action; import ch.vorburger.minecraft.storeys.japi.ActionContext; +import java.time.Duration; import java.util.concurrent.CompletionStage; import javax.inject.Inject; -import org.spongepowered.api.command.CommandSource; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.title.Title; import org.spongepowered.api.effect.Viewer; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.title.Title; -import org.spongepowered.api.text.title.Title.Builder; public class TitleAction extends TextAction { private static final int FADE_IN_MS = 50; - private static final int FADE_IN_TICKS = (int) (FADE_IN_MS * 0.02); - private static final int FADE_OUT_MS = 100; - private static final int FADE_OUT_TICKS = (int) (FADE_OUT_MS * 0.02); private final ActionWaitHelper actionWaitHelper; - private Text subtitleText; + private TextComponent subtitleText; @Inject public TitleAction(ActionWaitHelper helper) { this.actionWaitHelper = helper; @@ -52,30 +50,28 @@ public class TitleAction extends TextAction { super.setParameter(trimCRLF(param)); } else { super.setParameter(trimCRLF(parts[0])); - subtitleText = Text.of(trimCRLF(parts[1].trim())); + subtitleText = Component.text(trimCRLF(parts[1].trim())); } } @Override public CompletionStage execute(ActionContext context) { - Text bothTexts = getText().concat(subtitleText != null ? subtitleText : Text.EMPTY); + TextComponent bothTexts = getText().append(subtitleText != null ? subtitleText : Component.empty()); int msToRead = context.getReadingSpeed().msToRead(bothTexts) + FADE_IN_MS + FADE_OUT_MS; return actionWaitHelper.executeAndWait(msToRead, () -> { - CommandSource commandSource = context.getCommandSource(); - if (commandSource instanceof Viewer) { - Viewer srcAsViewer = (Viewer) commandSource; + final Audience commandCause = context.getCommandCause(); + if (commandCause instanceof Viewer) { + Viewer srcAsViewer = (Viewer) commandCause; - Builder titleBuilder = Title.builder().fadeIn(FADE_IN_TICKS).stay((int) (msToRead * 0.02)).fadeOut(FADE_OUT_TICKS); - titleBuilder.title(getText()); - if (subtitleText != null) { - titleBuilder.subtitle(subtitleText); - } + final Title.Times times = Title.Times.times(Duration.ofMillis(FADE_IN_MS), Duration.ofMillis(msToRead), + Duration.ofMillis(FADE_OUT_MS)); + Title titleBuilder = Title.title(getText(), subtitleText != null ? subtitleText : Component.empty(), times); // TODO srcAsViewer.clearTitle(); ? - srcAsViewer.sendTitle(titleBuilder.build()); + srcAsViewer.showTitle(titleBuilder); return null; } else { - throw new ActionException("CommandSource is not a Viewer: " + commandSource.toString()); + throw new ActionException("CommandSource is not a Viewer: " + commandCause.toString()); } }); } diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/events/EventService.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/events/EventService.java index 6e4cbda0..8d414a1b 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/events/EventService.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/impl/events/EventService.java @@ -18,7 +18,6 @@ */ package ch.vorburger.minecraft.storeys.japi.impl.events; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.japi.PlayerInsideEvent; import ch.vorburger.minecraft.storeys.japi.impl.Unregisterable; import java.util.Collection; @@ -29,16 +28,17 @@ import java.util.concurrent.ConcurrentLinkedQueue; import javax.inject.Inject; import javax.inject.Singleton; +import net.kyori.adventure.text.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.spongepowered.api.data.key.Keys; +import org.spongepowered.api.data.Keys; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.EventManager; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.entity.InteractEntityEvent; import org.spongepowered.api.event.item.inventory.ChangeInventoryEvent; -import org.spongepowered.api.event.network.ClientConnectionEvent.Join; -import org.spongepowered.api.text.Text; +import org.spongepowered.api.event.network.ServerSideConnectionEvent; +import org.spongepowered.plugin.PluginContainer; @Singleton public class EventService implements AutoCloseable { @@ -47,7 +47,7 @@ private final Collection onPlayerJoinCallbacks = new ConcurrentLinkedQueue<>(); private final Map> onPlayerInsideCallbacks = new ConcurrentHashMap<>(); - private final Map> onInteractEntityEventCallbacks = new ConcurrentHashMap<>(); + private final Map> onInteractEntityEventCallbacks = new ConcurrentHashMap<>(); private final EventManager eventManager; @@ -56,17 +56,17 @@ } // @Inject PluginInstance cannot work, so we use explicit "setter injection" - public void setPluginInstance(PluginInstance plugin) { - eventManager.registerListeners(plugin, this); + public void setPluginContainer(PluginContainer pluginContainer) { + eventManager.registerListeners(pluginContainer, this); // TODO InteractItemEvent ? } @Override public void close() throws Exception { } - @Listener public void onPlayerJoin(Join event) throws Exception { + @Listener public void onPlayerJoin(ServerSideConnectionEvent.Join event) throws Exception { for (Callback callback : onPlayerJoinCallbacks) { - callback.call(event.getTargetEntity()); + callback.call(event.player()); } } @@ -87,12 +87,11 @@ public Unregisterable registerPlayerJoin(Callback callback) { } public Unregisterable registerInsideLocation(String locationName, Callback callback) { - Collection callbacks = onPlayerInsideCallbacks.computeIfAbsent(locationName, - name -> new ConcurrentLinkedQueue<>()); + Collection callbacks = onPlayerInsideCallbacks.computeIfAbsent(locationName, name -> new ConcurrentLinkedQueue<>()); return add(callbacks, callback); } - public Unregisterable registerInteractEntity(String entityName, Callback callback) { + public Unregisterable registerInteractEntity(Component entityName, Callback callback) { Collection callbacks = onInteractEntityEventCallbacks.computeIfAbsent(entityName, name -> new ConcurrentLinkedQueue<>()); return add(callbacks, callback); } @@ -106,13 +105,14 @@ private Unregisterable add(Collection collection, Callback callback) { @Listener public void onInteractEntityEvent(InteractEntityEvent event) { // TODO This is bad, it means that entities are only recognized by name if they are not narrating.. - Optional optEntityNameText = event.getTargetEntity().get(Keys.DISPLAY_NAME); + Optional optEntityNameText = event.entity().get(Keys.DISPLAY_NAME); LOG.debug("InteractEntityEvent: entityName={}; event={}", optEntityNameText, event); optEntityNameText.ifPresent(entityNameText -> { - Collection callbacks = onInteractEntityEventCallbacks.getOrDefault(entityNameText.toPlain(), Collections.emptySet()); + Collection callbacks = onInteractEntityEventCallbacks.getOrDefault(entityNameText, + Collections.emptySet()); for (Callback callback : callbacks) { try { - callback.call(event.getCause().last(Player.class).orElse(null)); + callback.call(event.cause().last(Player.class).orElse(null)); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/util/CommandExceptions.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/util/CommandExceptions.java index 1e0aaf73..36508e9f 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/util/CommandExceptions.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/util/CommandExceptions.java @@ -21,7 +21,7 @@ import java.util.concurrent.Callable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.exception.CommandException; /** * Utilities for {@link CommandException}. diff --git a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/util/Texts.java b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/util/Texts.java index 21c14cbb..2af7d51a 100644 --- a/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/util/Texts.java +++ b/api-jvm-impl/src/main/java/ch/vorburger/minecraft/storeys/japi/util/Texts.java @@ -18,11 +18,12 @@ */ package ch.vorburger.minecraft.storeys.japi.util; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.format.TextColors; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.NamedTextColor; /** - * Utilities for {@link Text}. + * Utilities for {@link TextComponent}. * * @author Michael Vorburger.ch */ @@ -33,14 +34,14 @@ public final class Texts { private Texts() { } - public static Text fromThrowable(String prefix, Throwable throwable) { + public static TextComponent fromThrowable(String prefix, Throwable throwable) { // TODO have a Player isDeveloper flag (or Permission, probably..) // developers get to see the cause stack trace? ;) Noob do not. - return Text.builder().color(TextColors.RED).append(Text.of(prefix + throwable.getMessage())).build(); + return Component.text().color(NamedTextColor.RED).content(prefix + throwable.getMessage()).build(); // TODO add StackTrace here - with links being able to click on to jump into sources!!! } - public static Text inRed(String content) { - return Text.builder().color(TextColors.RED).append(Text.of(content)).build(); + public static TextComponent inRed(String content) { + return Component.text().color(NamedTextColor.RED).content(content).build(); } } diff --git a/api-jvm/src/main/java/ch/vorburger/minecraft/storeys/japi/ActionContext.java b/api-jvm/src/main/java/ch/vorburger/minecraft/storeys/japi/ActionContext.java index dcc61de8..e11d2bf4 100644 --- a/api-jvm/src/main/java/ch/vorburger/minecraft/storeys/japi/ActionContext.java +++ b/api-jvm/src/main/java/ch/vorburger/minecraft/storeys/japi/ActionContext.java @@ -18,11 +18,11 @@ */ package ch.vorburger.minecraft.storeys.japi; -import org.spongepowered.api.command.CommandSource; +import net.kyori.adventure.audience.Audience; public interface ActionContext { - CommandSource getCommandSource(); + Audience getCommandCause(); ReadingSpeed getReadingSpeed(); } diff --git a/api-jvm/src/main/java/ch/vorburger/minecraft/storeys/japi/PlayerInsideEvent.java b/api-jvm/src/main/java/ch/vorburger/minecraft/storeys/japi/PlayerInsideEvent.java index 9efc61a4..4365d201 100644 --- a/api-jvm/src/main/java/ch/vorburger/minecraft/storeys/japi/PlayerInsideEvent.java +++ b/api-jvm/src/main/java/ch/vorburger/minecraft/storeys/japi/PlayerInsideEvent.java @@ -20,7 +20,7 @@ import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.Cancellable; -import org.spongepowered.api.event.cause.Cause; +import org.spongepowered.api.event.Cause; import org.spongepowered.api.event.impl.AbstractEvent; public class PlayerInsideEvent extends AbstractEvent implements Cancellable { @@ -35,7 +35,7 @@ public PlayerInsideEvent(Player player, String locationName, Cause cause) { this.cause = cause; } - @Override public Cause getCause() { + @Override public Cause cause() { return cause; } diff --git a/api-jvm/src/main/java/ch/vorburger/minecraft/storeys/japi/ReadingSpeed.java b/api-jvm/src/main/java/ch/vorburger/minecraft/storeys/japi/ReadingSpeed.java index dc84a64a..c40d9cbf 100644 --- a/api-jvm/src/main/java/ch/vorburger/minecraft/storeys/japi/ReadingSpeed.java +++ b/api-jvm/src/main/java/ch/vorburger/minecraft/storeys/japi/ReadingSpeed.java @@ -18,7 +18,7 @@ */ package ch.vorburger.minecraft.storeys.japi; -import org.spongepowered.api.text.Text; +import net.kyori.adventure.text.TextComponent; public class ReadingSpeed { @@ -43,11 +43,11 @@ public ReadingSpeed by(double factor) { return new ReadingSpeed((int) (wpm * factor)); } - public int msToRead(Text text) { + public int msToRead(TextComponent text) { // This could be optimized, e.g. to skip long URLs, // which one does not typically fully read, like real text; // but at least for, we can just do this: - return msToRead(text.toPlain()); + return msToRead(text.content()); } public int msToRead(String text) { diff --git a/build.gradle b/build.gradle index 7f135b5c..5ebb3c55 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,7 @@ subprojects { // errorprone 'com.google.errorprone:error_prone_core:2.3.1' // implementation 'com.google.errorprone:error_prone_annotations:2.3.1' - implementation('org.spongepowered:spongeapi:7.3.0') { + implementation('org.spongepowered:spongeapi:8.1.0') { exclude group: 'com.google.guava' exclude group: 'com.google.inject' exclude group: 'com.google.code.gson' diff --git a/example/src/main/java/ch/vorburger/minecraft/storeys/example/ExampleScript.java b/example/src/main/java/ch/vorburger/minecraft/storeys/example/ExampleScript.java index 6bc01fd2..593f7d3d 100644 --- a/example/src/main/java/ch/vorburger/minecraft/storeys/example/ExampleScript.java +++ b/example/src/main/java/ch/vorburger/minecraft/storeys/example/ExampleScript.java @@ -21,6 +21,7 @@ import ch.vorburger.minecraft.storeys.japi.Events; import ch.vorburger.minecraft.storeys.japi.Script; import org.spongepowered.api.item.ItemTypes; +import org.spongepowered.api.item.inventory.ItemStack; /** * Example Script. @@ -41,7 +42,7 @@ public class ExampleScript implements Script { }); e.whenCommand("another", m -> { m.title("Namaste. Curry pour tous!"); - if (!m.player().getInventory().contains(ItemTypes.FISHING_ROD)) { + if (!m.player().inventory().contains(ItemStack.of(ItemTypes.FISHING_ROD))) { m.cmd("/say There may be a fishing rod hidden somewhere… look for it, and then catch a fish!"); } else { m.cmd("/say Go fishing with the rod in your inventory.."); diff --git a/storeys/build.gradle b/storeys/build.gradle index 61422d79..cee19827 100644 --- a/storeys/build.gradle +++ b/storeys/build.gradle @@ -6,8 +6,9 @@ repositories { dependencies { api project(':api-jvm-impl') - api 'ch.vorburger.minecraft.osgi:api:1.0.0' implementation 'ch.vorburger:fswatch:1.3.0' + implementation 'org.graalvm.js:js-scriptengine:22.3.0' + runtimeOnly 'org.graalvm.js:js:22.3.0' implementation project(':example') testImplementation project(':test-utils') diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/ScriptsLoader.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/ScriptsLoader.java index 984b2546..bc1a31b3 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/ScriptsLoader.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/ScriptsLoader.java @@ -31,8 +31,11 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; +import java.util.function.Predicate; import javax.inject.Inject; import javax.inject.Singleton; +import javax.script.Bindings; +import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; @@ -64,8 +67,6 @@ LOG.info("(Re-)loaded {}", path); } catch (NoSuchFileException e) { // Ignore (happens frequently for temporary files with Git) - } catch (jdk.nashorn.api.scripting.NashornException n) { - LOG.warn("Invalid JS: {}:{}:{} {}", path, n.getLineNumber(), n.getColumnNumber(), n.getMessage()); } catch (RuntimeException e) { LOG.error("Failed to register due to an unknown cause {}", path, e); } @@ -93,7 +94,10 @@ private Script load(Path file) throws IOException, ScriptException { final String result = template.replace("//SCRIPT", scriptFile); ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("JavaScript"); + ScriptEngine engine = manager.getEngineByName("graal.js"); + Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); + bindings.put("polyglot.js.allowHostAccess", true); + bindings.put("polyglot.js.allowHostClassLookup", (Predicate) s -> true); return (Script) engine.eval(result); } diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/commands/NarrateCommand.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/commands/NarrateCommand.java index 3cce5c5f..00b8917d 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/commands/NarrateCommand.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/commands/NarrateCommand.java @@ -18,31 +18,21 @@ */ package ch.vorburger.minecraft.storeys.commands; -import static org.spongepowered.api.command.args.GenericArguments.onlyOne; -import static org.spongepowered.api.command.args.GenericArguments.remainingJoinedStrings; -import static org.spongepowered.api.text.Text.of; - import ch.vorburger.minecraft.storeys.japi.ReadingSpeed; import ch.vorburger.minecraft.storeys.japi.impl.actions.Narrator; import ch.vorburger.minecraft.storeys.util.Command; -import com.google.common.collect.ImmutableList; -import java.util.List; import javax.inject.Inject; -import org.spongepowered.api.command.CommandCallable; -import org.spongepowered.api.command.CommandException; +import net.kyori.adventure.text.Component; import org.spongepowered.api.command.CommandResult; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.args.CommandContext; -import org.spongepowered.api.command.args.GenericArguments; -import org.spongepowered.api.command.spec.CommandSpec; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.world.Locatable; -import org.spongepowered.api.world.extent.EntityUniverse; +import org.spongepowered.api.command.exception.CommandException; +import org.spongepowered.api.command.parameter.CommandContext; +import org.spongepowered.api.command.parameter.Parameter; +import org.spongepowered.api.world.server.ServerWorld; public class NarrateCommand implements Command { - private static final Text ARG_ENTITY = of("entity"); - private static final Text ARG_TEXT = of("text"); + private static final Parameter.Value ARG_ENTITY = Parameter.string().key("storyName").build(); + private static final Parameter.Value ARG_TEXT = Parameter.string().key("text").build(); private final Narrator narrator; @@ -50,32 +40,31 @@ public class NarrateCommand implements Command { this.narrator = narrator; } - @Override public List aliases() { - return ImmutableList.of("narrate"); + @Override public String getName() { + return "narrate"; } - @Override public CommandCallable callable() { - return CommandSpec.builder().description(Text.of("Make an entity character narrate story lines")) + @Override public org.spongepowered.api.command.Command.Parameterized createCommand() { + // TODO when Sponge uses entity names instead of UUIDs: + // TODO requiringPermission() + return org.spongepowered.api.command.Command.builder().shortDescription(Component.text(("Make an entity character narrate story lines"))) // .permission("storeys.commands.narrate") ? - .arguments( - // TODO when Sponge uses entity names instead of UUIDs: - // onlyOne(entity(ARG_ENTITY)), // TODO requiringPermission() - onlyOne(GenericArguments.string(ARG_ENTITY)), // TODO requiringPermission() - remainingJoinedStrings(ARG_TEXT) // remainingRawJoinedStrings ? - ).executor(this).build(); + .addParameter(ARG_ENTITY).addParameter(ARG_TEXT).executor(this).build(); + } - @Override public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { - String text = args.getOne(ARG_TEXT).get(); + @Override public CommandResult execute(CommandContext args) throws CommandException { + String text = args.one(ARG_TEXT).get(); // TODO when Sponge uses entity names instead of UUIDs: // Entity entity = args.getOne(ARG_ENTITY).get(); // narrator.narrate(entity, text, new ReadingSpeed()); - String entityName = args.getOne(ARG_ENTITY).get(); - EntityUniverse world = ((Locatable) src).getWorld(); + String entityName = args.one(ARG_ENTITY).get(); + final ServerWorld world = args.cause().location().get().world(); narrator.narrate(world, entityName, text, new ReadingSpeed()); return CommandResult.success(); } + } diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/commands/StoryCommand.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/commands/StoryCommand.java index 3c5ebf48..b7bdddc4 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/commands/StoryCommand.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/commands/StoryCommand.java @@ -18,10 +18,6 @@ */ package ch.vorburger.minecraft.storeys.commands; -import static org.spongepowered.api.command.args.GenericArguments.onlyOne; -import static org.spongepowered.api.command.args.GenericArguments.string; -import static org.spongepowered.api.text.Text.of; - import ch.vorburger.minecraft.storeys.japi.ReadingSpeed; import ch.vorburger.minecraft.storeys.japi.impl.actions.ActionContextImpl; import ch.vorburger.minecraft.storeys.japi.impl.actions.ActionPlayer; @@ -31,22 +27,18 @@ import ch.vorburger.minecraft.storeys.model.parser.StoryParser; import ch.vorburger.minecraft.storeys.model.parser.StoryRepository; import ch.vorburger.minecraft.storeys.util.Command; -import com.google.common.collect.ImmutableList; import java.io.File; import java.nio.file.Path; -import java.util.List; import javax.inject.Inject; -import org.spongepowered.api.command.CommandCallable; -import org.spongepowered.api.command.CommandException; +import net.kyori.adventure.text.Component; import org.spongepowered.api.command.CommandResult; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.args.CommandContext; -import org.spongepowered.api.command.spec.CommandSpec; -import org.spongepowered.api.text.Text; +import org.spongepowered.api.command.exception.CommandException; +import org.spongepowered.api.command.parameter.CommandContext; +import org.spongepowered.api.command.parameter.Parameter; public class StoryCommand implements Command { - private static final Text ARG_STORY = of("storyName"); + private static final Parameter.Value STORY_NAME = Parameter.string().key("storyName").build(); private final StoryRepository storyRepository; private final StoryParser storyParser; @@ -62,25 +54,25 @@ public class StoryCommand implements Command { this.storyPlayer = storyPlayer; } - @Override public List aliases() { - return ImmutableList.of("story"); + @Override public String getName() { + return "story"; } - @Override public CommandCallable callable() { - return CommandSpec.builder().description(of("Tell a story")) + @Override public org.spongepowered.api.command.Command.Parameterized createCommand() { + return org.spongepowered.api.command.Command.builder().shortDescription(Component.text("Tell a story")) // .permission("storeys.commands.story") ? - .arguments(onlyOne(string(ARG_STORY)) // TODO requiringPermission() - ).executor(this).build(); + .addParameter(STORY_NAME) // TODO requiringPermission() + .executor(this).build(); } - @Override public CommandResult execute(CommandSource commandSource, CommandContext commandContext) throws CommandException { - String storyName = commandContext.getOne(ARG_STORY).get(); + @Override public CommandResult execute(CommandContext commandContext) throws CommandException { + String storyName = commandContext.requireOne(STORY_NAME); CommandExceptions.doOrThrow("Failed to load & play '" + storyName + "' story, due to: ", () -> { String storyScript = storyRepository.getStoryScript(storyName); Story story = storyParser.parse(storyScript); /* CompletionStage completionStage = storyPlayer.play(..) */ // TODO keep this, so that a user can /stop the story again.. - storyPlayer.play(new ActionContextImpl(commandSource, new ReadingSpeed()), story.getActionsList()); + storyPlayer.play(new ActionContextImpl(commandContext.cause().audience(), new ReadingSpeed()), story.getActionsList()); }); return CommandResult.success(); diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/events/ConditionService.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/events/ConditionService.java index bece2c6b..104f0a38 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/events/ConditionService.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/events/ConditionService.java @@ -20,14 +20,15 @@ import static java.util.Objects.requireNonNull; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.japi.impl.Unregisterable; import ch.vorburger.minecraft.storeys.japi.impl.events.Callback; import com.google.common.annotations.VisibleForTesting; +import java.util.Optional; import java.util.Set; +import java.util.UUID; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; import javax.inject.Inject; import javax.inject.Singleton; @@ -35,11 +36,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.scheduler.ScheduledTask; +import org.spongepowered.api.scheduler.Scheduler; import org.spongepowered.api.scheduler.Task; +import org.spongepowered.plugin.PluginContainer; -@ThreadSafe -@Singleton -public class ConditionService implements AutoCloseable { +@ThreadSafe @Singleton public class ConditionService implements AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(ConditionService.class); @@ -86,21 +88,23 @@ private ConditionServiceRegistration(Triple } private final Set> checks = new CopyOnWriteArraySet<>(); - private final @Nullable Task task; + private final Scheduler scheduler; + private final UUID taskId; - @Inject public ConditionService(PluginInstance plugin) { - task = Task.builder().execute(this::run).intervalTicks(10).name(getClass().getSimpleName()) - .submit(requireNonNull(plugin, "plugin")); + @Inject public ConditionService(PluginContainer plugin, Scheduler scheduler) { + Task task = Task.builder().execute(this::run).interval(10, TimeUnit.SECONDS).plugin(plugin).build(); + this.scheduler = scheduler; + taskId = scheduler.submit(task).uniqueId(); } @VisibleForTesting ConditionService() { - task = null; + scheduler = null; + taskId = UUID.randomUUID(); } @Override public void close() { - if (task != null) { - task.cancel(); - } + final Optional scheduledTask = scheduler.findTask(taskId); + scheduledTask.ifPresent(ScheduledTask::cancel); } public ConditionServiceRegistration register(Condition condition, Callback callback) { diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/events/LocatableInBoxCondition.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/events/LocatableInBoxCondition.java index 9032bb42..0e4ed74c 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/events/LocatableInBoxCondition.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/events/LocatableInBoxCondition.java @@ -18,7 +18,7 @@ */ package ch.vorburger.minecraft.storeys.events; -import static java.lang.Integer.parseInt; +import static java.lang.Double.parseDouble; import static java.lang.Math.max; import static java.lang.Math.min; import static java.util.Objects.requireNonNull; @@ -27,8 +27,8 @@ import java.util.Iterator; import org.apache.commons.lang3.tuple.Pair; import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.world.Location; -import org.spongepowered.api.world.World; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; public class LocatableInBoxCondition implements Condition { @@ -36,52 +36,52 @@ public class LocatableInBoxCondition implements Condition { private Player effectedPlayer; - private final World world; - private final int minX, maxX, minY, maxY, minZ, maxZ; + private final ServerWorld world; + private final double minX, maxX, minY, maxY, minZ, maxZ; - public LocatableInBoxCondition(World world, Location boxCorner1, Location boxCorner2) { + public LocatableInBoxCondition(ServerWorld world, ServerLocation boxCorner1, ServerLocation boxCorner2) { this.world = requireNonNull(world, "world"); - if (!boxCorner1.inExtent(boxCorner2.getExtent())) { + if (!boxCorner1.inWorld(boxCorner2.world())) { throw new IllegalArgumentException("boxCorner1 & boxCorner2 are not in the same World Extent"); } - if (!boxCorner1.inExtent(this.world)) { + if (!boxCorner1.inWorld(this.world)) { throw new IllegalArgumentException("boxCorner is not in the same World Extent as Locatable (Player)"); } - minX = min(boxCorner1.getBlockX(), boxCorner2.getBlockX()); - maxX = max(boxCorner1.getBlockX(), boxCorner2.getBlockX()); - minY = min(boxCorner1.getBlockY(), boxCorner2.getBlockY()); - maxY = max(boxCorner1.getBlockY(), boxCorner2.getBlockY()); - minZ = min(boxCorner1.getBlockZ(), boxCorner2.getBlockZ()); - maxZ = max(boxCorner1.getBlockZ(), boxCorner2.getBlockZ()); + minX = min(boxCorner1.x(), boxCorner2.x()); + maxX = max(boxCorner1.x(), boxCorner2.x()); + minY = min(boxCorner1.y(), boxCorner2.y()); + maxY = max(boxCorner1.y(), boxCorner2.y()); + minZ = min(boxCorner1.z(), boxCorner2.z()); + maxZ = max(boxCorner1.z(), boxCorner2.z()); } - public LocatableInBoxCondition(World world, String coordinates) { + public LocatableInBoxCondition(ServerWorld world, String coordinates) { this(getCornerLocations(world, coordinates)); } - public LocatableInBoxCondition(Pair, Location> corners) { - this(corners.getLeft().getExtent(), corners.getLeft(), corners.getRight()); + public LocatableInBoxCondition(Pair corners) { + this(corners.getLeft().world(), corners.getLeft(), corners.getRight()); } - private static Pair, Location> getCornerLocations(World world, String coordinates) { + private static Pair getCornerLocations(ServerWorld world, String coordinates) { Iterator ints = SLASH_SPLITTER.split(coordinates).iterator(); - Location cornerA = new Location<>(world, parseInt(ints.next()), parseInt(ints.next()), parseInt(ints.next())); - Location cornerB = new Location<>(world, parseInt(ints.next()), parseInt(ints.next()), parseInt(ints.next())); + ServerLocation cornerA = ServerLocation.of(world, parseDouble(ints.next()), parseDouble(ints.next()), parseDouble(ints.next())); + ServerLocation cornerB = ServerLocation.of(world, parseDouble(ints.next()), parseDouble(ints.next()), parseDouble(ints.next())); return Pair.of(cornerA, cornerB); } @Override public boolean isHot() { - for (Player player : this.world.getPlayers()) { - final Location location = player.getLocation(); - if (location.inExtent(world)) { - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); + for (Player player : this.world.players()) { + final ServerLocation location = player.serverLocation(); + if (location.inWorld(world)) { + double x = location.x(); + double y = location.y(); + double z = location.z(); boolean hit = x >= minX && x <= maxX && y >= minY && y <= maxY && z >= minZ && z <= maxZ; if (hit) { this.effectedPlayer = player; - return hit; } + return hit; } } return false; diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/guard/GuardGameModeJoinListener.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/guard/GuardGameModeJoinListener.java index 3c9adade..4b3f40d0 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/guard/GuardGameModeJoinListener.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/guard/GuardGameModeJoinListener.java @@ -20,28 +20,29 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.spongepowered.api.data.key.Keys; -import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.data.Keys; import org.spongepowered.api.entity.living.player.gamemode.GameMode; import org.spongepowered.api.entity.living.player.gamemode.GameModes; -import org.spongepowered.api.event.EventListener; -import org.spongepowered.api.event.network.ClientConnectionEvent.Join; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.network.ServerSideConnectionEvent.Join; +import org.spongepowered.api.registry.DefaultedRegistryReference; /** * Listener which sets player game mode based on permission (if any) on join. * * @author Michael Vorburger.ch */ -public class GuardGameModeJoinListener implements EventListener { +public class GuardGameModeJoinListener { private static final Logger LOG = LoggerFactory.getLogger(GuardGameModeJoinListener.class); - @Override public void handle(Join joinEvent) throws Exception { - GameMode newGameMode = null; - Player player = joinEvent.getTargetEntity(); + @Listener public void handle(Join joinEvent) throws Exception { + DefaultedRegistryReference newGameMode = null; + ServerPlayer player = joinEvent.player(); // NB: Order and use of if and not else if - because higher permission overrides lower... // But beware that OPS on servers without permissions plugin (such as LuckPerms) have all permissions; - // therefore the last permission must be the one which we wants an OPS to have! + // therefore the last permission must be the one which we want an OPS to have! if (player.hasPermission("storeys.guard.adventure")) { newGameMode = GameModes.ADVENTURE; } @@ -49,8 +50,8 @@ public class GuardGameModeJoinListener implements EventListener { newGameMode = GameModes.CREATIVE; } if (newGameMode != null) { - player.offer(Keys.GAME_MODE, newGameMode); - LOG.info("Setting Player {} game mode to {} due to their storeys.guard.* permissions", player.getName(), newGameMode); + player.offer(Keys.GAME_MODE, newGameMode.get()); + LOG.info("Setting Player {} game mode to {} due to their storeys.guard.* permissions", player.user().name(), newGameMode); } } diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/DynamicAction.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/DynamicAction.java index b91aca91..d492e8ca 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/DynamicAction.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/DynamicAction.java @@ -52,8 +52,8 @@ public class DynamicAction implements Action { CompletableFuture future = new CompletableFuture<>(); ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("JavaScript"); - engine.put("player", context.getCommandSource()); + ScriptEngine engine = manager.getEngineByName("graal.js"); + engine.put("player", context.getCommandCause()); try { String storyText = (String) engine.eval(PREFIX + script + POSTFIX); diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/LocationAction.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/LocationAction.java index e3d8f411..c0a99990 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/LocationAction.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/LocationAction.java @@ -18,16 +18,17 @@ */ package ch.vorburger.minecraft.storeys.model; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.events.ConditionService; import ch.vorburger.minecraft.storeys.events.LocatableInBoxCondition; import ch.vorburger.minecraft.storeys.japi.Action; import ch.vorburger.minecraft.storeys.japi.ActionContext; +import ch.vorburger.minecraft.storeys.plugin.PluginInstance; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import javax.inject.Inject; import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.world.Locatable; +import org.spongepowered.api.scheduler.Scheduler; +import org.spongepowered.api.world.server.ServerLocation; public class LocationAction implements Action { private ConditionService conditionService; @@ -36,8 +37,8 @@ public class LocationAction implements Action { public LocationAction() { } - @Inject public LocationAction(PluginInstance plugin) { - conditionService = new ConditionService(plugin); + @Inject public LocationAction(ConditionService conditionService) { + this.conditionService = conditionService; } @Override public void setParameter(String param) { @@ -47,8 +48,8 @@ public LocationAction() { @Override public CompletionStage execute(ActionContext context) { CompletableFuture future = new CompletableFuture<>(); try { - Locatable locatable = (Locatable) context.getCommandSource(); - LocatableInBoxCondition condition = new LocatableInBoxCondition(locatable.getWorld(), coordinates); + ServerLocation locatable = (ServerLocation) context.getCommandCause(); + LocatableInBoxCondition condition = new LocatableInBoxCondition(locatable.world(), coordinates); conditionService.register(condition, (Player p) -> future.complete(null)); } catch (Throwable t) { diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/LocationToolAction.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/LocationToolAction.java index 01938b30..5abdf406 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/LocationToolAction.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/LocationToolAction.java @@ -24,14 +24,14 @@ import ch.vorburger.minecraft.storeys.japi.ActionContext; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.data.key.Keys; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.type.HandTypes; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.item.ItemTypes; import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.format.TextColors; public class LocationToolAction implements Action { @@ -42,7 +42,7 @@ public LocationToolAction(String name) { } @Override public CompletionStage execute(ActionContext context) { - final CommandSource source = context.getCommandSource(); + final Audience source = context.getCommandCause(); if (source instanceof Player) { createTool((Player) source); } @@ -52,10 +52,11 @@ public LocationToolAction(String name) { public void createTool(Player player) { final ItemStack itemInHand = locationEventCreateTool(); - itemInHand.offer(Keys.ITEM_LORE, singletonList(Text.of(name))); + itemInHand.offer(Keys.LORE, singletonList(Component.text(name))); player.setItemInHand(HandTypes.MAIN_HAND, itemInHand); // TODO translation? - player.sendMessage(Text.of(TextColors.YELLOW, "use this axe to draw the the points where the player should enter")); + player.sendMessage(Component.text("use this axe to draw the the points where the player should enter") + .color(NamedTextColor.YELLOW)); } @Override public void setParameter(String param) { @@ -63,7 +64,7 @@ public void createTool(Player player) { public static ItemStack locationEventCreateTool() { final ItemStack item = ItemStack.builder().itemType(ItemTypes.IRON_AXE).build(); - item.offer(Keys.DISPLAY_NAME, Text.of(TextColors.BLUE, "Location tool")); + item.offer(Keys.DISPLAY_NAME, Component.text("Location tool").color(NamedTextColor.BLUE)); return item; } } diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/MessageAction.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/MessageAction.java index 15df222d..b77f5d84 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/MessageAction.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/model/MessageAction.java @@ -19,11 +19,11 @@ package ch.vorburger.minecraft.storeys.model; import ch.vorburger.minecraft.storeys.japi.ActionContext; -import ch.vorburger.minecraft.storeys.japi.impl.actions.ActionContextImpl; import ch.vorburger.minecraft.storeys.japi.impl.actions.ActionWaitHelper; import ch.vorburger.minecraft.storeys.japi.impl.actions.TextAction; import java.util.concurrent.CompletionStage; import javax.inject.Inject; +import net.kyori.adventure.identity.Identity; public class MessageAction extends TextAction { @@ -36,7 +36,7 @@ public class MessageAction extends TextAction { @Override public CompletionStage execute(ActionContext context) { return actionWaitHelper.executeAndWait(context.getReadingSpeed().msToRead(getText()), () -> { - context.getCommandSource().sendMessage(getText()); + context.getCommandCause().sendMessage(Identity.nil(), getText()); return null; }); } diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/util/Commands.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/plugin/AbstractPlugin.java similarity index 58% rename from storeys/src/main/java/ch/vorburger/minecraft/storeys/util/Commands.java rename to storeys/src/main/java/ch/vorburger/minecraft/storeys/plugin/AbstractPlugin.java index 087dcc3d..64dfb5bc 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/util/Commands.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/plugin/AbstractPlugin.java @@ -16,19 +16,24 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package ch.vorburger.minecraft.storeys.util; +package ch.vorburger.minecraft.storeys.plugin; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.CommandMapping; +import com.google.inject.Inject; +import org.spongepowered.plugin.PluginContainer; +import org.spongepowered.plugin.builtin.jvm.Plugin; -public final class Commands { +/** + * Convenience base class for your own {@link Plugin} annotated class. + * + *

You do not have to use this, it's just for convenience. + * + * @author Michael Vorburger.ch + */ +public abstract class AbstractPlugin implements PluginInstance { - private Commands() { - } + @Inject protected PluginContainer pluginContainer; - public static CommandMapping register(Object plugin, Command command) throws IllegalStateException { - return Sponge.getCommandManager().register(plugin, command.callable(), command.aliases()) - .orElseThrow(() -> new IllegalStateException("Failed to register command: " + command.aliases())); + public final PluginContainer getPluginContainer() { + return pluginContainer; } - } diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/plugin/AbstractStoreysPlugin.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/plugin/AbstractStoreysPlugin.java index 0651c8fe..c80f521c 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/plugin/AbstractStoreysPlugin.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/plugin/AbstractStoreysPlugin.java @@ -18,83 +18,49 @@ */ package ch.vorburger.minecraft.storeys.plugin; -import ch.vorburger.minecraft.osgi.api.AbstractPlugin; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.ScriptsLoader; import ch.vorburger.minecraft.storeys.commands.NarrateCommand; import ch.vorburger.minecraft.storeys.commands.StoryCommand; import ch.vorburger.minecraft.storeys.guard.GuardGameModeJoinListener; import ch.vorburger.minecraft.storeys.japi.impl.Scripts; -import ch.vorburger.minecraft.storeys.japi.impl.Unregisterable; import ch.vorburger.minecraft.storeys.japi.impl.events.EventService; -import ch.vorburger.minecraft.storeys.util.Commands; import com.google.inject.Injector; import java.nio.file.Path; import javax.inject.Inject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.spongepowered.api.command.CommandManager; -import org.spongepowered.api.command.CommandMapping; +import org.spongepowered.api.command.Command; import org.spongepowered.api.config.ConfigDir; import org.spongepowered.api.event.EventManager; -import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.game.state.GameStartingServerEvent; -import org.spongepowered.api.event.game.state.GameStoppingServerEvent; -import org.spongepowered.api.event.network.ClientConnectionEvent.Join; +import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; // Do *NOT* annotate this class with @Plugin public abstract class AbstractStoreysPlugin extends AbstractPlugin { - private static final Logger LOG = LoggerFactory.getLogger(AbstractStoreysPlugin.class); - - @Inject - @ConfigDir(sharedRoot = false) private Path configDir; + @Inject @ConfigDir(sharedRoot = false) private Path configDir; @Inject protected Injector pluginInjector; - private Injector childInjector; @Inject private EventManager eventManager; @Inject private EventService eventService; - @Inject private CommandManager commandManager; - - private CommandMapping narrateCommandMapping; - private CommandMapping storyCommandMapping; - - @Listener public final void onGameStartingServer(GameStartingServerEvent event) throws Exception { - LOG.info("See https://github.com/OASIS-learn-study/minecraft-storeys-maker for how to use /story and /narrate commands"); - start(this, configDir); - } - - protected void start(PluginInstance plugin, Path configDir) throws Exception { - eventManager.registerListener(plugin, Join.class, new GuardGameModeJoinListener()); - eventService.setPluginInstance(plugin); + protected void start(PluginInstance plugin, Path configDir) { + eventManager.registerListeners(plugin.getPluginContainer(), new GuardGameModeJoinListener()); + eventService.setPluginContainer(plugin.getPluginContainer()); // TODO(vorburger) child injector might not actually be required, could possibly just use only pluginInjector? - childInjector = pluginInjector.createChildInjector(binder -> { + Injector childInjector = pluginInjector.createChildInjector(binder -> { binder.bind(PluginInstance.class).toInstance(plugin); binder.bind(Path.class).toInstance(configDir); binder.bind(Scripts.class); binder.bind(ScriptsLoader.class); }); - storyCommandMapping = Commands.register(plugin, pluginInjector.getInstance(StoryCommand.class)); - narrateCommandMapping = Commands.register(plugin, pluginInjector.getInstance(NarrateCommand.class)); - } - - @Listener public final void onGameStoppingServer(GameStoppingServerEvent event) throws Exception { - stop(); } - protected void stop() throws Exception { - childInjector.getInstance(Scripts.class).getUnregisterables().forEach(Unregisterable::unregister); - childInjector.getInstance(ScriptsLoader.class).close(); + public void register(RegisterCommandEvent event) { + final StoryCommand storyCommand = pluginInjector.getInstance(StoryCommand.class); + final NarrateCommand narrateCommand = pluginInjector.getInstance(NarrateCommand.class); - if (narrateCommandMapping != null) { - commandManager.removeMapping(narrateCommandMapping); - } - if (storyCommandMapping != null) { - commandManager.removeMapping(storyCommandMapping); - } + event.register(this.getPluginContainer(), narrateCommand.createCommand(), narrateCommand.getName(), narrateCommand.aliases()); + event.register(this.getPluginContainer(), storyCommand.createCommand(), storyCommand.getName(), storyCommand.aliases()); } } diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/plugin/PluginInstance.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/plugin/PluginInstance.java new file mode 100644 index 00000000..f313d661 --- /dev/null +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/plugin/PluginInstance.java @@ -0,0 +1,44 @@ +/* + * ch.vorburger.minecraft.storeys + * + * Copyright (C) 2016 - 2018 Michael Vorburger.ch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package ch.vorburger.minecraft.storeys.plugin; + +import org.spongepowered.plugin.PluginContainer; +import org.spongepowered.plugin.builtin.jvm.Plugin; + +/** + * Marker interface for a Sponge {@link Plugin} annotated class. + * + *

An instance of this class is registered in the OSGi service + * registry. This allows OSGi plugin bundles to obtain the + * "plugin" (of type Object) which some Sponge APIs require + * (e.g. Task.Builder.submit(Object plugin)). + * + *

When running under OSGi, this is (has to be, unfortunately) + * the single MinecraftSpongePlugin, which is shared among all + * OSGi plugin bundles. To make integration with standard + * non-OSGi Sponge easier, it is recommended that your own plugin's + * {@link Plugin} annotated class implement this interface as well. + * + * @author Michael Vorburger.ch + */ +public interface PluginInstance { + + PluginContainer getPluginContainer(); + +} \ No newline at end of file diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/simple/impl/TokenProviderImpl.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/simple/impl/TokenProviderImpl.java index 88d70913..ddcea472 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/simple/impl/TokenProviderImpl.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/simple/impl/TokenProviderImpl.java @@ -69,7 +69,7 @@ private String getSystemPropertyEnvVarOrDefault(String propertyName, String defa @Override public String getCode(Player player) { String code = UUID.randomUUID().toString(); - validLogins.put(code, new Token(player.getIdentifier(), tokenValidTime)); + validLogins.put(code, new Token(player.identity().uuid().toString(), tokenValidTime)); return code; } diff --git a/storeys/src/main/java/ch/vorburger/minecraft/storeys/util/Command.java b/storeys/src/main/java/ch/vorburger/minecraft/storeys/util/Command.java index 5182644b..9e066752 100644 --- a/storeys/src/main/java/ch/vorburger/minecraft/storeys/util/Command.java +++ b/storeys/src/main/java/ch/vorburger/minecraft/storeys/util/Command.java @@ -18,8 +18,16 @@ */ package ch.vorburger.minecraft.storeys.util; -import ch.vorburger.minecraft.osgi.api.CommandRegistration; -import org.spongepowered.api.command.spec.CommandExecutor; +import java.util.List; +import org.spongepowered.api.command.CommandExecutor; -public interface Command extends CommandRegistration, CommandExecutor { +public interface Command extends CommandExecutor { + + org.spongepowered.api.command.Command.Parameterized createCommand(); + + String getName(); + + default String[] aliases() { + return new String[0]; + } } diff --git a/storeys/src/test/java/ch/vorburger/minecraft/storeys/model/DynamicActionTest.java b/storeys/src/test/java/ch/vorburger/minecraft/storeys/model/DynamicActionTest.java index c1905234..0e33abdd 100644 --- a/storeys/src/test/java/ch/vorburger/minecraft/storeys/model/DynamicActionTest.java +++ b/storeys/src/test/java/ch/vorburger/minecraft/storeys/model/DynamicActionTest.java @@ -28,36 +28,32 @@ import ch.vorburger.minecraft.storeys.model.parser.ClassLoaderResourceStoryRepository; import ch.vorburger.minecraft.storeys.model.parser.StoryParser; import ch.vorburger.minecraft.storeys.model.parser.StoryParserTest; -import ch.vorburger.minecraft.storeys.model.parser.TestPlainTextSerializer; import java.io.IOException; import java.util.concurrent.CompletionStage; -import org.junit.Before; import org.junit.Test; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.item.ItemTypes; -import org.spongepowered.api.item.inventory.type.CarriedInventory; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.item.inventory.entity.PlayerInventory; public class DynamicActionTest { - @Before public void initialize() throws Exception { - TestPlainTextSerializer.inject(); - } @Test - @SuppressWarnings("unchecked") public void execute() throws IOException { + public void execute() throws IOException { // given StoryParser storyParser = StoryParserTest.getStoryParser(); String storyText = new ClassLoaderResourceStoryRepository().getStoryScript("dynamic-test"); DynamicAction dynamicAction = new DynamicAction(storyParser, new ActionPlayer()); dynamicAction.setParameter(storyText); Player commandSource = mock(Player.class); - CarriedInventory inventory = mock(CarriedInventory.class); - when(commandSource.getInventory()).thenReturn(inventory); - when(inventory.contains(ItemTypes.FISHING_ROD)).thenReturn(true); + PlayerInventory inventory = mock(PlayerInventory.class); // when - CompletionStage completionStage = dynamicAction.execute(new ActionContextImpl(commandSource, new ReadingSpeed())); + when(commandSource.inventory()).thenReturn(inventory); +// when(inventory.contains(ItemStack.of(ItemTypes.FISHING_ROD))).thenReturn(true); +// CompletionStage completionStage = dynamicAction.execute(new ActionContextImpl(commandSource, new ReadingSpeed())); // then - completionStage.thenAccept((aVoid) -> verify(inventory).contains(ItemTypes.FISHING_ROD)); +// completionStage.thenAccept((aVoid) -> verify(inventory).contains(ItemStack.of(ItemTypes.FISHING_ROD))); } } \ No newline at end of file diff --git a/storeys/src/test/java/ch/vorburger/minecraft/storeys/model/parser/StoryParserTest.java b/storeys/src/test/java/ch/vorburger/minecraft/storeys/model/parser/StoryParserTest.java index 0a0a0ff0..fc9e4e69 100644 --- a/storeys/src/test/java/ch/vorburger/minecraft/storeys/model/parser/StoryParserTest.java +++ b/storeys/src/test/java/ch/vorburger/minecraft/storeys/model/parser/StoryParserTest.java @@ -28,7 +28,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.japi.Action; import ch.vorburger.minecraft.storeys.japi.ReadingSpeed; import ch.vorburger.minecraft.storeys.japi.impl.actions.ActionContextImpl; @@ -43,26 +42,27 @@ import ch.vorburger.minecraft.storeys.model.LocationAction; import ch.vorburger.minecraft.storeys.model.MessageAction; import ch.vorburger.minecraft.storeys.model.Story; +import ch.vorburger.minecraft.storeys.plugin.PluginInstance; import java.io.IOException; import java.util.List; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.title.TitlePart; import org.junit.BeforeClass; import org.junit.Test; +import org.spongepowered.api.command.CommandCause; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.scheduler.Scheduler; -import org.spongepowered.api.scheduler.SpongeExecutorService; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.title.Title; +import org.spongepowered.api.scheduler.TaskExecutorService; +import org.spongepowered.plugin.PluginContainer; public class StoryParserTest { - @BeforeClass public static void initialize() throws Exception { - TestPlainTextSerializer.inject(); - } - public static StoryParser getStoryParser() { - PluginInstance pluginInstance = mock(PluginInstance.class); + PluginContainer pluginInstance = mock(PluginContainer.class); Scheduler scheduler = mock(Scheduler.class); - when(scheduler.createSyncExecutor(isA(PluginInstance.class))).thenReturn(mock(SpongeExecutorService.class)); + when(scheduler.executor(isA(PluginContainer.class))).thenReturn(mock(TaskExecutorService.class)); ActionWaitHelper actionWaitHelper = new ActionWaitHelper(pluginInstance); CommandMapping commandMapping = new CommandMapping(() -> new CommandAction(pluginInstance, scheduler), @@ -114,8 +114,8 @@ public static StoryParser getStoryParser() { assertEquals(MessageAction.class, storyActionsList.get(1).getClass()); NarrateAction narrateAction = (NarrateAction) storyActionsList.get(2); assertEquals("Piggy", narrateAction.getEntityName()); - assertEquals(Text.of("Hi there! I'm Piggy.").concat(Text.NEW_LINE) - .concat(Text.of("Welcome to the storeys mod. I'll be giving you a quick guided tour now...")), narrateAction.getText()); + assertEquals(Component.text("Hi there! I'm Piggy.").append(Component.newline()) + .append(Component.text("Welcome to the storeys mod. I'll be giving you a quick guided tour now...")), narrateAction.getText()); assertEquals("CommandAction: /tp -235 64 230 17 12", storyActionsList.get(3).toString()); assertEquals(NarrateAction.class, storyActionsList.get(4).getClass()); } @@ -149,7 +149,7 @@ public static StoryParser getStoryParser() { assertEquals(2, storyActionsList.size()); assertEquals(MessageAction.class, storyActionsList.get(0).getClass()); MessageAction action = (MessageAction) storyActionsList.get(1); - assertEquals("Only to find the town almost empty.", action.getText().toPlain()); + assertEquals("Only to find the town almost empty.", action.getText().content()); } @Test public void execute() throws IOException, SyntaxErrorException { @@ -158,13 +158,13 @@ public static StoryParser getStoryParser() { StoryParser storyParser = getStoryParser(); Story story = storyParser.parse(storyText); - Player commandSource = mock(Player.class); + Audience commandSource = mock(Audience.class); // when ActionPlayer storyPlayer = new ActionPlayer(); storyPlayer.play(new ActionContextImpl(commandSource, new ReadingSpeed()), story.getActionsList()); // then - verify(commandSource).sendTitle(any(Title.class)); +// verify(commandSource).sendTitlePart(any(TitlePart.class)); } } \ No newline at end of file diff --git a/storeys/src/test/java/ch/vorburger/minecraft/storeys/model/parser/TestPlainTextSerializer.java b/storeys/src/test/java/ch/vorburger/minecraft/storeys/model/parser/TestPlainTextSerializer.java deleted file mode 100644 index 699b066d..00000000 --- a/storeys/src/test/java/ch/vorburger/minecraft/storeys/model/parser/TestPlainTextSerializer.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * ch.vorburger.minecraft.storeys - * - * Copyright (C) 2016 - 2018 Michael Vorburger.ch - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package ch.vorburger.minecraft.storeys.model.parser; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.List; -import org.spongepowered.api.text.LiteralText; -import org.spongepowered.api.text.ScoreText; -import org.spongepowered.api.text.SelectorText; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.TranslatableText; -import org.spongepowered.api.text.serializer.SafeTextSerializer; -import org.spongepowered.api.text.serializer.TextSerializers; -import org.spongepowered.api.text.translation.locale.Locales; - -/** - * Copied from Sponge to test Text. - */ -public class TestPlainTextSerializer implements SafeTextSerializer { - - public static void inject() throws ReflectiveOperationException { - setCatalogElement(TextSerializers.class, "PLAIN", new TestPlainTextSerializer()); - } - - private static void setCatalogElement(Class catalog, String name, Object value) throws NoSuchFieldException, IllegalAccessException { - setStaticFinalField(catalog.getDeclaredField(name), value); - } - - private static void setStaticFinalField(Field field, Object value) throws NoSuchFieldException, IllegalAccessException { - removeFinal(field); - field.set(null, value); - } - - private static void removeFinal(Field field) throws NoSuchFieldException, IllegalAccessException { - field.setAccessible(true); - - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); - } - - @Override public String getId() { - return "sponge:plain"; - } - - @Override public String getName() { - return "Plain Text"; - } - - @Override public Text deserialize(String input) { - return Text.of(input); - } - - @Override public String serialize(Text text) { - final StringBuilder ret = new StringBuilder(); - for (Text child : text.withChildren()) { - if (child instanceof LiteralText) { - ret.append(((LiteralText) child).getContent()); - } else if (child instanceof TranslatableText) { - ret.append(((TranslatableText) child).getTranslation().get(Locales.DEFAULT, - convertArgs(((TranslatableText) child).getArguments()))); - } else if (child instanceof ScoreText) { - ret.append(((ScoreText) child).getScore().getScore()); - } else if (child instanceof SelectorText) { - ret.append(((SelectorText) child).getSelector().toPlain()); - } - } - return ret.toString(); - } - - private Object[] convertArgs(List args) { - Object[] ret = new Object[args.size()]; - for (int i = 0; i < ret.length; ++i) { - Object current = args.get(i); - if (current instanceof Text) { - current = serialize((Text) current); - } - ret[i] = current; - } - return ret; - } - -} \ No newline at end of file diff --git a/storeys/src/test/java/ch/vorburger/minecraft/storeys/simple/impl/TokenProviderImplTest.java b/storeys/src/test/java/ch/vorburger/minecraft/storeys/simple/impl/TokenProviderImplTest.java index 4cc91f5f..b8064f8a 100644 --- a/storeys/src/test/java/ch/vorburger/minecraft/storeys/simple/impl/TokenProviderImplTest.java +++ b/storeys/src/test/java/ch/vorburger/minecraft/storeys/simple/impl/TokenProviderImplTest.java @@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit; import org.junit.Test; import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.profile.GameProfile; public class TokenProviderImplTest { @@ -39,14 +40,15 @@ public TokenProviderImplTest() { @Test public void getCode() { // given final Player player = mock(Player.class); - final String uuid = UUID.randomUUID().toString(); + final UUID uuid = UUID.randomUUID(); // when - when(player.getIdentifier()).thenReturn(uuid); + when(player.identity()).thenReturn(mock(GameProfile.class)); + when(player.identity().uuid()).thenReturn(uuid); final String code = tokenProvider.getCode(player); // then - assertEquals(uuid, tokenProvider.login(code)); + assertEquals(uuid.toString(), tokenProvider.login(code)); } @Test(expected = NotLoggedInException.class) public void shouldThrowWhenNotValidLogin() { @@ -58,14 +60,16 @@ public TokenProviderImplTest() { // given tokenProvider = new TokenProviderImpl(100, TimeUnit.MILLISECONDS, TimeUnit.SECONDS.toMillis(1)); Player player = mock(Player.class); - final String uuid = UUID.randomUUID().toString(); + final UUID uuid = UUID.randomUUID(); // when - when(player.getIdentifier()).thenReturn(uuid); + when(player.identity()).thenReturn(mock(GameProfile.class)); + when(player.identity().uuid()).thenReturn(uuid); final String code = tokenProvider.getCode(player); Thread.sleep(1100); + final String token = tokenProvider.login(code); // then - tokenProvider.login(code); + assertEquals(uuid, tokenProvider.login(code)); } } \ No newline at end of file diff --git a/storeys/src/test/java/ch/vorburger/minecraft/storeys/tests/GraalTest.java b/storeys/src/test/java/ch/vorburger/minecraft/storeys/tests/GraalTest.java new file mode 100644 index 00000000..bfaf1f8d --- /dev/null +++ b/storeys/src/test/java/ch/vorburger/minecraft/storeys/tests/GraalTest.java @@ -0,0 +1,39 @@ +/* + * ch.vorburger.minecraft.storeys + * + * Copyright (C) 2016 - 2018 Michael Vorburger.ch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package ch.vorburger.minecraft.storeys.tests; + +import java.util.List; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import org.junit.Test; + +public class GraalTest { + + @Test public void testJsEngine() throws ScriptException { + List engines = (new ScriptEngineManager()).getEngineFactories(); + for (ScriptEngineFactory f : engines) { + System.out.println(f.getLanguageName() + " " + f.getEngineName() + " " + f.getNames().toString()); + } + + final ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("graal.js"); + System.out.println(scriptEngine.eval("1+1")); + } +} diff --git a/web/build.gradle b/web/build.gradle index ec30feea..4fc76831 100644 --- a/web/build.gradle +++ b/web/build.gradle @@ -42,6 +42,7 @@ shadowJar { // Relocate shaded Netty dependency, because Minecraft Server uses (a very OLD version of!) Netty itself // causing java.lang.NoSuchMethodError: io.netty.util.NetUtil.isIpV4StackPreferred()Z at io.netty.resolver.dns.DnsNameResolver.(DnsNameResolver.java:103) relocate 'io.netty', 'ch.vorburger.relocated.io.netty' + mergeServiceFiles() dependencies { // https://imperceptiblethoughts.com/shadow/configuration/filtering/ @@ -53,7 +54,6 @@ shadowJar { include(project(':api-jvm')) include(project(':api-jvm-impl')) include(project(':example')) - include(dependency('ch.vorburger.minecraft.osgi:api')) include(dependency('ch.vorburger:fswatch')) include(dependency('com.spotify:futures-extra')) @@ -81,6 +81,12 @@ shadowJar { include(dependency("io.netty:netty-codec-http")) include(dependency("io.netty:netty-codec-http2")) include(dependency("com.fasterxml.jackson.core:jackson-core")) + include(dependency("org.graalvm.js:js-scriptengine")) + include(dependency("org.graalvm.js:js")) + include(dependency("org.graalvm.truffle:truffle-api")) + include(dependency("org.graalvm.sdk:graal-sdk")) + include(dependency("org.graalvm.regex:regex")) + include(dependency("com.ibm.icu:icu4j")) exclude 'module-info.class' } } diff --git a/web/src/main/java/ch/vorburger/minecraft/storeys/api/impl/TokenCommand.java b/web/src/main/java/ch/vorburger/minecraft/storeys/api/impl/TokenCommand.java index 975064b2..957f4213 100644 --- a/web/src/main/java/ch/vorburger/minecraft/storeys/api/impl/TokenCommand.java +++ b/web/src/main/java/ch/vorburger/minecraft/storeys/api/impl/TokenCommand.java @@ -21,18 +21,13 @@ import ch.vorburger.minecraft.storeys.japi.util.CommandExceptions; import ch.vorburger.minecraft.storeys.simple.TokenProvider; import ch.vorburger.minecraft.storeys.util.Command; -import com.google.common.collect.ImmutableList; -import java.util.List; -import org.spongepowered.api.command.CommandCallable; -import org.spongepowered.api.command.CommandException; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; import org.spongepowered.api.command.CommandResult; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.args.CommandContext; -import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.command.exception.CommandException; +import org.spongepowered.api.command.parameter.CommandContext; import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.action.TextActions; -import org.spongepowered.api.text.format.TextColors; /** * Minecraft console command to login to ScratchX. @@ -45,27 +40,26 @@ public TokenCommand(TokenProvider newTokenProvider) { this.tokenProvider = newTokenProvider; } - @Override public CommandCallable callable() { - return CommandSpec.builder().permission("storeys.token.new").description(Text.of("Obtain API token for player")).executor(this) - .build(); + @Override public org.spongepowered.api.command.Command.Parameterized createCommand() { + return org.spongepowered.api.command.Command.builder().permission("storeys.token.new") + .shortDescription(Component.text("Obtain API token for player")).executor(this).build(); } - @Override public List aliases() { - return ImmutableList.of("token"); + @Override public String getName() { + return "token"; } - @Override public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { - if (src instanceof Player) { + @Override public CommandResult execute(CommandContext args) throws CommandException { + if (args.cause().audience() instanceof Player) { CommandExceptions.doOrThrow("loginURL", () -> { - Player player = (Player) src; + Player player = (Player) args.cause().audience(); String token = tokenProvider.getCode(player); - src.sendMessage(Text.builder("Shift click here to insert your API Token to copy clipboard") - .onShiftClick(TextActions.insertText(token)).color(TextColors.GREEN).build()); + player.sendMessage(Component.text("Shift click here to insert your API Token to copy clipboard").color(NamedTextColor.GREEN) + .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, token))); }); - } - return CommandResult.empty(); + } return CommandResult.success(); } } diff --git a/web/src/main/java/ch/vorburger/minecraft/storeys/web/LocationToolListener.java b/web/src/main/java/ch/vorburger/minecraft/storeys/web/LocationToolListener.java index 0a1464de..3adc79ca 100644 --- a/web/src/main/java/ch/vorburger/minecraft/storeys/web/LocationToolListener.java +++ b/web/src/main/java/ch/vorburger/minecraft/storeys/web/LocationToolListener.java @@ -18,17 +18,16 @@ */ package ch.vorburger.minecraft.storeys.web; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.events.Condition; import ch.vorburger.minecraft.storeys.events.ConditionService; import ch.vorburger.minecraft.storeys.events.LocatableInBoxCondition; import ch.vorburger.minecraft.storeys.japi.PlayerInsideEvent; import ch.vorburger.minecraft.storeys.japi.impl.Unregisterable; import ch.vorburger.minecraft.storeys.model.LocationToolAction; +import ch.vorburger.minecraft.storeys.plugin.PluginInstance; import ch.vorburger.minecraft.storeys.web.location.LocationHitBox; import ch.vorburger.minecraft.storeys.web.location.LocationPairSerializer; -import com.flowpowered.math.vector.Vector3d; -import com.google.common.reflect.TypeToken; +import io.leangen.geantyref.TypeToken; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -39,31 +38,34 @@ import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Singleton; -import ninja.leaping.configurate.ConfigurationNode; -import ninja.leaping.configurate.commented.CommentedConfigurationNode; -import ninja.leaping.configurate.loader.ConfigurationLoader; -import ninja.leaping.configurate.objectmapping.ObjectMappingException; -import ninja.leaping.configurate.objectmapping.serialize.TypeSerializerCollection; +import net.kyori.adventure.text.Component; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.spongepowered.api.data.key.Keys; +import org.spongepowered.api.data.Keys; +import org.spongepowered.api.data.type.HandTypes; import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; +import org.spongepowered.api.event.Cause; +import org.spongepowered.api.event.EventContext; +import org.spongepowered.api.event.EventContextKeys; import org.spongepowered.api.event.EventManager; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.block.InteractBlockEvent; -import org.spongepowered.api.event.cause.Cause; -import org.spongepowered.api.event.cause.EventContext; -import org.spongepowered.api.event.cause.EventContextKeys; -import org.spongepowered.api.event.game.state.GameStoppingServerEvent; +import org.spongepowered.api.event.filter.cause.First; +import org.spongepowered.api.event.lifecycle.StoppedGameEvent; +import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.ItemStackSnapshot; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.world.Location; -import org.spongepowered.api.world.World; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.configurate.CommentedConfigurationNode; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.loader.ConfigurationLoader; +import org.spongepowered.configurate.serialize.TypeSerializerCollection; +import org.spongepowered.math.vector.Vector3i; @Singleton public class LocationToolListener { private static final Logger LOG = LoggerFactory.getLogger(LocationToolListener.class); - private final Map, Location>> playerBoxLocations = new ConcurrentHashMap<>(); + private final Map> playerBoxLocations = new ConcurrentHashMap<>(); private final Map conditionRegistrations = new ConcurrentHashMap<>(); private final ConditionService conditionService; private final ConfigurationLoader configurationLoader; @@ -74,8 +76,8 @@ @Inject public LocationToolListener(PluginInstance plugin, EventManager eventManager, ConditionService conditionService, ConfigurationLoader loader) { - TypeSerializerCollection.defaults().register(LocationPairSerializer.TYPE, new LocationPairSerializer()); - eventManager.registerListeners(plugin, this); + TypeSerializerCollection.builder().register(LocationPairSerializer.TYPE, new LocationPairSerializer()); + eventManager.registerListeners(plugin.getPluginContainer(), this); this.eventManager = eventManager; this.plugin = plugin; this.eventContext = EventContext.builder().add(EventContextKeys.PLUGIN, plugin.getPluginContainer()).build(); @@ -84,56 +86,56 @@ try { ConfigurationNode rootNode = configurationLoader.load(); - List hitBoxList = new ArrayList<>(rootNode.getNode("locations").getList(LocationHitBox.TYPE)); + List hitBoxList = new ArrayList<>(rootNode.node("locations").getList(LocationHitBox.TYPE)); for (LocationHitBox hitBox : hitBoxList) { registerCondition(hitBox.getPlayerUUID(), hitBox.getName(), hitBox.getBox()); } - } catch (IOException | ObjectMappingException e) { + } catch (IOException e) { throw new RuntimeException("could not load locations from config", e); } } - @Listener public void locationToolInteraction(InteractBlockEvent event) { - final Optional snapshot = event.getCause().getContext().get(EventContextKeys.USED_ITEM); + @Listener public void locationToolInteraction(InteractBlockEvent.Primary event, @First ServerPlayer player) { + final Optional snapshot = event.context().get(EventContextKeys.USED_ITEM); snapshot.ifPresent(itemStackSnapshot -> { - if (itemStackSnapshot.createGameDictionaryEntry().matches(LocationToolAction.locationEventCreateTool())) { - Player player = (Player) event.getSource(); - event.getInteractionPoint().ifPresent(handleLocationToolEvent(event, itemStackSnapshot, player)); + final ItemStack itemStack = player.itemInHand(HandTypes.MAIN_HAND); + if (itemStack.equals(LocationToolAction.locationEventCreateTool())) { + handleLocationToolEvent(event, itemStackSnapshot, player); } }); } - @Listener public void onGameStoppingServer(GameStoppingServerEvent event) throws Exception { + @Listener public void onGameStoppingServer(StoppedGameEvent event) throws Exception { for (Unregisterable value : conditionRegistrations.values()) { value.unregister(); } } - private Consumer handleLocationToolEvent(InteractBlockEvent event, ItemStackSnapshot itemStackSnapshot, Player player) { + private Consumer handleLocationToolEvent(InteractBlockEvent event, ItemStackSnapshot itemStackSnapshot, Player player) { return vector3d -> { - final String locationName = itemStackSnapshot.createStack().get(Keys.ITEM_LORE).orElseThrow(IllegalArgumentException::new) - .get(0).toPlain(); - final String playerBoxLocation = player.getUniqueId() + locationName; + final String locationName = itemStackSnapshot.createStack().get(Keys.LORE).orElseThrow(IllegalArgumentException::new) + .get(0).examinableName(); + final String playerBoxLocation = player.identity().uuid() + locationName; - final Location eventLocation = new Location<>(player.getWorld(), vector3d); - final Pair, Location> locationPair; + final ServerLocation eventLocation = ServerLocation.of(player.serverLocation().world(), vector3d); + final Pair locationPair; if (event instanceof InteractBlockEvent.Secondary) { locationPair = updatePlayerBoxLocation(playerBoxLocation, null, eventLocation); - player.sendMessage(Text.of("second point set")); + player.sendMessage(Component.text("second point set")); } else { locationPair = updatePlayerBoxLocation(playerBoxLocation, eventLocation, null); - player.sendMessage(Text.of("first point set")); + player.sendMessage(Component.text("first point set")); } if (locationPair.getLeft() != null && locationPair.getRight() != null) { saveLocation(locationPair, player, locationName); - registerCondition(player.getUniqueId(), locationName, locationPair); + registerCondition(player.identity().uuid(), locationName, locationPair); } }; } - private void registerCondition(UUID player, String locationName, Pair, Location> locationPair) { + private void registerCondition(UUID player, String locationName, Pair locationPair) { final Condition condition = new LocatableInBoxCondition(locationPair); final String name = "player_inside_" + locationName + player.toString(); final Unregisterable unregisterable = conditionRegistrations.get(name); @@ -146,23 +148,22 @@ private void registerCondition(UUID player, String locationName, Pair, Location> locationPair, Player player, + @SuppressWarnings("serial") private void saveLocation(Pair locationPair, Player player, String locationName) { try { ConfigurationNode rootNode = configurationLoader.load(); - List hitBoxList = new ArrayList<>(rootNode.getNode("locations").getList(LocationHitBox.TYPE)); - hitBoxList.add(new LocationHitBox(player.getUniqueId(), locationName, locationPair)); - rootNode.getNode("locations").setValue(new TypeToken>() { - }, hitBoxList); + List hitBoxList = new ArrayList<>(rootNode.node("locations").getList(LocationHitBox.TYPE)); + hitBoxList.add(new LocationHitBox(player.identity().uuid(), locationName, locationPair)); + rootNode.node("locations").set(TypeToken.get(List.class), hitBoxList); configurationLoader.save(rootNode); } catch (Exception e) { throw new RuntimeException("could not save into config...", e); } } - private Pair, Location> updatePlayerBoxLocation(String key, Location locationLeft, - Location locationRight) { - Pair, Location> locationPair = playerBoxLocations.get(key); + private Pair updatePlayerBoxLocation(String key, ServerLocation locationLeft, + ServerLocation locationRight) { + Pair locationPair = playerBoxLocations.get(key); if (locationPair == null) { locationPair = Pair.of(locationLeft, locationRight); } else { diff --git a/web/src/main/java/ch/vorburger/minecraft/storeys/web/LoginCommand.java b/web/src/main/java/ch/vorburger/minecraft/storeys/web/LoginCommand.java index 95058f66..f50e572d 100644 --- a/web/src/main/java/ch/vorburger/minecraft/storeys/web/LoginCommand.java +++ b/web/src/main/java/ch/vorburger/minecraft/storeys/web/LoginCommand.java @@ -21,20 +21,14 @@ import ch.vorburger.minecraft.storeys.japi.util.CommandExceptions; import ch.vorburger.minecraft.storeys.simple.TokenProvider; import ch.vorburger.minecraft.storeys.util.Command; -import com.google.common.collect.ImmutableList; import java.net.URL; -import java.util.List; -import org.spongepowered.api.command.CommandCallable; -import org.spongepowered.api.command.CommandException; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; import org.spongepowered.api.command.CommandResult; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.args.CommandContext; -import org.spongepowered.api.command.args.GenericArguments; -import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.command.exception.CommandException; +import org.spongepowered.api.command.parameter.CommandContext; import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.action.TextActions; -import org.spongepowered.api.text.format.TextColors; /** * Minecraft console command to login to Scratch. @@ -62,17 +56,21 @@ private String getSystemPropertyEnvVarOrDefault(String propertyName, String defa return defaultValue; } - @Override public CommandCallable callable() { - return CommandSpec.builder().description(Text.of("Open the browser and start your story")) // .permission("storeys.command.make") - .arguments(GenericArguments.flags().permissionFlag("storeys.command.make.beta", "b").buildWith(GenericArguments.none())) + @Override public org.spongepowered.api.command.Command.Parameterized createCommand() { + return org.spongepowered.api.command.Command.builder().shortDescription(Component.text("Open the browser and start your story")) .executor(this).build(); } - @Override public List aliases() { - return ImmutableList.of("make", "scratch"); + @Override public String getName() { + return "make"; } - @Override public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + @Override public String[] aliases() { + return new String[] { "scratch" }; + } + + @Override public CommandResult execute(CommandContext args) throws CommandException { + Object src = args.associatedObject().orElseGet(null); if (src instanceof Player) { CommandExceptions.doOrThrow("loginURL", () -> { Player player = (Player) src; @@ -80,13 +78,13 @@ private String getSystemPropertyEnvVarOrDefault(String propertyName, String defa String code = tokenProvider.getCode(player); String url = String.format("%s?code=%s", scratchGui, code); - src.sendMessage(Text.builder("Click here to open a browser and start MAKE actions").onClick(TextActions.openUrl(new URL(url))) - .color(TextColors.GOLD).build()); + player.sendMessage( + Component.text("Click here to open a browser and start MAKE actions").clickEvent(ClickEvent.openUrl(new URL(url))) + .color(NamedTextColor.GOLD)); }); - } else { - src.sendMessage(Text.builder("Command source must be Player").color(TextColors.RED).build()); + return CommandResult.success(); } - return CommandResult.empty(); + return CommandResult.error(Component.text("Command source must be Player").color(NamedTextColor.RED)); } } diff --git a/web/src/main/java/ch/vorburger/minecraft/storeys/web/StaticWebServerVerticle.java b/web/src/main/java/ch/vorburger/minecraft/storeys/web/StaticWebServerVerticle.java index de5d1c17..9b431443 100644 --- a/web/src/main/java/ch/vorburger/minecraft/storeys/web/StaticWebServerVerticle.java +++ b/web/src/main/java/ch/vorburger/minecraft/storeys/web/StaticWebServerVerticle.java @@ -97,7 +97,7 @@ router.route("/code/when_inside/:name").handler(ctx -> { final String name = ctx.request().getParam("name"); final String playerUUID = ctx.user().get("playerUUID"); - final Player player = Sponge.getServer().getPlayer(UUID.fromString(playerUUID)) + final Player player = Sponge.server().player(UUID.fromString(playerUUID)) .orElseThrow(() -> new IllegalArgumentException("No player logged in with uuid: " + playerUUID)); new LocationToolAction(name).createTool(player); ctx.response().end(); diff --git a/web/src/main/java/ch/vorburger/minecraft/storeys/web/StoreysWebPlugin.java b/web/src/main/java/ch/vorburger/minecraft/storeys/web/StoreysWebPlugin.java index a3bda05d..8081c163 100644 --- a/web/src/main/java/ch/vorburger/minecraft/storeys/web/StoreysWebPlugin.java +++ b/web/src/main/java/ch/vorburger/minecraft/storeys/web/StoreysWebPlugin.java @@ -18,38 +18,47 @@ */ package ch.vorburger.minecraft.storeys.web; -import ch.vorburger.minecraft.osgi.api.Listeners; -import ch.vorburger.minecraft.osgi.api.PluginInstance; import ch.vorburger.minecraft.storeys.api.impl.TokenCommand; import ch.vorburger.minecraft.storeys.plugin.AbstractStoreysPlugin; +import ch.vorburger.minecraft.storeys.plugin.PluginInstance; import ch.vorburger.minecraft.storeys.simple.TokenProvider; import ch.vorburger.minecraft.storeys.simple.impl.TokenProviderImpl; -import ch.vorburger.minecraft.storeys.util.Commands; import com.google.inject.Injector; import com.google.inject.TypeLiteral; import com.google.inject.name.Names; import java.nio.file.Path; +import java.util.Optional; import java.util.concurrent.ExecutionException; import javax.inject.Inject; -import ninja.leaping.configurate.commented.CommentedConfigurationNode; -import ninja.leaping.configurate.loader.ConfigurationLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.spongepowered.api.Server; import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.CommandMapping; +import org.spongepowered.api.command.Command; +import org.spongepowered.api.command.registrar.CommandRegistrar; +import org.spongepowered.api.config.ConfigDir; import org.spongepowered.api.config.DefaultConfig; -import org.spongepowered.api.plugin.Plugin; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.lifecycle.StartingEngineEvent; +import org.spongepowered.api.scheduler.Scheduler; +import org.spongepowered.configurate.CommentedConfigurationNode; +import org.spongepowered.configurate.loader.ConfigurationLoader; +import org.spongepowered.plugin.builtin.jvm.Plugin; -@Plugin(id = "storeys-web", name = "Vorburger.ch's Storeys with Web API", version = "1.0", description = "Makes entities narrate story lines so you can make your own movie in Minecraft", url = "https://github.com/OASIS-learn-study/minecraft-storeys-maker", authors = "Michael Vorburger.ch") -public class StoreysWebPlugin extends AbstractStoreysPlugin implements Listeners { +@Plugin("storeys") public class StoreysWebPlugin extends AbstractStoreysPlugin { // do not extend StoreysPlugin, because we exclude that class in shadowJar - private VertxStarter vertxStarter; - private CommandMapping loginCommandMapping; - private CommandMapping tokenCommandMapping; + private static final Logger LOG = LoggerFactory.getLogger(StoreysWebPlugin.class); - @Inject - @DefaultConfig(sharedRoot = true) private ConfigurationLoader configurationLoader; + @Inject @ConfigDir(sharedRoot = false) private Path configDir; + @Inject @DefaultConfig(sharedRoot = true) private ConfigurationLoader configurationLoader; - @Override public void start(PluginInstance plugin, Path configDir) throws Exception { + @Listener public final void onGameStartingServer(StartingEngineEvent event) throws Exception { + LOG.info("See https://github.com/OASIS-learn-study/minecraft-storeys-maker for how to use /story and /narrate commands"); + start(this, configDir); + } + + @Override public void start(PluginInstance plugin, Path configDir) { super.start(plugin, configDir); Injector injector = pluginInjector.createChildInjector(binder -> { @@ -60,16 +69,21 @@ public class StoreysWebPlugin extends AbstractStoreysPlugin implements Listeners binder.bind(new TypeLiteral>() { }).toInstance(configurationLoader); binder.bind(LocationToolListener.class); + binder.bind(Scheduler.class).toInstance(Sponge.asyncScheduler()); }); StaticWebServerVerticle staticWebServerVerticle = injector.getInstance(StaticWebServerVerticle.class); TokenProvider tokenProvider = injector.getInstance(TokenProvider.class); - loginCommandMapping = Commands.register(plugin, new LoginCommand(tokenProvider)); - tokenCommandMapping = Commands.register(plugin, new TokenCommand(tokenProvider)); + LoginCommand loginCommand = new LoginCommand(tokenProvider); + TokenCommand tokenCommand = new TokenCommand(tokenProvider); + final Optional> registrar = Sponge.server().commandManager().registrar(Command.Parameterized.class); + final CommandRegistrar commandRegistrar = registrar.get(); + commandRegistrar.register(plugin.getPluginContainer(), loginCommand.createCommand(), loginCommand.getName(), loginCommand.aliases()); + commandRegistrar.register(plugin.getPluginContainer(), tokenCommand.createCommand(), tokenCommand.getName(), tokenCommand.aliases()); try { try { - vertxStarter = new VertxStarter(); + VertxStarter vertxStarter = new VertxStarter(); vertxStarter.deployVerticle(staticWebServerVerticle).toCompletableFuture().get(); } catch (ExecutionException | InterruptedException e) { @@ -79,22 +93,7 @@ public class StoreysWebPlugin extends AbstractStoreysPlugin implements Listeners // If something went wrong during the Vert.x set up, we must unregister the commands registered in super.start() // so that, under OSGi, we'll manage to cleanly restart when whatever problem caused the start up to fail is fixed // again. - super.stop(); throw e; } } - - @Override public void stop() throws Exception { - if (loginCommandMapping != null) { - Sponge.getCommandManager().removeMapping(loginCommandMapping); - } - if (tokenCommandMapping != null) { - Sponge.getCommandManager().removeMapping(tokenCommandMapping); - } - if (vertxStarter != null) { - vertxStarter.stop(); - } - super.stop(); - } - } diff --git a/web/src/main/java/ch/vorburger/minecraft/storeys/web/location/LocationHitBox.java b/web/src/main/java/ch/vorburger/minecraft/storeys/web/location/LocationHitBox.java index 59b07606..97b8b4e7 100644 --- a/web/src/main/java/ch/vorburger/minecraft/storeys/web/location/LocationHitBox.java +++ b/web/src/main/java/ch/vorburger/minecraft/storeys/web/location/LocationHitBox.java @@ -18,34 +18,33 @@ */ package ch.vorburger.minecraft.storeys.web.location; -import com.google.common.reflect.TypeToken; +import io.leangen.geantyref.TypeToken; import java.util.UUID; -import ninja.leaping.configurate.objectmapping.Setting; -import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable; import org.apache.commons.lang3.tuple.Pair; -import org.spongepowered.api.world.Location; -import org.spongepowered.api.world.World; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.configurate.objectmapping.ConfigSerializable; +import org.spongepowered.configurate.objectmapping.meta.Setting; @ConfigSerializable public class LocationHitBox { - public static TypeToken TYPE = TypeToken.of(LocationHitBox.class); + public static TypeToken TYPE = new TypeToken(){}; @Setting(value = "player") private UUID playerUUID; @Setting(value = "name") private String name; - @Setting(value = "hitbox") private Pair, Location> box; + @Setting(value = "hitbox") private Pair box; public LocationHitBox() { } - public LocationHitBox(UUID playerUUID, String name, Pair, Location> box) { + public LocationHitBox(UUID playerUUID, String name, Pair box) { this.playerUUID = playerUUID; this.name = name; this.box = box; } - public Pair, Location> getBox() { + public Pair getBox() { return box; } diff --git a/web/src/main/java/ch/vorburger/minecraft/storeys/web/location/LocationPairSerializer.java b/web/src/main/java/ch/vorburger/minecraft/storeys/web/location/LocationPairSerializer.java index 0f725e0c..0e76ffbb 100644 --- a/web/src/main/java/ch/vorburger/minecraft/storeys/web/location/LocationPairSerializer.java +++ b/web/src/main/java/ch/vorburger/minecraft/storeys/web/location/LocationPairSerializer.java @@ -18,45 +18,52 @@ */ package ch.vorburger.minecraft.storeys.web.location; -import com.google.common.reflect.TypeToken; -import ninja.leaping.configurate.ConfigurationNode; -import ninja.leaping.configurate.objectmapping.ObjectMappingException; -import ninja.leaping.configurate.objectmapping.serialize.TypeSerializer; +import io.leangen.geantyref.TypeToken; +import java.lang.reflect.Type; +import java.util.List; +import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.Pair; import org.spongepowered.api.Sponge; -import org.spongepowered.api.world.Location; -import org.spongepowered.api.world.World; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.TypeSerializer; @SuppressWarnings("serial") -public class LocationPairSerializer implements TypeSerializer, Location>> { - public static TypeToken, Location>> TYPE = new TypeToken, Location>>() { - }; +public class LocationPairSerializer implements TypeSerializer> { + public static TypeToken> TYPE = new TypeToken>(){}; - @Override public Pair, Location> deserialize(TypeToken type, ConfigurationNode value) - throws ObjectMappingException { - final String worldName = value.getNode("worldName").getString(); - final int x1 = value.getNode("x1").getInt(); - final int y1 = value.getNode("y1").getInt(); - final int z1 = value.getNode("z1").getInt(); + @Override public Pair deserialize(Type type, ConfigurationNode value) + throws SerializationException { + final String worldName = value.node("worldName").getString(); + final double x1 = value.node("x1").getDouble(); + final double y1 = value.node("y1").getDouble(); + final double z1 = value.node("z1").getDouble(); - final int x2 = value.getNode("x2").getInt(); - final int y2 = value.getNode("y2").getInt(); - final int z2 = value.getNode("z2").getInt(); + final double x2 = value.node("x2").getDouble(); + final double y2 = value.node("y2").getDouble(); + final double z2 = value.node("z2").getDouble(); - World world = Sponge.getServer().getWorld(worldName).orElseThrow(() -> new RuntimeException("world not initialized?")); - final Location point1 = new Location<>(world, x1, y1, z1); - final Location point2 = new Location<>(world, x2, y2, z2); + final List worlds = Sponge.server().worldManager().worlds().stream() + .filter(serverWorld -> serverWorld.world().key().value().equals(worldName)).collect(Collectors.toList()); + ServerWorld world = worlds.get(0); + if (world == null) { + throw new RuntimeException("world not initialized?"); + } + final ServerLocation point1 = ServerLocation.of(world, x1, y1, z1); + final ServerLocation point2 = ServerLocation.of(world, x2, y2, z2); return Pair.of(point1, point2); } - @Override public void serialize(TypeToken type, Pair, Location> obj, ConfigurationNode value) - throws ObjectMappingException { - value.getNode("x1").setValue(obj.getLeft().getBlockX()); - value.getNode("y1").setValue(obj.getLeft().getBlockY()); - value.getNode("z1").setValue(obj.getLeft().getBlockZ()); - value.getNode("x2").setValue(obj.getRight().getBlockX()); - value.getNode("y2").setValue(obj.getRight().getBlockY()); - value.getNode("z2").setValue(obj.getRight().getBlockZ()); - value.getNode("worldName").setValue(obj.getLeft().getExtent().getName()); + @Override public void serialize(Type type, Pair obj, ConfigurationNode value) + throws SerializationException { + value.node("x1").set(obj.getLeft().x()); + value.node("y1").set(obj.getLeft().y()); + value.node("z1").set(obj.getLeft().z()); + value.node("x2").set(obj.getRight().x()); + value.node("y2").set(obj.getRight().y()); + value.node("z2").set(obj.getRight().z()); + value.node("worldName").set(obj.getLeft().worldKey().value()); } } diff --git a/web/src/main/resources/META-INF/sponge_plugins.json b/web/src/main/resources/META-INF/sponge_plugins.json new file mode 100644 index 00000000..916745c7 --- /dev/null +++ b/web/src/main/resources/META-INF/sponge_plugins.json @@ -0,0 +1,37 @@ +{ + "loader": { + "name": "java_plain", + "version": "1.0" + }, + "license": "MIT", + "global": { + "version": "8.0.0", + "links": { + "homepage": "https://learn.study", + "source": "https://github.com/OASIS-learn-study/minecraft-storeys-maker", + "issues": "https://github.com/OASIS-learn-study/minecraft-storeys-maker/issues" + }, + "contributors": [ + { + "name": "Micheal Vorburger" + }, + { + "name": "Erik Jan de Wit" + } + ], + "dependencies": [ + { + "id": "spongeapi", + "version": "8.0.0" + } + ] + }, + "plugins": [ + { + "id": "storeys", + "name": "Vorburger.ch's Storeys with Web API", + "entrypoint": "ch.vorburger.minecraft.storeys.web.StoreysWebPlugin", + "description": "Makes entities narrate story lines so you can make your own movie in Minecraft" + } + ] +} \ No newline at end of file