Skip to content

Commit

Permalink
WIP of new JVM API (incl. Unregistrable Script)
Browse files Browse the repository at this point in the history
  • Loading branch information
vorburger committed Apr 6, 2022
1 parent 5a231a5 commit c86bf66
Show file tree
Hide file tree
Showing 35 changed files with 541 additions and 39 deletions.
4 changes: 4 additions & 0 deletions api-jvm-impl/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

dependencies {
api project(':api-jvm')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* ch.vorburger.minecraft.storeys
*
* Copyright (C) 2016 - 2018 Michael Vorburger.ch <[email protected]>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package ch.vorburger.minecraft.storeys.japi.impl;

import ch.vorburger.minecraft.storeys.japi.Callback;
import ch.vorburger.minecraft.storeys.japi.Events;
import ch.vorburger.minecraft.storeys.japi.Script;
import ch.vorburger.minecraft.storeys.japi.util.CommandExceptions;
import ch.vorburger.minecraft.storeys.japi.util.Texts;
import java.util.Collection;
import java.util.Optional;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandMapping;
import org.spongepowered.api.command.CommandResult;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.command.spec.CommandSpec;

/**
* {@link Events} implementation.
*
* Created via {@link Scripts}.
*
* The "lifecycle" of this is NOT a Singleton,
* but one for each new (possibly reloaded) {@link Script} instance.
*/
class EventsImpl implements Events, Unregisterable {

private final Object plugin;
private final CommandSource source;
private final Collection<Unregisterable> unregistrables = new ConcurrentLinkedQueue<>();

EventsImpl(Object plugin, CommandSource source) {
this.plugin = plugin;
this.source = source;
}

@Override public void whenCommand(String name, Callback callback) {
CommandSpec spec = CommandSpec.builder().executor((src, args) -> {
CommandExceptions.doOrThrow("/" + name, () -> callback.invoke(new MinecraftJvmImpl(src)));
return CommandResult.success();
}).build();
Optional<CommandMapping> opt = Sponge.getCommandManager().register(plugin, spec, name);
if (opt.isEmpty()) {
source.sendMessage(Texts.inRed("Could not register /" + name));
return;
}
unregistrables.add(() -> Sponge.getCommandManager().removeMapping(opt.get()));
}

@Override public void unregister() {
for (Unregisterable unregisterable : unregistrables) {
unregisterable.unregister();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* ch.vorburger.minecraft.storeys
*
* Copyright (C) 2016 - 2018 Michael Vorburger.ch <[email protected]>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package ch.vorburger.minecraft.storeys.japi.impl;

import static java.util.Objects.requireNonNull;

import ch.vorburger.minecraft.storeys.japi.Events;
import ch.vorburger.minecraft.storeys.japi.Minecraft;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.player.Player;

/**
* {@link Minecraft} implementation.
*
* Created indirectly (by EventsImpl) via {@link Scripts}.
*
* 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.
*/
class MinecraftJvmImpl implements Minecraft {

private final CommandSource source;

MinecraftJvmImpl(CommandSource source) {
this.source = source;
}

@Override public void cmd(String command) {
String commandWithoutSlash = requireNonNull(command, "command").trim();
if (commandWithoutSlash.startsWith("/")) {
commandWithoutSlash = commandWithoutSlash.substring(1);
}
Sponge.getCommandManager().process(source, requireNonNull(commandWithoutSlash, "commandWithoutSlash"));
}

@Override public Player player() {
// TODO if (source instanceof Player), else... error handling TBD (not just log, but explain it to source)
return (Player) source;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* ch.vorburger.minecraft.storeys
*
* Copyright (C) 2016 - 2018 Michael Vorburger.ch <[email protected]>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package ch.vorburger.minecraft.storeys.japi.impl;

import ch.vorburger.minecraft.storeys.japi.Script;
import com.google.errorprone.annotations.CheckReturnValue;
import org.spongepowered.api.command.CommandSource;

public final class Scripts {

// TODO CommandSource argument here still smells wrong (it should be "later")

@CheckReturnValue public static Unregisterable init(Object plugin, CommandSource source, Script script) {
EventsImpl e = new EventsImpl(plugin, source);
script.init(e);
return e;
}

private Scripts() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ch.vorburger.minecraft.storeys.events;
package ch.vorburger.minecraft.storeys.japi.impl;

public interface Unregisterable {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* ch.vorburger.minecraft.storeys
*
* Copyright (C) 2016 - 2018 Michael Vorburger.ch <[email protected]>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package ch.vorburger.minecraft.storeys.japi.util;

import java.util.concurrent.Callable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongepowered.api.command.CommandException;

/**
* Utilities for {@link CommandException}.
*
* @author Michael Vorburger.ch
*/
public final class CommandExceptions {

// Copy/pasted from https://github.com/vorburger/ch.vorburger.minecraft.osgi/blob/master/ch.vorburger.minecraft.osgi.api/src/main/java/ch/vorburger/minecraft/utils/CommandExceptions.java

private static final Logger LOG = LoggerFactory.getLogger(CommandExceptions.class);

private CommandExceptions() {
}

/**
* Invoke 'callable' and return its value,
* or rethrow any Exception from it wrapped in a CommandException,
* with description.
*
* @param description a humand-readable description of the Callable (used in the CommandException)
* @param callable the code to invoke
* @return the value returned by the callable
* @throws CommandException in case the callable failed with an Exception
*/
public static <T> T getOrThrow(String description, Callable<T> callable) throws CommandException {
try {
return callable.call();
} catch (Exception cause) {
// TODO see isDeveloper() idea in Texts.fromThrowable
throw new CommandException(Texts.fromThrowable(description, cause), cause, true);
}
}

public static void doOrThrow(String description, RunnableWithException runnable) throws CommandException {
try {
runnable.run();
} catch (Exception cause) {
// TODO once the cause is properly throw to the user incl. stack trace, this log is probably redundant; then remove?
LOG.error("doOrThrow()", cause);
// TODO see isDeveloper() idea in Texts.fromThrowable
throw new CommandException(Texts.fromThrowable(description, cause), cause, true);
}
}

public static CommandException create(String message) {
return new CommandException(Texts.inRed(message));
}

@FunctionalInterface
public interface RunnableWithException {
void run() throws Exception;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* ch.vorburger.minecraft.storeys
*
* Copyright (C) 2016 - 2018 Michael Vorburger.ch <[email protected]>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package ch.vorburger.minecraft.storeys.japi.util;

import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.format.TextColors;

/**
* Utilities for {@link Text}.
*
* @author Michael Vorburger.ch
*/
public final class Texts {

// Copy/pasted from https://github.com/vorburger/ch.vorburger.minecraft.osgi/blob/master/ch.vorburger.minecraft.osgi.api/src/main/java/ch/vorburger/minecraft/utils/Texts.java

private Texts() {
}

public static Text 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();
// 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();
}
}
5 changes: 5 additions & 0 deletions api-jvm/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

// TODO Build refactoring so that this module inherits only spongeapi WITHOUT everything else from the subprojects {} in ../build.gradle

dependencies {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* ch.vorburger.minecraft.storeys
*
* Copyright (C) 2016 - 2018 Michael Vorburger.ch <[email protected]>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package ch.vorburger.minecraft.storeys.japi;

@FunctionalInterface
public interface Callback {

void invoke(Minecraft m) throws Exception;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* ch.vorburger.minecraft.storeys
*
* Copyright (C) 2016 - 2018 Michael Vorburger.ch <[email protected]>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package ch.vorburger.minecraft.storeys.japi;

public interface Events {

// This is intentionally NOT returning CommandResult, to keep it simple, for scripting.
void whenCommand(String name, Callback callback);

// TODO add more "event handlers" here; see
// https://github.com/OASIS-learn-study/minecraft-storeys-maker/blob/develop/api/src/main/typescript/observable-wrapper.ts
}
Loading

0 comments on commit c86bf66

Please sign in to comment.