diff --git a/.env b/.env deleted file mode 100644 index 7fbd36d4..00000000 --- a/.env +++ /dev/null @@ -1 +0,0 @@ -TEST_VALUE=hello \ No newline at end of file diff --git a/.env.sample b/.env.sample new file mode 100644 index 00000000..03fd0f69 --- /dev/null +++ b/.env.sample @@ -0,0 +1,2 @@ +# Path to a local copy of hollow-cube/common. Required for now. +COMMON_LIB_PATH=../common \ No newline at end of file diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 376095a2..ee491058 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -12,12 +12,23 @@ jobs: steps: - uses: actions/checkout@v2 + with: + path: libmmo + - name: Set up libmmo env + working-directory: libmmo + run: cp .env.sample .env + - name: Checkout common project + uses: actions/checkout@v2 + with: + repository: hollow-cube/common + path: common - name: Set up JDK 17 uses: actions/setup-java@v2 with: distribution: 'zulu' java-version: 17 - name: Grant execute permission for gradlew + working-directory: libmmo run: chmod +x gradlew - name: Setup gradle cache uses: burrunan/gradle-cache-action@v1 @@ -30,6 +41,8 @@ jobs: maven-local-ignore-paths: | starlight/mmo/ - name: Build + working-directory: libmmo run: ./gradlew classes testClasses - name: Run tests + working-directory: libmmo run: ./gradlew test diff --git a/.gitignore b/.gitignore index 8bd6ed5b..664b032c 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ bin/ !.github log.txt + +.env \ No newline at end of file diff --git a/README.md b/README.md index 2c7d9570..a32124a0 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,14 @@ todo todo +## Using a local copy of `hollow-cube/common` +> Currently, this is the only option. When the libraries are properly versioned in the future this will be optional. + +1. Ensure you have a local copy of `hollow-cube/common` on your machine. +2. Create a copy of the sample `.env` file in the root of this project, eg `cp .env.sample .env`. +3. Ensure `COMMON_LIB_PATH` points to the location of your local copy of `hollow-cube/common`. +4. Reload the gradle project. + # Project Structure The project is split into a set of modules, each one representing a unique feature. The modules may be used diff --git a/modules/block-interactions/build.gradle.kts b/modules/block-interactions/build.gradle.kts index 2275e458..fcd026bb 100644 --- a/modules/block-interactions/build.gradle.kts +++ b/modules/block-interactions/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } dependencies { - implementation(project(":modules:common")) + implementation("net.hollowcube.common:common:0.0.0") implementation(project(":modules:item")) implementation(project(":modules:loot-table")) implementation(project(":modules:player")) diff --git a/modules/build.gradle.kts b/modules/build.gradle.kts index aff7755e..9f132148 100644 --- a/modules/build.gradle.kts +++ b/modules/build.gradle.kts @@ -32,7 +32,7 @@ subprojects { implementation("com.github.minestommmo:Minestom:c6c97162a6") // Testing - testImplementation(project(":modules:test")) + testImplementation("net.hollowcube.common:test:0.0.0") } tasks.getByName("test") { diff --git a/modules/chat/build.gradle.kts b/modules/chat/build.gradle.kts index 516280c8..ea9ff6d4 100644 --- a/modules/chat/build.gradle.kts +++ b/modules/chat/build.gradle.kts @@ -1,5 +1,5 @@ dependencies { - implementation(project(":modules:common")) + implementation("net.hollowcube.common:common:0.0.0") implementation("org.mongodb:mongodb-driver-sync:4.7.0") } diff --git a/modules/common/README.md b/modules/common/README.md deleted file mode 100644 index df8b896a..00000000 --- a/modules/common/README.md +++ /dev/null @@ -1,11 +0,0 @@ -## common - -Common libraries for other modules in the project. - -Included by all other projects, so this must be kept small with minimal dependencies. - -``` -data: Data parsing abstraction -registry: Resource registry for various data driven modules -util: Common utilities -``` diff --git a/modules/common/build.gradle.kts b/modules/common/build.gradle.kts deleted file mode 100644 index 1473429c..00000000 --- a/modules/common/build.gradle.kts +++ /dev/null @@ -1,17 +0,0 @@ -plugins { - `java-library` -} - -dependencies { - api("com.github.minestommmo:DataFixerUpper:cf58e926a6") - api("net.kyori:adventure-text-minimessage:4.11.0") - - implementation("org.tinylog:tinylog-impl:2.4.1") - - implementation("io.github.cdimascio:dotenv-java:2.2.4") - - // Optional components - compileOnly("org.mongodb:mongodb-driver-sync:4.7.0") - - -} diff --git a/modules/common/src/main/java/net/hollowcube/Env.java b/modules/common/src/main/java/net/hollowcube/Env.java deleted file mode 100644 index cd9bf1f6..00000000 --- a/modules/common/src/main/java/net/hollowcube/Env.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.hollowcube; - -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.function.Supplier; - -public class Env { - /** - * Strict mode is enabled in production, but may be disabled during tests. - *

- * It should be used to check cases which are fine during development but are a fatal problem in production. For - * example, if a registry is empty for any reason in production the server should not be allowed to start. - */ - public static final Boolean STRICT_MODE = Boolean.valueOf(System.getProperty("starlight.strict", "false")); - - - private static final Logger STRICT_LOGGER = LoggerFactory.getLogger("STRICT"); - - public static void strictValidation(@NotNull String message, @NotNull Supplier predicate) { - if (STRICT_MODE && predicate.get()) { - STRICT_LOGGER.error(message); - System.exit(1); - } - } - -} diff --git a/modules/common/src/main/java/net/hollowcube/config/ConfigProvider.java b/modules/common/src/main/java/net/hollowcube/config/ConfigProvider.java deleted file mode 100644 index cd363eb3..00000000 --- a/modules/common/src/main/java/net/hollowcube/config/ConfigProvider.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.hollowcube.config; - -import com.mojang.serialization.Codec; -import net.minestom.server.utils.validate.Check; -import org.jetbrains.annotations.NotNull; -import net.hollowcube.dfu.EnvVarOps; - -import java.util.Locale; - -public final class ConfigProvider { - - public static @NotNull T load(@NotNull String prefix, @NotNull Codec codec) { - var result = EnvVarOps.DOTENV.withDecoder(codec) - .apply(prefix.toUpperCase(Locale.ROOT)) - .result() - .orElse(null); - Check.notNull(result, "Config unable to load"); - return result.getFirst(); - } -} diff --git a/modules/common/src/main/java/net/hollowcube/data/NumberSource.java b/modules/common/src/main/java/net/hollowcube/data/NumberSource.java deleted file mode 100644 index 4a125afc..00000000 --- a/modules/common/src/main/java/net/hollowcube/data/NumberSource.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.hollowcube.data; - -import org.jetbrains.annotations.NotNull; - -import java.util.concurrent.ThreadLocalRandom; - -/** - * A source of numbers, implementations decide where the numbers come from - */ -@FunctionalInterface -public interface NumberSource { - - static @NotNull NumberSource constant(double value) { - return () -> value; - } - - static @NotNull NumberSource threadLocalRandom() { - return () -> ThreadLocalRandom.current().nextDouble(); - } - - - double random(); - -} diff --git a/modules/common/src/main/java/net/hollowcube/data/number/ConstantNumberProvider.java b/modules/common/src/main/java/net/hollowcube/data/number/ConstantNumberProvider.java deleted file mode 100644 index 398321f2..00000000 --- a/modules/common/src/main/java/net/hollowcube/data/number/ConstantNumberProvider.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.hollowcube.data.number; - -import com.google.auto.service.AutoService; -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.hollowcube.data.NumberSource; -import net.minestom.server.utils.NamespaceID; -import org.jetbrains.annotations.NotNull; -import net.hollowcube.dfu.ExtraCodecs; - -record ConstantNumberProvider( - @NotNull Number value -) implements NumberProvider { - - public static Codec CODEC = RecordCodecBuilder.create(i -> i.group( - ExtraCodecs.NUMBER.fieldOf("value").forGetter(ConstantNumberProvider::value) - ).apply(i, ConstantNumberProvider::new)); - - - @Override - public long nextLong(@NotNull NumberSource numbers) { - return value().longValue(); - } - - @Override - public double nextDouble(@NotNull NumberSource numbers) { - return value().doubleValue(); - } - - - @AutoService(NumberProvider.Factory.class) - public static final class Factory extends NumberProvider.Factory { - public Factory() { - super( - NamespaceID.from("starlight:constant"), - ConstantNumberProvider.class, - ConstantNumberProvider.CODEC - ); - } - } - -} diff --git a/modules/common/src/main/java/net/hollowcube/data/number/NumberProvider.java b/modules/common/src/main/java/net/hollowcube/data/number/NumberProvider.java deleted file mode 100644 index 294e09cb..00000000 --- a/modules/common/src/main/java/net/hollowcube/data/number/NumberProvider.java +++ /dev/null @@ -1,79 +0,0 @@ -package net.hollowcube.data.number; - -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Codec; -import net.hollowcube.registry.Registry; -import net.hollowcube.registry.ResourceFactory; -import net.minestom.server.utils.NamespaceID; -import org.jetbrains.annotations.NotNull; -import net.hollowcube.data.NumberSource; -import net.hollowcube.dfu.DFUUtil; -import net.hollowcube.dfu.ExtraCodecs; - -/** - * A source of numbers, see Number - * Providers. - *

- * Implementing a new number source requires a few steps: - *

    - *
  1. Create a class inheriting from {@link NumberProvider}
  2. - *
  3. Write a {@link Codec} for the class
  4. - *
  5. Create an inner factory class inheriting from {@link NumberProvider.Factory}, filling in the required constructor params
  6. - *
  7. Annotate the factory class with {@link com.google.auto.service.AutoService} for {@link NumberProvider.Factory}
  8. - *
- *

- * Would like to look into a simplification of this process & removal of the Factory class. I would prefer if it was something like the following - *

{@code
- *     // This, where the annotation generates an entry for the superclass
- *     @BasicRegistryItem("minecraft:constant")
- *     public record ConstantNumberProvider(
- *         Number value
- *     ) implements NumberProvider {
- *
- *         Codec CODEC = ...;
- *
- *         // Or alternatively something like this, where it finds the descriptor element
- *         Descriptor DESCRIPTOR = new Descriptor("minecraft:constant", CODEC){}
- *
- *     }
- * }
- * - * @see ConstantNumberProvider - */ -public interface NumberProvider { - - static @NotNull NumberProvider constant(@NotNull Number value) { - return new ConstantNumberProvider(value); - } - - Codec CODEC = Codec.either( - Factory.CODEC.dispatch(Factory::from, Factory::codec), - // Handle the case of providing a single value value. If serialized back it will - // come out as a full {"type": "constant", "value": ...} - ExtraCodecs.NUMBER.xmap(ConstantNumberProvider::new, ConstantNumberProvider::value) - ).xmap(DFUUtil::value, Either::left); - - - // Impl - - long nextLong(@NotNull NumberSource numbers); - - double nextDouble(@NotNull NumberSource numbers); - - - abstract class Factory extends ResourceFactory { - static Registry REGISTRY = Registry.service("number_providers", NumberProvider.Factory.class); - static Registry.Index, NumberProvider.Factory> TYPE_REGISTRY = REGISTRY.index(NumberProvider.Factory::type); - - public static final Codec CODEC = Codec.STRING.xmap(ns -> REGISTRY.get(ns), Factory::name); - - public Factory(NamespaceID namespace, Class type, Codec codec) { - super(namespace, type, codec); - } - - static @NotNull Factory from(@NotNull NumberProvider provider) { - return TYPE_REGISTRY.get(provider.getClass()); - } - } - -} diff --git a/modules/common/src/main/java/net/hollowcube/dfu/DFUUtil.java b/modules/common/src/main/java/net/hollowcube/dfu/DFUUtil.java deleted file mode 100644 index 424f8d36..00000000 --- a/modules/common/src/main/java/net/hollowcube/dfu/DFUUtil.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.hollowcube.dfu; - -import com.mojang.datafixers.util.Either; -import com.mojang.datafixers.util.Pair; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -public final class DFUUtil { - - public static Map pairListToMap(List> pairList) { - return pairList.stream().collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)); - } - - public static List> mapToPairList(Map map) { - return map.entrySet().stream().map(entry -> new Pair<>(entry.getKey(), entry.getValue())).toList(); - } - - public static @NotNull T value(@NotNull Either either) { - return either.map(Function.identity(), Function.identity()); - } -} diff --git a/modules/common/src/main/java/net/hollowcube/dfu/EnvVarOps.java b/modules/common/src/main/java/net/hollowcube/dfu/EnvVarOps.java deleted file mode 100644 index c74221b6..00000000 --- a/modules/common/src/main/java/net/hollowcube/dfu/EnvVarOps.java +++ /dev/null @@ -1,224 +0,0 @@ -package net.hollowcube.dfu; - -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.MapLike; -import io.github.cdimascio.dotenv.Dotenv; -import io.github.cdimascio.dotenv.DotenvEntry; -import kotlin.NotImplementedError; -import net.minestom.server.utils.validate.Check; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -import java.util.*; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.stream.Stream; - -public abstract class EnvVarOps implements DynamicOps { - public static final EnvVarOps DOTENV = new EnvVarOps() { - private final Dotenv dotenv = Dotenv.configure().ignoreIfMissing().load(); - - @Override - protected Collection envKeys() { - return dotenv.entries().stream().map(DotenvEntry::getKey).toList(); - } - - @Override - protected String get(String path) { - if (path.isEmpty()) - return ""; - return dotenv.get(path); - } - }; - - @Override - public String empty() { - return ""; - } - - @Override - public DataResult getNumberValue(String input) { - String value = get(input); - - // This is really primitive number parsing, but I guess it will work. - try { - if (value.contains(".")) { - return DataResult.success(Double.parseDouble(value)); - } else { - return DataResult.success(Long.parseLong(value)); - } - } catch (NumberFormatException e) { - return DataResult.error(e.getMessage()); - } - } - - @Override - public DataResult getBooleanValue(String input) { - String value = get(input).toLowerCase(Locale.ROOT); - // Do not use Boolean.parseBoolean because it treats invalid as false. - if (value.equals("true")) - return DataResult.success(true); - if (value.equals("false")) - return DataResult.success(false); - return DataResult.error("Not a boolean: " + input); - } - - @Override - public DataResult getStringValue(String input) { - return DataResult.success(get(input)); - } - - @Override - public DataResult> getMap(String input) { - // All the available keys starting with the input prefix - Set possibleKeys = new HashSet<>(); - for (String path : envKeys()) { - if (path.toUpperCase(Locale.ROOT).startsWith(input)) { - possibleKeys.add(path); - } - } - - return DataResult.success(new MapLike<>() { - @Override - public String get(String key) { - // Create the new path by appending to the original query path - String newPath = key.toUpperCase(Locale.ROOT); - if (!input.isEmpty()) { - newPath = input + "_" + newPath; - } - - // The map contains any path starting with this one, so we need to iterate over it. - for (var entryKey : possibleKeys) { - if (entryKey.startsWith(newPath)) { - // Return the new path. entryKey contains the entire path - return newPath; - } - } - - return null; - } - - @Override - public Stream> entries() { - return notImplemented("getMap -> entries"); - } - }); - } - - @Override - public DataResult>> getList(String input) { - // Children contains every path which starts with input and is followed by a single number segment - Map children = new HashMap<>(); // (map to ignore duplicate keys) - for (String path : envKeys()) { - if (!path.toUpperCase(Locale.ROOT).startsWith(input)) - continue; - String[] rest = path.substring(input.length()).split("_", -1); - // First entry must be "" because we split on _00_REST - if (rest.length < 2 || !rest[0].isEmpty()) - continue; - // Try to parse number segment - int index = Integer.parseInt(rest[1]); - children.put(index, input + "_" + index); - } - - // Sort on index - String[] sortedChildren = new String[children.size()]; - for (var child : children.entrySet()) { - // If the child is not within the sorted range then there was an order problem in the original (eg skipping a number) - if (child.getKey() < 0 || child.getKey() >= children.size()) - return DataResult.error(String.format("invalid index of %s: %s", input, child)); - sortedChildren[child.getKey()] = child.getValue(); - } - - return DataResult.success(c -> { - for (var child : sortedChildren) { - Check.notNull(child, "missing list element"); - c.accept(child); - } - }); - } - - @Override - public String createList(Stream input) { - return "ERR@createList"; - } - - // NOT IMPLEMENTED BELOW - // The rest of DynamicOps is not implemented. The reasons are: - // - Serialization is not supported by EnvVarOps. - // - I have not found a use for the function. If we find one it will be implemented. - - @Override - public U convertTo(DynamicOps outOps, String input) { - //todo - throw new NotImplementedError("convertTo"); - } - - @Override - public String createNumeric(Number i) { - return notImplemented("createNumeric"); - } - - @Override - public String createBoolean(boolean value) { - return notImplemented("createBoolean"); - } - - @Override - public String createString(String value) { - return notImplemented("createString"); - } - - @Override - public DataResult mergeToList(String list, String value) { - throw new NotImplementedError("mergeToList"); - } - - @Override - public DataResult mergeToMap(String map, String key, String value) { - return notImplemented("mergeToMap@3"); - } - - @Override - public DataResult mergeToMap(String map, MapLike values) { - throw new NotImplementedError("mergeToMap@2"); - } - - @Override - public DataResult>> getMapValues(String input) { - throw new NotImplementedError("getMapValues"); - } - - @Override - public DataResult>> getMapEntries(String input) { - throw new NotImplementedError("getMapEntries"); - } - - @Override - public String createMap(Stream> map) { - return notImplemented("createMap"); - } - - @Override - public DataResult> getStream(String input) { - return notImplemented("getStream"); - } - - @Override - public String remove(String input, String key) { - return notImplemented("remove"); - } - - - protected abstract Collection envKeys(); - - protected abstract String get(String path); - - @Contract("_ -> fail") - @SuppressWarnings("TypeParameterUnusedInFormals") - private T notImplemented(@NotNull String name) { - throw new NotImplementedError("EnvVarOps#" + name); - } -} diff --git a/modules/common/src/main/java/net/hollowcube/dfu/ExtraCodecs.java b/modules/common/src/main/java/net/hollowcube/dfu/ExtraCodecs.java deleted file mode 100644 index 1e42a46f..00000000 --- a/modules/common/src/main/java/net/hollowcube/dfu/ExtraCodecs.java +++ /dev/null @@ -1,77 +0,0 @@ -package net.hollowcube.dfu; - -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.MapCodec; -import com.mojang.serialization.codecs.PrimitiveCodec; -import net.minestom.server.instance.block.Block; -import net.minestom.server.item.Material; -import net.minestom.server.potion.PotionEffect; -import net.minestom.server.utils.NamespaceID; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Locale; -import java.util.function.Supplier; - -public final class ExtraCodecs { - private ExtraCodecs() {} - - public static final PrimitiveCodec NUMBER = new PrimitiveCodec<>() { - @Override - public DataResult read(DynamicOps ops, T input) { - return ops.getNumberValue(input); - } - - @Override - public T write(DynamicOps ops, Number value) { - return ops.createNumeric(value); - } - }; - - public static final Codec NAMESPACE_ID = Codec.STRING.xmap(NamespaceID::from, NamespaceID::asString); - - public static final Codec MATERIAL = Codec.STRING.xmap(Material::fromNamespaceId, Material::name); - - public static final Codec POTION_EFFECT = Codec.STRING.xmap(PotionEffect::fromNamespaceId, PotionEffect::name); - - public static final Codec BLOCK = Codec.STRING.xmap(Block::fromNamespaceId, Block::name); - - public static @NotNull MapCodec string(@NotNull String name, @Nullable String defaultValue) { - return Codec.STRING.optionalFieldOf(name, defaultValue); - } - - public static > @NotNull Codec forEnum(Class type) { - return Codec.STRING.xmap(s -> Enum.valueOf(type, s.toUpperCase(Locale.ROOT)), e -> e.name().toLowerCase(Locale.ROOT)); - } - - public static @NotNull Codec lazy(Supplier> init) { - return new LazyCodec<>(init); - } - - - public static class LazyCodec implements Codec { - private final Supplier> init; - private Codec value = null; - - LazyCodec(Supplier> init) { - this.init = init; - } - - @Override - public DataResult> decode(DynamicOps ops, T1 input) { - if (value == null) value = init.get(); - return value.decode(ops, input); - } - - @Override - public DataResult encode(T input, DynamicOps ops, T1 prefix) { - if (value == null) value = init.get(); - return value.encode(input, ops, prefix); - } - } - - -} diff --git a/modules/common/src/main/java/net/hollowcube/lang/LanguageProvider.java b/modules/common/src/main/java/net/hollowcube/lang/LanguageProvider.java deleted file mode 100644 index 11c39f8b..00000000 --- a/modules/common/src/main/java/net/hollowcube/lang/LanguageProvider.java +++ /dev/null @@ -1,72 +0,0 @@ -package net.hollowcube.lang; - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.TextReplacementConfig; -import net.kyori.adventure.text.TranslatableComponent; -import org.jetbrains.annotations.NotNull; -import net.hollowcube.util.ComponentUtil; - -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.Properties; -import java.util.regex.Pattern; - -/** - * Naive component translation system. - *

- * Should be replaced with adventure translation or something else in the future. - */ -public class LanguageProvider { - private static final Properties properties = new Properties(); - - static { - try (InputStream is = LanguageProvider.class.getResourceAsStream("/lang/en_US.properties")) { - if (is != null) { - properties.load(is); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private static final Pattern ARG_PATTERN = Pattern.compile("\\{[0-9]+}"); - - /** - * Translates a component (if possible, see below). - *

- * If the component is a {@link TranslatableComponent}, it will attempt to be translated. Any arguments in the - * component will also be templated into the translation using the {@link java.text.MessageFormat} syntax of `{0}`, - * `{1}`, etc. Translations are parsed using MiniMessage, and may contain styling as such. - *

- * Translations are always (for now) loaded from `/lang/en_US.properties` within the classpath. This system is - * temporary, and will be replaced with either a proxy translation system or using the Adventure translation system. - * The problem with the adventure translation system is that it does not support MiniMessage in translation strings - * as far as I can tell. - * - * @param component The component to translate - * @return The component, or a component holding just the translation key if not found - */ - public static @NotNull Component get(@NotNull Component component) { - if (!(component instanceof TranslatableComponent translatable)) { - return component; - } - String value = properties.getProperty(translatable.key()); - if (value == null) return Component.text(translatable.key()); - Component translated = ComponentUtil.fromStringSafe(value); - List args = translatable.args(); - if (args.size() != 0) { - //todo this seems like it could be wildly slow... - translated = translated.replaceText(TextReplacementConfig.builder() - .match(ARG_PATTERN) - .replacement((result, builder) -> { - var group = result.group(); - int index = Integer.parseInt(group.substring(1, group.length() - 1)); - return index < args.size() ? - args.get(index) : - Component.text("$$" + index); - }).build()); - } - return translated; - } -} diff --git a/modules/common/src/main/java/net/hollowcube/logging/CustomJsonWriter.java b/modules/common/src/main/java/net/hollowcube/logging/CustomJsonWriter.java deleted file mode 100644 index 209bccf0..00000000 --- a/modules/common/src/main/java/net/hollowcube/logging/CustomJsonWriter.java +++ /dev/null @@ -1,155 +0,0 @@ -package net.hollowcube.logging; - -import com.google.auto.service.AutoService; -import org.tinylog.core.LogEntry; -import org.tinylog.core.LogEntryValue; -import org.tinylog.pattern.FormatPatternParser; -import org.tinylog.pattern.Token; -import org.tinylog.writers.AbstractFileBasedWriter; -import org.tinylog.writers.Writer; -import org.tinylog.writers.raw.ByteArrayWriter; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.*; -import java.util.Map.Entry; - -/** - * Copy of {@link org.tinylog.writers.JsonWriter} with some modifications to join the config with the log - */ -@AutoService(Writer.class) -public final class CustomJsonWriter extends AbstractFileBasedWriter { - - private static final String NEW_LINE = System.getProperty("line.separator"); - private static final String FIELD_PREFIX = "field."; - - private final Charset charset; - private final ByteArrayWriter writer; - - private StringBuilder builder; - private final Map jsonProperties; - - public CustomJsonWriter() throws IOException { - this(Collections.emptyMap()); - } - - public CustomJsonWriter(final Map properties) throws IOException { - super(properties); - - String fileName = getFileName(); - boolean append = getBooleanValue("append"); - boolean buffered = getBooleanValue("buffered"); - boolean writingThread = getBooleanValue("writingthread"); - - charset = getCharset(); - writer = createByteArrayWriter(fileName, append, buffered, !writingThread, false, charset); - - jsonProperties = createTokens(properties); - - if (writingThread) { - builder = new StringBuilder(); - } - } - - @Override - public void write(final LogEntry logEntry) throws IOException { - StringBuilder builder; - if (this.builder == null) { - builder = new StringBuilder(); - } else { - builder = this.builder; - builder.setLength(0); - } - - addJsonObject(logEntry, builder); - - byte[] data = builder.toString().getBytes(charset); - writer.write(data, 0, data.length); - } - - @Override - public void flush() throws IOException { - writer.flush(); - } - - @Override - public void close() throws IOException { - writer.flush(); - writer.close(); - } - - @Override - public Collection getRequiredLogEntryValues() { - Collection values = EnumSet.noneOf(LogEntryValue.class); - values.add(LogEntryValue.CONTEXT); - for (Token token : jsonProperties.values()) { - values.addAll(token.getRequiredLogEntryValues()); - } - return values; - } - - private void addJsonObject(final LogEntry logEntry, final StringBuilder builder) { - builder.append("{"); - - Map entries = new HashMap<>(); - if (logEntry.getContext() != null) - entries.putAll(logEntry.getContext()); - entries.putAll(jsonProperties); - - Object[] tokenEntries = entries.values().toArray(new Object[0]); - String[] fields = entries.keySet().toArray(new String[0]); - - for (int i = 0; i < tokenEntries.length; i++) { - builder.append("\"").append(fields[i]).append("\":\""); - int start = builder.length(); - - Object entry = tokenEntries[i]; - if (entry instanceof Token token) { - token.render(logEntry, builder); - } else { - builder.append(entry.toString()); - } - - escapeCharacter("\\", "\\\\", builder, start); - escapeCharacter("\"", "\\\"", builder, start); - escapeCharacter(NEW_LINE, "\\n", builder, start); - escapeCharacter("\t", "\\t", builder, start); - escapeCharacter("\b", "\\b", builder, start); - escapeCharacter("\f", "\\f", builder, start); - escapeCharacter("\n", "\\n", builder, start); - escapeCharacter("\r", "\\r", builder, start); - - builder.append("\""); - - if (i + 1 < entries.size()) { - builder.append(","); - } - } - builder.append("}").append(NEW_LINE); - } - - private void escapeCharacter(final String character, final String escapeWith, final StringBuilder stringBuilder, - final int startIndex) { - for ( - int index = stringBuilder.indexOf(character, startIndex); - index != -1; - index = stringBuilder.indexOf(character, index + escapeWith.length()) - ) { - stringBuilder.replace(index, index + character.length(), escapeWith); - } - } - - private static Map createTokens(final Map properties) { - FormatPatternParser parser = new FormatPatternParser(properties.get("exception")); - - Map tokens = new HashMap<>(); - for (Entry entry : properties.entrySet()) { - if (entry.getKey().toLowerCase(Locale.ROOT).startsWith(FIELD_PREFIX)) { - tokens.put(entry.getKey().substring(FIELD_PREFIX.length()), parser.parse(entry.getValue())); - } - } - return tokens; - } - -} - diff --git a/modules/common/src/main/java/net/hollowcube/logging/Logger.java b/modules/common/src/main/java/net/hollowcube/logging/Logger.java deleted file mode 100644 index 692bd327..00000000 --- a/modules/common/src/main/java/net/hollowcube/logging/Logger.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.hollowcube.logging; - -import org.jetbrains.annotations.NotNull; - -import java.util.Map; - -/** - * SLF4J wrapper with a sane API for MDC. - *

- * Context variables are important for searching within log tools such as Loki (grafana) and the default usage of MDC is - * extremely verbose and error-prone. - *

- * Create using {@link LoggerFactory}. - */ -public interface Logger { - - void debug(@NotNull String message); - - void debug(@NotNull String message, @NotNull Map context); - - void info(@NotNull String message); - - void info(@NotNull String message, @NotNull Map context); - - void warn(@NotNull String message); - - void warn(@NotNull String message, @NotNull Map context); - - void error(@NotNull String message); - - void error(@NotNull String message, @NotNull Map context); - -} diff --git a/modules/common/src/main/java/net/hollowcube/logging/LoggerFactory.java b/modules/common/src/main/java/net/hollowcube/logging/LoggerFactory.java deleted file mode 100644 index 53d36838..00000000 --- a/modules/common/src/main/java/net/hollowcube/logging/LoggerFactory.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.hollowcube.logging; - -import org.jetbrains.annotations.NotNull; - -public final class LoggerFactory { - private LoggerFactory() {} - - public static @NotNull Logger getLogger(@NotNull Class clazz) { - return new LoggerImpl(org.slf4j.LoggerFactory.getLogger(clazz)); - } - -} diff --git a/modules/common/src/main/java/net/hollowcube/logging/LoggerImpl.java b/modules/common/src/main/java/net/hollowcube/logging/LoggerImpl.java deleted file mode 100644 index d75d9875..00000000 --- a/modules/common/src/main/java/net/hollowcube/logging/LoggerImpl.java +++ /dev/null @@ -1,98 +0,0 @@ -package net.hollowcube.logging; - -import org.jetbrains.annotations.NotNull; -import org.slf4j.MDC; - -import java.util.Map; - -record LoggerImpl(org.slf4j.Logger delegate) implements Logger { - - @Override - public void debug(@NotNull String message) { - debug(message, Map.of()); - } - - @Override - public void debug(@NotNull String message, @NotNull Map context) { - if (!delegate.isDebugEnabled()) return; - - for (var entry : context.entrySet()) { - put(entry.getKey(), entry.getValue()); - } - - delegate.debug(message); - - for (var key : context.keySet()) { - remove(key); - } - } - - - @Override - public void info(@NotNull String message) { - info(message, Map.of()); - } - - @Override - public void info(@NotNull String message, @NotNull Map context) { - if (!delegate.isInfoEnabled()) return; - - for (var entry : context.entrySet()) { - put(entry.getKey(), entry.getValue()); - } - - delegate.info(message); - - for (var key : context.keySet()) { - remove(key); - } - } - - @Override - public void warn(@NotNull String message) { - warn(message, Map.of()); - } - - @Override - public void warn(@NotNull String message, @NotNull Map context) { - if (!delegate.isWarnEnabled()) return; - - for (var entry : context.entrySet()) { - put(entry.getKey(), entry.getValue()); - } - - delegate.warn(message); - - for (var key : context.keySet()) { - remove(key); - } - } - - @Override - public void error(@NotNull String message) { - error(message, Map.of()); - } - - @Override - public void error(@NotNull String message, @NotNull Map context) { - if (!delegate.isErrorEnabled()) return; - - for (var entry : context.entrySet()) { - put(entry.getKey(), entry.getValue()); - } - - delegate.error(message); - - for (var key : context.keySet()) { - remove(key); - } - } - - private void put(String key, Object value) { - MDC.put(key, value == null ? null : value.toString()); - } - - private void remove(String key) { - MDC.remove(key); - } -} diff --git a/modules/common/src/main/java/net/hollowcube/mongo/BsonOps.java b/modules/common/src/main/java/net/hollowcube/mongo/BsonOps.java deleted file mode 100644 index 0a53a460..00000000 --- a/modules/common/src/main/java/net/hollowcube/mongo/BsonOps.java +++ /dev/null @@ -1,294 +0,0 @@ -package net.hollowcube.mongo; - -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.MapLike; -import org.bson.*; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.stream.Stream; - -/** - * DFU {@link DynamicOps} implementation for BSON values. - *

- * The official BSON library _does_ support direct reflection based object mapping, however, since codecs are being used - * in many other places, it makes some sense to use them here too. It generalizes storage implementations to simply use - * the codec for a type. - *

- * todo its possible this will be problematic because it is not using the real bson types (eg bson date), - * but I dont expect this to be a huge issue. - */ -public class BsonOps implements DynamicOps { - - public static final BsonOps INSTANCE = new BsonOps(); - - private BsonOps() {} - - @Override - public BsonValue empty() { - return BsonNull.VALUE; - } - - @Override - public U convertTo(DynamicOps outOps, BsonValue input) { - if (input instanceof BsonDocument) { - return convertMap(outOps, input); - } - if (input instanceof BsonArray) { - return convertList(outOps, input); - } - if (input instanceof BsonNull) { - return outOps.empty(); - } - //todo other bson types - return null; - } - - @Override - public DataResult getNumberValue(BsonValue input) { - if (input instanceof BsonNumber number) { - return DataResult.success(new BsonNumberWrapper(number)); - } - if (input instanceof BsonBoolean bool) { - return DataResult.success(bool.getValue() ? 1 : 0); - } - return DataResult.error("Not a number: " + input); - } - - @Override - public BsonValue createNumeric(Number i) { - if (i instanceof Byte || i instanceof Short || i instanceof Integer) { - return new BsonInt32(i.intValue()); - } - if (i instanceof Long) { - return new BsonInt64(i.longValue()); - } - if (i instanceof Float || i instanceof Double) { - return new BsonDouble(i.doubleValue()); - } - throw new IllegalArgumentException("Unknown number type: " + i.getClass().getSimpleName() + " (" + i + ")"); - } - - @Override - public DataResult getStringValue(BsonValue input) { - if (input instanceof BsonString string) { - return DataResult.success(string.getValue()); - } - return DataResult.error("Not a string: " + input); - } - - @Override - public BsonValue createString(String value) { - return new BsonString(value); - } - - @Override - public DataResult mergeToList(BsonValue list, BsonValue value) { - if (!(list instanceof BsonArray) && list != empty()) { - return DataResult.error("mergeToList called with not a list: " + list, list); - } - - final BsonArray result = new BsonArray(); - if (list != empty()) { - result.addAll(list.asArray()); - } - result.add(value); - return DataResult.success(result); - } - - @Override - public DataResult mergeToList(BsonValue list, List values) { - if (!(list instanceof BsonArray) && list != empty()) { - return DataResult.error("mergeToList called with not a list: " + list, list); - } - - final BsonArray result = new BsonArray(); - if (list != empty()) { - result.addAll(list.asArray()); - } - result.addAll(values); - return DataResult.success(result); - } - - @Override - public DataResult mergeToMap(BsonValue map, BsonValue key, BsonValue value) { - if (!(map instanceof BsonDocument) && map != empty()) { - return DataResult.error("mergeToMap called with not a map: " + map, map); - } - if (!(key instanceof BsonString keyString)) { - return DataResult.error("key is not a string: " + key, map); - } - - final BsonDocument output = new BsonDocument(); - if (map != empty()) { - output.putAll(map.asDocument()); - } - output.put(keyString.getValue(), value); - - return DataResult.success(output); - } - - @Override - public DataResult mergeToMap(BsonValue map, MapLike values) { - if (!(map instanceof BsonDocument) && map != empty()) { - return DataResult.error("mergeToMap called with not a map: " + map, map); - } - - final BsonDocument output = new BsonDocument(); - if (map != empty()) { - output.putAll(map.asDocument()); - } - - final List missed = new ArrayList<>(); - - values.entries().forEach(entry -> { - final BsonValue key = entry.getFirst(); - if (!(key instanceof BsonString keyString)) { - missed.add(key); - return; - } - output.put(keyString.getValue(), entry.getSecond()); - }); - - if (!missed.isEmpty()) { - return DataResult.error("some keys are not strings: " + missed, output); - } - - return DataResult.success(output); - } - - @Override - public DataResult>> getMapValues(BsonValue input) { - if (!(input instanceof BsonDocument document)) { - return DataResult.error("Not a bson document: " + input); - } - return DataResult.success(document.entrySet().stream().map(entry -> Pair.of( - new BsonString(entry.getKey()), - entry.getValue() instanceof BsonNull ? null : entry.getValue()) - )); - } - - @Override - public DataResult>> getMapEntries(BsonValue input) { - if (!(input instanceof BsonDocument document)) { - return DataResult.error("Not a bson document: " + input); - } - return DataResult.success(c -> { - for (final Map.Entry entry : document.entrySet()) { - c.accept(createString(entry.getKey()), entry.getValue() instanceof BsonNull ? null : entry.getValue()); - } - }); - } - - @Override - public DataResult> getMap(BsonValue input) { - if (!(input instanceof BsonDocument document)) { - return DataResult.error("Not a bson document: " + input); - } - return DataResult.success(new MapLike<>() { - @Override - public @Nullable BsonValue get(final BsonValue key) { - final BsonValue value = document.get(key.asString().getValue()); - return value instanceof BsonNull ? null : value; - } - - @Override - public @Nullable BsonValue get(final String key) { - final BsonValue value = document.get(key); - return value instanceof BsonNull ? null : value; - } - - @Override - public Stream> entries() { - return document.entrySet().stream().map(e -> Pair.of(new BsonString(e.getKey()), e.getValue())); - } - - @Override - public String toString() { - return "MapLike[" + document + "]"; - } - }); - } - - @Override - public BsonValue createMap(Stream> map) { - final BsonDocument result = new BsonDocument(); - map.forEach(p -> result.put(p.getFirst().asString().getValue(), p.getSecond())); - return result; - } - - @Override - public DataResult> getStream(BsonValue input) { - if (input instanceof BsonArray array) { - return DataResult.success(array.stream().map(e -> e instanceof BsonNull ? null : e)); - } - return DataResult.error("Not a bson array: " + input); - } - - @Override - public DataResult>> getList(BsonValue input) { - if (input instanceof BsonArray array) { - return DataResult.success(c -> { - for (final BsonValue value : array) { - c.accept(value); - } - }); - } - return DataResult.error("Not a bson array: " + input); - } - - @Override - public BsonValue createList(Stream input) { - final BsonArray result = new BsonArray(); - input.forEach(result::add); - return result; - } - - @Override - public BsonValue remove(BsonValue input, String key) { - if (input instanceof BsonDocument document) { - final BsonDocument result = new BsonDocument(); - document.entrySet().stream() - .filter(entry -> !Objects.equals(entry.getKey(), key)) - .forEach(entry -> result.put(entry.getKey(), entry.getValue())); - return result; - } - return input; - } - - - private static final class BsonNumberWrapper extends Number { - private final BsonNumber delegate; - - public BsonNumberWrapper(BsonNumber delegate) { - this.delegate = delegate; - } - - @Override - public int intValue() { - return delegate.intValue(); - } - - @Override - public long longValue() { - return delegate.longValue(); - } - - @Override - public float floatValue() { - return (float) delegate.doubleValue(); - } - - @Override - public double doubleValue() { - return delegate.doubleValue(); - } - } -} diff --git a/modules/common/src/main/java/net/hollowcube/mongo/MongoConfig.java b/modules/common/src/main/java/net/hollowcube/mongo/MongoConfig.java deleted file mode 100644 index abf2a404..00000000 --- a/modules/common/src/main/java/net/hollowcube/mongo/MongoConfig.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.hollowcube.mongo; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import org.jetbrains.annotations.NotNull; - -public record MongoConfig( - @NotNull String uri, - boolean useTransactions -) { - - public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( - Codec.STRING.fieldOf("uri").forGetter(MongoConfig::uri), - Codec.BOOL.optionalFieldOf("use_transactions", false).forGetter(MongoConfig::useTransactions) - ).apply(i, MongoConfig::new)); - -} diff --git a/modules/common/src/main/java/net/hollowcube/mongo/package-info.java b/modules/common/src/main/java/net/hollowcube/mongo/package-info.java deleted file mode 100644 index f359a091..00000000 --- a/modules/common/src/main/java/net/hollowcube/mongo/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * MongoDB utilities to work with the other systems present. - *

- * `common` does not have a runtime dependency on mongodb, so this package will not bring along any extra baggage. - * However, any package using this module must bring along mongodb-driver-sync. - */ -package net.hollowcube.mongo; \ No newline at end of file diff --git a/modules/common/src/main/java/net/hollowcube/registry/MapRegistry.java b/modules/common/src/main/java/net/hollowcube/registry/MapRegistry.java deleted file mode 100644 index c28c2ee9..00000000 --- a/modules/common/src/main/java/net/hollowcube/registry/MapRegistry.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.hollowcube.registry; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.UnknownNullability; - -import java.util.Collection; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -class MapRegistry implements Registry { - private final Map delegate; - - public MapRegistry(Map resources) { - this.delegate = resources; - } - - @Override - public @Nullable T getRaw(String namespace) { - return delegate.get(namespace); - } - - @Override - public @NotNull Collection values() { - return delegate.values(); - } - - @Override - public int size() { - return delegate.size(); - } - - @Override - public @NotNull Index index(Function mapper) { - Map index = values().stream().collect(Collectors.toMap(mapper, i -> i)); - return new MapIndex<>(index); - } - - - static class MapIndex implements Index { - private final Map delegate; - - MapIndex(Map delegate) { - this.delegate = delegate; - } - - @Override - public @UnknownNullability T get(K key) { - return delegate.get(key); - } - } -} diff --git a/modules/common/src/main/java/net/hollowcube/registry/MissingEntryException.java b/modules/common/src/main/java/net/hollowcube/registry/MissingEntryException.java deleted file mode 100644 index d8ac5374..00000000 --- a/modules/common/src/main/java/net/hollowcube/registry/MissingEntryException.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.hollowcube.registry; - -import org.jetbrains.annotations.NotNull; - -public class MissingEntryException extends RuntimeException{ - private final @NotNull Registry registry; - private final @NotNull String key; - - public MissingEntryException(@NotNull Registry registry, @NotNull String key) { - super("Missing registry entry: " + key + " in " + registry + "!"); - this.registry = registry; - this.key = key; - } - - public @NotNull Registry registry() { - return registry; - } - - public @NotNull String key() { - return key; - } -} diff --git a/modules/common/src/main/java/net/hollowcube/registry/Registry.java b/modules/common/src/main/java/net/hollowcube/registry/Registry.java deleted file mode 100644 index 20a28e97..00000000 --- a/modules/common/src/main/java/net/hollowcube/registry/Registry.java +++ /dev/null @@ -1,200 +0,0 @@ -package net.hollowcube.registry; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.mojang.serialization.Codec; -import com.mojang.serialization.JsonOps; -import net.hollowcube.Env; -import net.minestom.server.utils.NamespaceID; -import net.minestom.server.utils.collection.ObjectArray; -import net.minestom.server.utils.validate.Check; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.UnknownNullability; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import net.hollowcube.dfu.DFUUtil; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * A (publically) immutable list of {@link Resource}s, indexed by {@link NamespaceID}. - *

- * Registries can be created in a variety of ways with varying degrees of comlepexity. Ores, item components and item - * entries serve as examples with varying complexity and should be used as an example. - *

- * The most simple option is {@link #codec(String, Codec)}. This will create a registry from a single data file with the - * name {@code ${name}.json} which must contain an array of objects, each conforming to the given {@link Codec}. Ores - * are an example using this pattern. - *

- * Another very common pattern is used in NumberProviders. This case can be used when a field may contain a variety of - * implementations, identified by their key. First, an interface should be created for the resource, as well as a - * Factory inner abstract class which implements ResourceFactory. A {@link #service(String, java.lang.Class)} registry - * can be created to load all implementations of the factory. From there, registry dispatch may be used on the codec to - * create a codec for all implementations of the interface. Finally, each implementation must implement a Factory class - * and register it with {@link com.google.auto.service.AutoService}. See NumberProvider for more detail. - *

- * Finally, if some complexity is needed during the loading process of static resources, - * {@link #manual(String, Function)} can be used to individually process each resource. The loading mechanism is the - * same as {@link #codec(String, Codec)}. Item registry entries (ItemRegistry.Entry) are an example using this pattern. - * - * @param The type of resource stored in the registry. - */ -public interface Registry { - //todo registry should implement Codec i think - - // Factory - - static Registry manual(@NotNull String name, Supplier> supplier) { - Map registry = new HashMap<>(); - for (T element : supplier.get()) { - registry.put(element.name(), element); - } - - // Registries may not be empty in strict mode - Env.strictValidation( - "Empty registry for manual resource: " + name, - registry::isEmpty - ); - - return new MapRegistry<>(registry); - } - - static Registry service(@NotNull String name, Class type) { - Map registry = new HashMap<>(); - for (T elem : ServiceLoader.load(type)) { - registry.put(elem.name(), elem); - } - - // Registries may not be empty in strict mode - Env.strictValidation( - "Empty registry for manual resource: " + name, - registry::isEmpty - ); - - return new MapRegistry<>(registry); - } - - static Registry manual(@NotNull String name, @NotNull Function mapper) { - Map registry = new HashMap<>(); - - JsonArray content = Resource.loadJsonArray(name + ".json"); - for (JsonElement elem : content) { - Check.stateCondition(!elem.isJsonObject(), "Registry items must be json objects"); - - try { - T element = mapper.apply(elem.getAsJsonObject()); - registry.put(element.name(), element); - } catch (Throwable e) { - Logger logger = LoggerFactory.getLogger(Registry.class); - logger.error("Failed to load registry item in {}: {}", name, elem, e); - - Env.strictValidation("Registry item failure", () -> true); - } - } - - // Registries may not be empty in strict mode - Env.strictValidation( - "Empty registry for resource: " + name, - registry::isEmpty - ); - - return new MapRegistry<>(registry); - } - - /** - * Create a registry from a codec directly. The registry item must have a "namespace" field for the ID. - * - * @param codec The codec to deserialize with - * @param name The name of the data file to load from (.json is appended) - */ - static Registry codec(@NotNull String name, @NotNull Codec codec) { - JsonArray content = Resource.loadJsonArray(name + ".json"); - - // Create a modified encoder that converts to a map. See the description of ItemRegistry.Entry.CODEC - // for more notes on the technique used here. - Codec> mapCodec = Codec.pair(Codec.STRING.fieldOf("namespace").codec(), codec) - .listOf() - .xmap(DFUUtil::pairListToMap, DFUUtil::mapToPairList); - - Map registry = null; // null is just to make javac happy, it can never happen. - try { - registry = JsonOps.INSTANCE - .withDecoder(mapCodec) - .apply(content) - .getOrThrow(false, ignored -> {}) - .getFirst(); - } catch (RuntimeException e) { - Logger logger = LoggerFactory.getLogger(Registry.class); - logger.error("Failed to create registry {}", name, e); - - // This is a fatal error. We should never allow a server to start up with a broken registry. - System.exit(1); - } - - // Registries may not be empty in strict mode - Env.strictValidation( - "Empty registry for resource: " + name, - registry::isEmpty - ); - - return new MapRegistry<>(registry); - } - - - // Impl - - @Nullable T getRaw(String namespace); - - default @UnknownNullability T get(String namespace) { - if (namespace == null) return null; - return getRaw(namespace.contains(":") ? namespace : "minecraft:" + namespace); - } - - default @UnknownNullability T get(NamespaceID namespace) { - if (namespace == null) return null; - return getRaw(namespace.asString()); - } - - default @NotNull T required(String namespace) { - T result = get(namespace); - if (result == null) throw new MissingEntryException(this, namespace); - return result; - } - - - @NotNull Collection values(); - - int size(); - - - // Derivatives - - interface Index { - - @UnknownNullability T get(K key); - - } - - @NotNull Index index(Function mapper); - - - // Below here is kinda cursed, will fix eventually but works for now. - - default @NotNull ObjectArray unsafeIntegerIndex(Function getter) { - Collection values = values(); - - ObjectArray index = ObjectArray.singleThread(values.size()); - for (T elem : values) - index.set(getter.apply(elem), elem); - - index.trim(); - return index; - } -} diff --git a/modules/common/src/main/java/net/hollowcube/registry/Resource.java b/modules/common/src/main/java/net/hollowcube/registry/Resource.java deleted file mode 100644 index 0bf4173b..00000000 --- a/modules/common/src/main/java/net/hollowcube/registry/Resource.java +++ /dev/null @@ -1,95 +0,0 @@ -package net.hollowcube.registry; - -import com.google.gson.JsonArray; -import com.google.gson.JsonParser; -import net.kyori.adventure.key.Key; -import net.kyori.adventure.key.Keyed; -import net.minestom.server.utils.NamespaceID; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.stream.Collectors; - -public interface Resource extends Keyed { - - @Contract(pure = true) - @NotNull NamespaceID namespace(); - - @Override - default @NotNull Key key() { - return namespace(); - } - - @Contract(pure = true) - default @NotNull String name() { - return namespace().asString(); - } - - - interface Id extends Resource { - - @Contract(pure = true) - int id(); - - } - - - Path DATA_PATH = Path.of(System.getProperty("starlight.data.dir", "data")); - - /** - * Attempts to load a resource file with the following priorities - *

    - *
  1. Read from `jar://data/{name}`
  2. - *
  3. Read from `{DATA_PATH}/{name}`
  4. - *
  5. null
  6. - *
- * - * @param name The resource name and extension to load - * @return The resource file content, or null if missing. - */ - static @Nullable String load(@NotNull String name) { - InputStream packaged = Resource.class.getClassLoader().getResourceAsStream("data/" + name); - if (packaged != null) { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(packaged, Charset.defaultCharset()))) { - return reader.lines().collect(Collectors.joining("\n")); - } catch (IOException e) { - Logger logger = LoggerFactory.getLogger(Resource.class); - logger.warn("Found resource {} in classpath, but failed to load it", name, e); - } - } - - Path external = DATA_PATH.resolve(name); - if (Files.exists(external) && Files.isRegularFile(external)) { - try (BufferedReader reader = Files.newBufferedReader(external)) { - return reader.lines().collect(Collectors.joining("\n")); - } catch (IOException e) { - Logger logger = LoggerFactory.getLogger(Resource.class); - logger.warn("Found resource {} in external data, but failed to load it", name, e); - } - } - - return null; - } - - /** - * Loads a resource using the semantics of {@link #load(String)}, but the resource must be a json file with an array - * at the root. If the file cannot be found, an empty array will be returned. - */ - static @NotNull JsonArray loadJsonArray(@NotNull String resource) { - String content = load(resource); - if (content == null) - return new JsonArray(); - - return JsonParser.parseString(content).getAsJsonArray(); - } -} diff --git a/modules/common/src/main/java/net/hollowcube/registry/ResourceFactory.java b/modules/common/src/main/java/net/hollowcube/registry/ResourceFactory.java deleted file mode 100644 index a1eb5709..00000000 --- a/modules/common/src/main/java/net/hollowcube/registry/ResourceFactory.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.hollowcube.registry; - -import com.mojang.serialization.Codec; -import net.minestom.server.utils.NamespaceID; -import org.jetbrains.annotations.NotNull; - -public abstract class ResourceFactory implements Resource { - private final NamespaceID namespace; - private final Class type; - private final Codec codec; - - public ResourceFactory(NamespaceID namespace, Class type, Codec codec) { - this.namespace = namespace; - this.type = type; - this.codec = codec; - } - - @Override - public @NotNull NamespaceID namespace() { - return this.namespace; - } - - public @NotNull Class type() { - return this.type; - } - - public @NotNull Codec codec() { - return this.codec; - } -} diff --git a/modules/common/src/main/java/net/hollowcube/server/Facet.java b/modules/common/src/main/java/net/hollowcube/server/Facet.java deleted file mode 100644 index de02857b..00000000 --- a/modules/common/src/main/java/net/hollowcube/server/Facet.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.hollowcube.server; - -import net.minestom.server.ServerProcess; -import org.jetbrains.annotations.NotNull; - -/** - * A concept for loading modules of the server, similar-ish to extensions. - *

- * Facets are defined, then loaded using the service provider interface by the controlling server (development, - * production, etc). - *

- * All facets must have a public no-args constructor. There may be other constructors present (eg for use in - * tests). - *

- * Common registration functions are provided on {@link ServerWrapper}. These should be used over accessing the - * {@link ServerProcess} directly, because they can be transparently extended to support unloading facets if this ever - * becomes a desired behavior (and they have some utilities). - */ -public interface Facet { - - void hook(@NotNull ServerWrapper server); - -} diff --git a/modules/common/src/main/java/net/hollowcube/server/IsolatedServerWrapper.java b/modules/common/src/main/java/net/hollowcube/server/IsolatedServerWrapper.java deleted file mode 100644 index 6c5267e0..00000000 --- a/modules/common/src/main/java/net/hollowcube/server/IsolatedServerWrapper.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.hollowcube.server; - -import net.minestom.server.ServerProcess; -import net.minestom.server.command.builder.Command; -import net.minestom.server.event.EventNode; -import net.minestom.server.instance.block.BlockHandler; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Supplier; - -@SuppressWarnings("UnstableApiUsage") -record IsolatedServerWrapper(@NotNull ServerProcess process) implements ServerWrapper { - - @Override - public @Nullable F getFacet(@NotNull Class type) { - return null; - } - - @Override - public void addEventNode(@NotNull EventNode node) { - process.eventHandler().addChild(node); - } - - @Override - public void registerCommand(@NotNull Command command) { - process.command().register(command); - } - - @Override - public void registerBlockHandler(@NotNull Supplier handlerSupplier) { - process.block().registerHandler(handlerSupplier.get().getNamespaceId(), handlerSupplier); - } -} diff --git a/modules/common/src/main/java/net/hollowcube/server/ServerWrapper.java b/modules/common/src/main/java/net/hollowcube/server/ServerWrapper.java deleted file mode 100644 index bb5a3611..00000000 --- a/modules/common/src/main/java/net/hollowcube/server/ServerWrapper.java +++ /dev/null @@ -1,44 +0,0 @@ -package net.hollowcube.server; - -import net.minestom.server.ServerProcess; -import net.minestom.server.command.builder.Command; -import net.minestom.server.event.EventNode; -import net.minestom.server.instance.block.BlockHandler; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Supplier; - -@SuppressWarnings("UnstableApiUsage") -public interface ServerWrapper { - - static @NotNull ServerWrapper isolated(@NotNull ServerProcess process) { - return new IsolatedServerWrapper(process); - } - - /** - * Access to the underlying server process. Should not be used if there is an alternative api present in this - * class. - */ - @NotNull ServerProcess process(); - - /** - * Fetches a {@link Facet} loaded on the server. - *

- * Note: Load order is _not_ guaranteed. If this method is accessed during the facet loading phase of server start, - * the target may not have been loaded yet. It will still be returned in this case. - * - * @return The facet if it is present on the server, otherwise null - */ - @Nullable F getFacet(@NotNull Class type); - - - // Utility functions - - void addEventNode(@NotNull EventNode node); - - void registerCommand(@NotNull Command command); - - void registerBlockHandler(@NotNull Supplier handlerSupplier); - -} diff --git a/modules/common/src/main/java/net/hollowcube/server/instance/TickTrackingInstance.java b/modules/common/src/main/java/net/hollowcube/server/instance/TickTrackingInstance.java deleted file mode 100644 index df2deee1..00000000 --- a/modules/common/src/main/java/net/hollowcube/server/instance/TickTrackingInstance.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.hollowcube.server.instance; - -import net.minestom.server.instance.IChunkLoader; -import net.minestom.server.instance.InstanceContainer; -import net.minestom.server.world.DimensionType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.UUID; - -public class TickTrackingInstance extends InstanceContainer { - //todo i (matt) really dont think this should be in common, but not sure where - - private long tick = 0; - - public TickTrackingInstance(@NotNull UUID uniqueId, @NotNull DimensionType dimensionType, @Nullable IChunkLoader loader) { - super(uniqueId, dimensionType, loader); - } - - public TickTrackingInstance(@NotNull UUID uniqueId, @NotNull DimensionType dimensionType) { - super(uniqueId, dimensionType); - } - - @Override - public void tick(long time) { - tick++; - - super.tick(time); - } - - public long getTick() { - return tick; - } -} diff --git a/modules/common/src/main/java/net/hollowcube/util/BlockUtil.java b/modules/common/src/main/java/net/hollowcube/util/BlockUtil.java deleted file mode 100644 index 34bb1f1c..00000000 --- a/modules/common/src/main/java/net/hollowcube/util/BlockUtil.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.hollowcube.util; - -import net.minestom.server.instance.block.Block; -import org.jetbrains.annotations.NotNull; - -public final class BlockUtil { - - public static @NotNull Block withType(@NotNull Block block, @NotNull Block type) { - return type.withHandler(block.handler()).withNbt(block.nbt()); - } - -} diff --git a/modules/common/src/main/java/net/hollowcube/util/ComponentUtil.java b/modules/common/src/main/java/net/hollowcube/util/ComponentUtil.java deleted file mode 100644 index 37fbcc7b..00000000 --- a/modules/common/src/main/java/net/hollowcube/util/ComponentUtil.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.hollowcube.util; - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.TextDecoration; -import net.kyori.adventure.text.minimessage.MiniMessage; -import org.jetbrains.annotations.NotNull; - -public class ComponentUtil { - - public static @NotNull Component fromStringSafe(@NotNull String content) { - Component mm = MiniMessage.miniMessage().deserialize(content); - return Component.text().decoration(TextDecoration.ITALIC, false).append(mm).asComponent(); - } - -} diff --git a/modules/common/src/main/java/net/hollowcube/util/EventUtil.java b/modules/common/src/main/java/net/hollowcube/util/EventUtil.java deleted file mode 100644 index e5dd8f3b..00000000 --- a/modules/common/src/main/java/net/hollowcube/util/EventUtil.java +++ /dev/null @@ -1,46 +0,0 @@ -package net.hollowcube.util; - -import net.hollowcube.Env; -import net.minestom.server.MinecraftServer; -import net.minestom.server.ServerProcess; -import net.minestom.server.event.Event; -import net.minestom.server.event.EventFilter; -import net.minestom.server.event.EventNode; -import net.minestom.server.event.trait.CancellableEvent; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Predicate; - -public class EventUtil { - - /** - * Creates an event node with the given name for any event which has not yet been cancelled. - */ - public static EventNode notCancelledNode(@NotNull String name) { - return EventNode.event(name, EventFilter.ALL, Predicate.not(EventUtil::isCancelled)); - } - - public static boolean isCancelled(Event event) { - return event instanceof CancellableEvent c && c.isCancelled(); - } - - /** - * Call an event in a test-safe manner. - */ - public static void safeDispatch(@NotNull Event event) { - ServerProcess process = MinecraftServer.process(); - if (process == null && !Env.STRICT_MODE) - return; - process.eventHandler().call(event); - } - - /** - * Call an event in a test-safe manner. - */ - public static void safeDispatchCancellable(@NotNull Event event, @NotNull Runnable onSuccess) { - ServerProcess process = MinecraftServer.process(); - if (process == null && !Env.STRICT_MODE) - return; - process.eventHandler().callCancellable(event, onSuccess); - } -} diff --git a/modules/common/src/main/java/net/hollowcube/util/FutureUtil.java b/modules/common/src/main/java/net/hollowcube/util/FutureUtil.java deleted file mode 100644 index 6b1e8e95..00000000 --- a/modules/common/src/main/java/net/hollowcube/util/FutureUtil.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.hollowcube.util; - -import org.jetbrains.annotations.Contract; - -public class FutureUtil { - - @Contract("_ -> null") - @SuppressWarnings("TypeParameterUnusedInFormals") - public static T handleException(Throwable throwable) { - //todo log to sentry or something - throwable.printStackTrace(); - return null; - } - -} diff --git a/modules/common/src/main/java/net/hollowcube/util/JsonUtil.java b/modules/common/src/main/java/net/hollowcube/util/JsonUtil.java deleted file mode 100644 index 446e1f4d..00000000 --- a/modules/common/src/main/java/net/hollowcube/util/JsonUtil.java +++ /dev/null @@ -1,103 +0,0 @@ -package net.hollowcube.util; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.UnknownNullability; - -import java.util.HashMap; -import java.util.Map; - -public class JsonUtil { - - /** - * Merge two {@link JsonElement}s recursively, combining arrays based on the "type" field. - *

- * The resulting json element is not necessarily a deep copy if the returned item has not been modified. - */ - @Contract("_, _ -> new") - public static @UnknownNullability JsonElement merge(@Nullable JsonElement left, @Nullable JsonElement right) { - if (left == null) return right; - if (right == null) return left; - - if (left.isJsonObject() && right.isJsonObject()) - return merge(left.getAsJsonObject(), right.getAsJsonObject()); - if (left.isJsonArray() && right.isJsonArray()) - return merge(left.getAsJsonArray(), right.getAsJsonArray()); - - return right; - } - - public static @NotNull JsonObject merge(@NotNull JsonObject left, @NotNull JsonObject right) { - JsonObject merged = new JsonObject(); - for (var entry : left.entrySet()) { - merged.add(entry.getKey(), entry.getValue()); - } - for (var entry : right.entrySet()) { - final String name = entry.getKey(); - // If left had the value, merge the two. Otherwise, just add the new entry. - if (merged.has(entry.getKey())) { - merged.add(name, merge(merged.get(name), entry.getValue())); - } else { - merged.add(entry.getKey(), entry.getValue()); - } - } - return merged; - } - - public static @NotNull JsonArray merge(@NotNull JsonArray left, @NotNull JsonArray right) { - JsonArray merged = new JsonArray(); - - //todo lots of duplication, very yikes - Map temp = new HashMap<>(); - for (JsonElement elem : left) { - // If it isnt an object, we cannot merge. Move on - if (!elem.isJsonObject()) { - merged.add(elem); - continue; - } - JsonObject obj = elem.getAsJsonObject(); - // If it has a type field, we can merge. Otherwise, just add it. - if (obj.has("type")) { - temp.put(obj.get("type").getAsString(), elem); - } else { - merged.add(elem); - } - } - - for (JsonElement elem : right) { - // If it isnt an object, we cannot merge. Move on - if (!elem.isJsonObject()) { - merged.add(elem); - continue; - } - JsonObject obj = elem.getAsJsonObject(); - - // If there is not a string type, we cannot merge. Move on - JsonElement type = obj.get("type"); - if (!type.isJsonPrimitive()) { - merged.add(elem); - continue; - } - - // If there is already an element of the same type, merge them. - // Otherwise just add the element to temp map - if (temp.containsKey(type.getAsString())) { - temp.put(type.getAsString(), merge(temp.get(type.getAsString()), elem)); - } else { - temp.put(type.getAsString(), elem); - } - } - - // Copy all entries from temp map into temp - for (var entry : temp.entrySet()) { - merged.add(entry.getValue()); - } - - return merged; - } - -} diff --git a/modules/common/src/main/java/net/hollowcube/util/ParticleUtils.java b/modules/common/src/main/java/net/hollowcube/util/ParticleUtils.java deleted file mode 100644 index 7214ef8b..00000000 --- a/modules/common/src/main/java/net/hollowcube/util/ParticleUtils.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.hollowcube.util; - -import net.minestom.server.coordinate.Point; -import net.minestom.server.entity.Player; -import net.minestom.server.item.Material; -import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.particle.Particle; -import net.minestom.server.particle.ParticleCreator; -import org.jetbrains.annotations.NotNull; - -public class ParticleUtils { - - public static void spawnBlockBreakParticles(@NotNull Player player, @NotNull Point point, @NotNull Material material) { - ServerPacket packet = ParticleCreator.createParticlePacket( - Particle.BLOCK, false, point.x(), point.y(), point.z(), 0.01f, 0.01f, 0.01f, - 0.05f, 12, binaryWriter -> binaryWriter.writeVarInt(material.id())); - player.sendPacketToViewersAndSelf(packet); - } -} diff --git a/modules/common/src/test/java/net/hollowcube/data/number/TestConstantNumberProvider.java b/modules/common/src/test/java/net/hollowcube/data/number/TestConstantNumberProvider.java deleted file mode 100644 index 0a544528..00000000 --- a/modules/common/src/test/java/net/hollowcube/data/number/TestConstantNumberProvider.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.hollowcube.data.number; - -import net.hollowcube.data.NumberSource; -import org.junit.jupiter.api.Test; -import org.opentest4j.AssertionFailedError; - -import static com.google.common.truth.Truth.assertThat; - -public class TestConstantNumberProvider { - - @Test - public void testHappyCase() { - var source = NumberSource.constant(0); - var provider = new ConstantNumberProvider(1.0); - - assertThat(provider.nextLong(source)).isEqualTo(1); - } - - @Test - public void testIgnoresSource() { - var source = new NumberSource() { - @Override - public double random() { - throw new AssertionFailedError("Should not be called."); - } - }; - var provider = new ConstantNumberProvider(1.0); - - provider.nextLong(source); - provider.nextDouble(source); - } - -} diff --git a/modules/common/src/test/java/net/hollowcube/dfu/TestEnvVarOps.java b/modules/common/src/test/java/net/hollowcube/dfu/TestEnvVarOps.java deleted file mode 100644 index b57e062a..00000000 --- a/modules/common/src/test/java/net/hollowcube/dfu/TestEnvVarOps.java +++ /dev/null @@ -1,172 +0,0 @@ -package net.hollowcube.dfu; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import org.junit.jupiter.api.Test; - -import java.util.Collection; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import static com.google.common.truth.Truth.assertThat; - -public class TestEnvVarOps { - - @Test - public void testBasicString() { - record Config(String value) {} - Codec codec = RecordCodecBuilder.create(i -> i.group( - Codec.STRING.fieldOf("value").forGetter(Config::value) - ).apply(i, Config::new)); - - var ops = new MockEnvVarOps(Map.of( - "VALUE", "foo" - )); - var result = ops.withDecoder(codec) - .apply("") - .result() - .orElse(null); - - assertThat(result).isNotNull(); - assertThat(result.getFirst().value).isEqualTo("foo"); - } - - @Test - public void testBasicInt() { - record Config(int value) {} - Codec codec = RecordCodecBuilder.create(i -> i.group( - Codec.INT.fieldOf("value").forGetter(Config::value) - ).apply(i, Config::new)); - - var ops = new MockEnvVarOps(Map.of( - "VALUE", "1" - )); - var result = ops.withDecoder(codec) - .apply("") - .result() - .orElse(null); - - assertThat(result).isNotNull(); - assertThat(result.getFirst().value).isEqualTo(1); - } - - @Test - public void testNestedValue() { - record InnerConfig(String value) {} - Codec innerCodec = RecordCodecBuilder.create(i -> i.group( - Codec.STRING.fieldOf("value").forGetter(InnerConfig::value) - ).apply(i, InnerConfig::new)); - record Config(InnerConfig inner) {} - Codec codec = RecordCodecBuilder.create(i -> i.group( - innerCodec.fieldOf("inner").forGetter(Config::inner) - ).apply(i, Config::new)); - - var ops = new MockEnvVarOps(Map.of( - "INNER_VALUE", "foo" - )); - var result = ops.withDecoder(codec) - .apply("") - .result() - .orElse(null); - - assertThat(result).isNotNull(); - assertThat(result.getFirst().inner.value).isEqualTo("foo"); - } - - @Test - public void test2xNestedValue() { - record InnerInnerConfig(String value) {} - Codec innerInnerCodec = RecordCodecBuilder.create(i -> i.group( - Codec.STRING.fieldOf("value").forGetter(InnerInnerConfig::value) - ).apply(i, InnerInnerConfig::new)); - record InnerConfig(InnerInnerConfig inner) {} - Codec innerCodec = RecordCodecBuilder.create(i -> i.group( - innerInnerCodec.fieldOf("inner").forGetter(InnerConfig::inner) - ).apply(i, InnerConfig::new)); - record Config(InnerConfig inner) {} - Codec codec = RecordCodecBuilder.create(i -> i.group( - innerCodec.fieldOf("inner").forGetter(Config::inner) - ).apply(i, Config::new)); - - var ops = new MockEnvVarOps(Map.of( - "INNER_INNER_VALUE", "foo" - )); - var result = ops.withDecoder(codec) - .apply("") - .result() - .orElse(null); - - assertThat(result).isNotNull(); - assertThat(result.getFirst().inner.inner.value).isEqualTo("foo"); - } - - @Test - public void testList() { - record Config(List value) {} - Codec codec = RecordCodecBuilder.create(i -> i.group( - Codec.STRING.listOf().fieldOf("value").forGetter(Config::value) - ).apply(i, Config::new)); - - var ops = new MockEnvVarOps(Map.of( - "VALUE_0", "A", - "VALUE_1", "B", - "VALUE_2", "C" - )); - var result = ops.withDecoder(codec) - .apply("") - .result() - .orElse(null); - - assertThat(result).isNotNull(); - assertThat(result.getFirst().value).containsExactly("A", "B", "C"); - } - - @Test - public void testListOfObject() { - record InnerConfig(String a, String b) {} - Codec innerCodec = RecordCodecBuilder.create(i -> i.group( - Codec.STRING.fieldOf("a").forGetter(InnerConfig::a), - Codec.STRING.fieldOf("b").forGetter(InnerConfig::b) - ).apply(i, InnerConfig::new)); - record Config(List value) {} - Codec codec = RecordCodecBuilder.create(i -> i.group( - innerCodec.listOf().fieldOf("value").forGetter(Config::value) - ).apply(i, Config::new)); - - var ops = new MockEnvVarOps(Map.of( - "VALUE_0_A", "0 a", - "VALUE_0_B", "0 b", - "VALUE_1_A", "1 a", - "VALUE_1_B", "1 b" - )); - var result = ops.withDecoder(codec) - .apply("") - .result() - .orElse(null); - - assertThat(result).isNotNull(); - assertThat(result.getFirst().value).containsExactly( - new InnerConfig("0 a", "0 b"), - new InnerConfig("1 a", "1 b") - ); - } - - - private static class MockEnvVarOps extends EnvVarOps { - private final Map env; - - private MockEnvVarOps(Map env) {this.env = env;} - - @Override - protected String get(String path) { - var value = env.get(path.toUpperCase(Locale.ROOT)); - return value == null ? "" : value; - } - - @Override - protected Collection envKeys() { - return env.keySet(); - } - } -} diff --git a/modules/common/src/test/java/net/hollowcube/registry/TestMissingEntry.java b/modules/common/src/test/java/net/hollowcube/registry/TestMissingEntry.java deleted file mode 100644 index 3aa57cc2..00000000 --- a/modules/common/src/test/java/net/hollowcube/registry/TestMissingEntry.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.hollowcube.registry; - -import com.google.gson.JsonParser; -import com.mojang.serialization.JsonOps; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -public class TestMissingEntry { - - @Test - public void testMissingRegistryEntry() { - var json = JsonParser.parseString("{\"type\": \"missing\"}"); - assertThrows(MissingEntryException.class, () -> JsonOps.INSTANCE.withDecoder(TestResource.CODEC).apply(json)); - } - -} diff --git a/modules/common/src/test/java/net/hollowcube/registry/TestResource.java b/modules/common/src/test/java/net/hollowcube/registry/TestResource.java deleted file mode 100644 index 630224bd..00000000 --- a/modules/common/src/test/java/net/hollowcube/registry/TestResource.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.hollowcube.registry; - -import com.mojang.serialization.Codec; -import net.minestom.server.utils.NamespaceID; -import org.jetbrains.annotations.NotNull; - -public interface TestResource extends Resource { - - Codec CODEC = Factory.CODEC.dispatch(Factory::from, Factory::codec); - - abstract class Factory extends ResourceFactory { - static Registry REGISTRY = Registry.service("test_resource", Factory.class); - static Registry.Index, Factory> TYPE_REGISTRY = REGISTRY.index(Factory::type); - - static Codec CODEC = Codec.STRING.xmap(ns -> REGISTRY.required(ns), Factory::name); - - public Factory(NamespaceID namespace, Class type, Codec codec) { - super(namespace, type, codec); - } - - public static @NotNull Factory from(@NotNull TestResource resource) { - return TYPE_REGISTRY.get(resource.getClass()); - } - } - -} diff --git a/modules/common/src/test/java/net/hollowcube/util/TestJsonUtil.java b/modules/common/src/test/java/net/hollowcube/util/TestJsonUtil.java deleted file mode 100644 index 6d0daadb..00000000 --- a/modules/common/src/test/java/net/hollowcube/util/TestJsonUtil.java +++ /dev/null @@ -1,136 +0,0 @@ -package net.hollowcube.util; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import org.intellij.lang.annotations.Language; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.stream.Stream; - -import static com.google.common.truth.Truth.assertThat; - -public class TestJsonUtil { - private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); - - private static Stream mergeTestData() { - return Stream.of( - test("null right", """ - { - "a": 1 - }""", null, """ - { - "a": 1 - }"""), - test("null left", null, """ - { - "a": 1 - }""", """ - { - "a": 1 - }"""), - test("merge top level objects", """ - { - "a": 1, - "b": 1 - }""", """ - { - "a": 2, - "c": 1 - }""", """ - { - "a": 2, - "b": 1, - "c": 1 - }"""), - test("merge sub objects", """ - { - "obj": { - "a": 1, - "b": 1 - } - }""", """ - { - "obj": { - "a": 2, - "c": 1 - } - }""", """ - { - "obj": { - "a": 2, - "b": 1, - "c": 1 - } - }"""), - // Note the extra "a" in the result because there is no type field to merge on - test("merge array simple", """ - [ - "a", - "b" - ]""", """ - [ - "a", - "c" - ]""", """ - [ - "a", - "b", - "a", - "c" - ]"""), - test("merge array complex", """ - [ - { - "type": "a", - "a": 1 - }, - { - "type": "b", - "a": 1 - } - ]""", """ - [ - { - "type": "a", - "a": 2, - "b": 1 - } - ]""", """ - [ - { - "type": "a", - "a": 2, - "b": 1 - }, - { - "type": "b", - "a": 1 - } - ]""") - ); - } - - @ParameterizedTest(name = "{0}") - @MethodSource("mergeTestData") - public void testMergeNullRight(String name, String leftStr, String rightStr, String mergedStr) { - // Parse and re stringify result to ensure formatting is the same. We just want to compare content with a readable error. - JsonElement left = null, right = null, merged = JsonParser.parseString(mergedStr); - if (leftStr != null) left = JsonParser.parseString(leftStr); - if (rightStr != null) right = JsonParser.parseString(rightStr); - - JsonElement result = JsonUtil.merge(left, right); - String resultStr = gson.toJson(result); - - assertThat(resultStr).isEqualTo(gson.toJson(merged)); - } - - private static Arguments test(String name, @Language("JSON") String left, @Language("JSON") String right, @Language("JSON") String merged) { - return Arguments.of(name, left, right, merged); - } - - -} diff --git a/modules/common/src/test/resources/lang/en_US.properties b/modules/common/src/test/resources/lang/en_US.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/modules/common/src/test/resources/test.json b/modules/common/src/test/resources/test.json deleted file mode 100644 index 914e095f..00000000 --- a/modules/common/src/test/resources/test.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "test:one": { - "string": "hello" - } -} \ No newline at end of file diff --git a/modules/development/build.gradle.kts b/modules/development/build.gradle.kts index 61c8c024..40c2887d 100644 --- a/modules/development/build.gradle.kts +++ b/modules/development/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } dependencies { - implementation(project(":modules:common")) + implementation("net.hollowcube.common:common:0.0.0") implementation(project(":modules:chat")) implementation(project(":modules:block-interactions")) implementation(project(":modules:item")) diff --git a/modules/item/build.gradle.kts b/modules/item/build.gradle.kts index 383ca884..ffef575f 100644 --- a/modules/item/build.gradle.kts +++ b/modules/item/build.gradle.kts @@ -1,4 +1,4 @@ dependencies { - implementation(project(":modules:common")) + implementation("net.hollowcube.common:common:0.0.0") implementation(project(":modules:loot-table")) } \ No newline at end of file diff --git a/modules/loot-table/build.gradle.kts b/modules/loot-table/build.gradle.kts index 4369e5a3..e6616567 100644 --- a/modules/loot-table/build.gradle.kts +++ b/modules/loot-table/build.gradle.kts @@ -1,3 +1,3 @@ dependencies { - implementation(project(":modules:common")) + implementation("net.hollowcube.common:common:0.0.0") } diff --git a/modules/player/build.gradle.kts b/modules/player/build.gradle.kts index a22bed27..ebce834a 100644 --- a/modules/player/build.gradle.kts +++ b/modules/player/build.gradle.kts @@ -4,5 +4,5 @@ plugins { dependencies { implementation(project(":modules:item")) - implementation(project(":modules:common")) + implementation("net.hollowcube.common:common:0.0.0") } \ No newline at end of file diff --git a/modules/quest/build.gradle.kts b/modules/quest/build.gradle.kts index e436f271..1cc9af63 100644 --- a/modules/quest/build.gradle.kts +++ b/modules/quest/build.gradle.kts @@ -2,6 +2,6 @@ apply(plugin = "java-library") dependencies { - implementation(project(":modules:common")) + implementation("net.hollowcube.common:common:0.0.0") implementation(project(":modules:player")) } \ No newline at end of file diff --git a/modules/test/README.md b/modules/test/README.md deleted file mode 100644 index e9d902f1..00000000 --- a/modules/test/README.md +++ /dev/null @@ -1,5 +0,0 @@ -## test - -A module for test utilities used by the others. Only ever included for tests. - -Contains a copy of the Minestom internal test framework until that has been extracted to its own module. diff --git a/modules/test/build.gradle.kts b/modules/test/build.gradle.kts deleted file mode 100644 index 8c7706b5..00000000 --- a/modules/test/build.gradle.kts +++ /dev/null @@ -1,28 +0,0 @@ -plugins { - `java-library` -} - -dependencies { - - // JUnit - api("org.junit.jupiter:junit-jupiter-api:5.9.0") - api("org.junit.jupiter:junit-jupiter-params:5.9.0") - runtimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.0") - - // Truth - api("com.google.truth:truth:1.1.3") - - - // TestContainers - fun testContainersApi(name: String) { - api("org.testcontainers:$name:1.17.3") { - exclude(group = "junit", module = "junit") - } - } - - testContainersApi("testcontainers") - testContainersApi("junit-jupiter") - testContainersApi("mongodb") - - -} \ No newline at end of file diff --git a/modules/test/src/main/java/net/hollowcube/test/ComponentUtil.java b/modules/test/src/main/java/net/hollowcube/test/ComponentUtil.java deleted file mode 100644 index 4e7684d1..00000000 --- a/modules/test/src/main/java/net/hollowcube/test/ComponentUtil.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.hollowcube.test; - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.TranslatableComponent; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import org.jetbrains.annotations.NotNull; - -public class ComponentUtil { - - public static @NotNull String toString(@NotNull Component component) { - if (component instanceof TranslatableComponent comp) - return comp.key(); - return PlainTextComponentSerializer.plainText().serialize(component); - } -} diff --git a/modules/test/src/main/java/net/hollowcube/test/TestUtil.java b/modules/test/src/main/java/net/hollowcube/test/TestUtil.java deleted file mode 100644 index 9c7911bd..00000000 --- a/modules/test/src/main/java/net/hollowcube/test/TestUtil.java +++ /dev/null @@ -1,40 +0,0 @@ -package net.hollowcube.test; - -import net.minestom.server.entity.Player; -import net.minestom.server.network.packet.server.SendablePacket; -import net.minestom.server.network.player.PlayerConnection; -import org.jetbrains.annotations.NotNull; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.time.Instant; -import java.util.UUID; - -//todo Moved straight from chat module, needs some refactoring -public class TestUtil { - - public static Instant instantNow() { - return Instant.ofEpochMilli(1659127729952L); - } - - public static @NotNull Player headlessPlayer(@NotNull String name) { - return new Player(UUID.randomUUID(), name, EMPTY_PLAYER_CONNECTION); - } - - public static @NotNull Player headlessPlayer() { - return headlessPlayer("test0"); - } - - private static final PlayerConnection EMPTY_PLAYER_CONNECTION = new PlayerConnection() { - @Override - public void sendPacket(@NotNull SendablePacket packet) { - - } - - @Override - public @NotNull SocketAddress getRemoteAddress() { - return new InetSocketAddress(0); - } - }; - -} diff --git a/modules/test/src/main/java/net/minestom/server/test/Collector.java b/modules/test/src/main/java/net/minestom/server/test/Collector.java deleted file mode 100644 index 813529bb..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/Collector.java +++ /dev/null @@ -1,40 +0,0 @@ -package net.minestom.server.test; - -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.function.Consumer; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; - -public interface Collector { - @NotNull List<@NotNull T> collect(); - - default

void assertSingle(@NotNull Class

type, @NotNull Consumer

consumer) { - List elements = collect(); - assertEquals(1, elements.size(), "Expected 1 element, got " + elements); - var element = elements.get(0); - assertInstanceOf(type, element, "Expected type " + type.getSimpleName() + ", got " + element.getClass().getSimpleName()); - consumer.accept((P) element); - } - - default void assertSingle(@NotNull Consumer consumer) { - List elements = collect(); - assertEquals(1, elements.size(), "Expected 1 element, got " + elements); - consumer.accept(elements.get(0)); - } - - default void assertCount(int count) { - List elements = collect(); - assertEquals(count, elements.size(), "Expected " + count + " element(s), got " + elements.size() + ": " + elements); - } - - default void assertSingle() { - assertCount(1); - } - - default void assertEmpty() { - assertCount(0); - } -} \ No newline at end of file diff --git a/modules/test/src/main/java/net/minestom/server/test/Env.java b/modules/test/src/main/java/net/minestom/server/test/Env.java deleted file mode 100644 index 91f5c443..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/Env.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.minestom.server.test; - -import net.minestom.server.ServerProcess; -import net.minestom.server.coordinate.Pos; -import net.minestom.server.entity.Player; -import net.minestom.server.event.Event; -import net.minestom.server.event.EventFilter; -import net.minestom.server.instance.Instance; -import net.minestom.server.instance.block.Block; -import net.minestom.server.network.PlayerProvider; -import org.jetbrains.annotations.NotNull; - -import java.time.Duration; -import java.util.function.BooleanSupplier; - -public interface Env { - - @NotNull ServerProcess process(); - - @NotNull TestConnection createConnection(); - - @NotNull Collector trackEvent(@NotNull Class eventType, @NotNull EventFilter filter, @NotNull H actor); - - @NotNull FlexibleListener listen(@NotNull Class eventType); - - default void tick() { - process().ticker().tick(System.nanoTime()); - } - - default boolean tickWhile(BooleanSupplier condition, Duration timeout) { - var ticker = process().ticker(); - final long start = System.nanoTime(); - while (condition.getAsBoolean()) { - final long tick = System.nanoTime(); - ticker.tick(tick); - if (timeout != null && System.nanoTime() - start > timeout.toNanos()) { - return false; - } - } - return true; - } - - default @NotNull Player createPlayer(@NotNull Instance instance, @NotNull Pos pos) { - return createConnection().connect(Player::new, instance, pos).join(); - } - - default @NotNull Player createPlayer(@NotNull PlayerProvider playerProvider, @NotNull Instance instance, @NotNull Pos pos) { - return createConnection().connect(playerProvider, instance, pos).join(); - } - - default @NotNull Instance createFlatInstance() { - var instance = process().instance().createInstanceContainer(); - instance.setGenerator(unit -> unit.modifier().fillHeight(0, 40, Block.STONE)); -// instance.loadChunk(0, 0).join(); //todo this line breaks tests that need a player... somehow... - return instance; - } -} diff --git a/modules/test/src/main/java/net/minestom/server/test/EnvBefore.java b/modules/test/src/main/java/net/minestom/server/test/EnvBefore.java deleted file mode 100644 index b59dc246..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/EnvBefore.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.minestom.server.test; - -import org.junit.jupiter.api.extension.BeforeEachCallback; -import org.junit.jupiter.api.extension.ExtensionContext; - -final class EnvBefore implements BeforeEachCallback { - @Override - public void beforeEach(ExtensionContext context) { - System.setProperty("minestom.viewable-packet", "false"); - } -} diff --git a/modules/test/src/main/java/net/minestom/server/test/EnvCleaner.java b/modules/test/src/main/java/net/minestom/server/test/EnvCleaner.java deleted file mode 100644 index c1940136..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/EnvCleaner.java +++ /dev/null @@ -1,16 +0,0 @@ -package net.minestom.server.test; - -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.InvocationInterceptor; -import org.junit.jupiter.api.extension.ReflectiveInvocationContext; - -import java.lang.reflect.Method; - -final class EnvCleaner implements InvocationInterceptor { - @Override - public void interceptTestMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { - invocation.proceed(); - EnvImpl env = (EnvImpl) invocationContext.getArguments().get(0); - env.cleanup(); - } -} diff --git a/modules/test/src/main/java/net/minestom/server/test/EnvImpl.java b/modules/test/src/main/java/net/minestom/server/test/EnvImpl.java deleted file mode 100644 index 73f848dd..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/EnvImpl.java +++ /dev/null @@ -1,111 +0,0 @@ -package net.minestom.server.test; - -import net.minestom.server.ServerProcess; -import net.minestom.server.event.Event; -import net.minestom.server.event.EventFilter; -import net.minestom.server.event.EventListener; -import net.minestom.server.utils.debug.DebugUtils; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.Consumer; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -final class EnvImpl implements Env { - - static { - DebugUtils.INSIDE_TEST = true; - } - - private final ServerProcess process; - private final List> listeners = new CopyOnWriteArrayList<>(); - - public EnvImpl(ServerProcess process) { - this.process = process; - } - - @Override - public @NotNull ServerProcess process() { - return process; - } - - @Override - public @NotNull TestConnection createConnection() { - return new TestConnectionImpl(this); - } - - @Override - public @NotNull Collector trackEvent(@NotNull Class eventType, @NotNull EventFilter filter, @NotNull H actor) { - var tracker = new EventCollector(actor); - this.process.eventHandler().map(actor, filter).addListener(eventType, tracker.events::add); - return tracker; - } - - @Override - public @NotNull FlexibleListener listen(@NotNull Class eventType) { - var handler = process.eventHandler(); - var flexible = new FlexibleListenerImpl<>(eventType); - var listener = EventListener.of(eventType, e -> flexible.handler.accept(e)); - handler.addListener(listener); - this.listeners.add(flexible); - return flexible; - } - - void cleanup() { - this.listeners.forEach(FlexibleListenerImpl::check); - } - - final class EventCollector implements Collector { - private final Object handler; - private final List events = new CopyOnWriteArrayList<>(); - - public EventCollector(Object handler) { - this.handler = handler; - } - - @Override - public @NotNull List collect() { - process.eventHandler().unmap(handler); - return List.copyOf(events); - } - } - - static final class FlexibleListenerImpl implements FlexibleListener { - private final Class eventType; - private Consumer handler = e -> { - }; - private boolean initialized; - private boolean called; - - FlexibleListenerImpl(Class eventType) { - this.eventType = eventType; - } - - @Override - public void followup(@NotNull Consumer handler) { - updateHandler(handler); - } - - @Override - public void failFollowup() { - updateHandler(e -> fail("Event " + e.getClass().getSimpleName() + " was not expected")); - } - - void updateHandler(@NotNull Consumer handler) { - check(); - this.initialized = true; - this.called = false; - this.handler = e -> { - handler.accept(e); - this.called = true; - }; - } - - void check() { - assertTrue(!initialized || called, "Last listener has not been called: " + eventType.getSimpleName()); - } - } -} diff --git a/modules/test/src/main/java/net/minestom/server/test/EnvParameterResolver.java b/modules/test/src/main/java/net/minestom/server/test/EnvParameterResolver.java deleted file mode 100644 index 5b960ae1..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/EnvParameterResolver.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.minestom.server.test; - -import net.minestom.server.MinecraftServer; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.api.extension.ParameterResolutionException; -import org.junit.jupiter.api.extension.support.TypeBasedParameterResolver; - -final class EnvParameterResolver extends TypeBasedParameterResolver { - @Override - public Env resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) - throws ParameterResolutionException { - return new EnvImpl(MinecraftServer.updateProcess()); - } -} diff --git a/modules/test/src/main/java/net/minestom/server/test/EnvTest.java b/modules/test/src/main/java/net/minestom/server/test/EnvTest.java deleted file mode 100644 index fe0230f6..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/EnvTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.minestom.server.test; - -import org.junit.jupiter.api.extension.ExtendWith; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@ExtendWith(EnvParameterResolver.class) -@ExtendWith(EnvBefore.class) -@ExtendWith(EnvCleaner.class) -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface EnvTest { - -} diff --git a/modules/test/src/main/java/net/minestom/server/test/FlexibleListener.java b/modules/test/src/main/java/net/minestom/server/test/FlexibleListener.java deleted file mode 100644 index 446a3c8c..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/FlexibleListener.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.minestom.server.test; - -import net.minestom.server.event.Event; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Consumer; - -public interface FlexibleListener { - /** - * Updates the handler. Fails if the previous followup has not been called. - */ - void followup(@NotNull Consumer handler); - - default void followup() { - followup(event -> { - // Empty - }); - } - - /** - * Fails if an event is received. Valid until the next followup call. - */ - void failFollowup(); -} diff --git a/modules/test/src/main/java/net/minestom/server/test/TestConnection.java b/modules/test/src/main/java/net/minestom/server/test/TestConnection.java deleted file mode 100644 index f71ff8c0..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/TestConnection.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.minestom.server.test; - -import net.minestom.server.coordinate.Pos; -import net.minestom.server.entity.Player; -import net.minestom.server.instance.Instance; -import net.minestom.server.network.PlayerProvider; -import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; - -import java.util.concurrent.CompletableFuture; - -public interface TestConnection { - @NotNull CompletableFuture<@NotNull Player> connect(@NotNull PlayerProvider playerProvider, @NotNull Instance instance, @NotNull Pos pos); - - @NotNull Collector trackIncoming(@NotNull Class type); - - default @NotNull Collector trackIncoming() { - return trackIncoming(ServerPacket.class); - } -} diff --git a/modules/test/src/main/java/net/minestom/server/test/TestConnectionImpl.java b/modules/test/src/main/java/net/minestom/server/test/TestConnectionImpl.java deleted file mode 100644 index db04b617..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/TestConnectionImpl.java +++ /dev/null @@ -1,87 +0,0 @@ -package net.minestom.server.test; - -import net.minestom.server.ServerProcess; -import net.minestom.server.coordinate.Pos; -import net.minestom.server.entity.Player; -import net.minestom.server.event.player.PlayerLoginEvent; -import net.minestom.server.instance.Instance; -import net.minestom.server.network.PlayerProvider; -import net.minestom.server.network.packet.server.SendablePacket; -import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.player.PlayerConnection; -import org.jetbrains.annotations.NotNull; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CopyOnWriteArrayList; - -final class TestConnectionImpl implements TestConnection { - private final ServerProcess process; - private final PlayerConnectionImpl playerConnection = new PlayerConnectionImpl(); - - private final List> incomingTrackers = new CopyOnWriteArrayList<>(); - - TestConnectionImpl(Env env) { - this.process = env.process(); - } - - @Override - public @NotNull CompletableFuture connect(@NotNull PlayerProvider playerProvider, @NotNull Instance instance, @NotNull Pos pos) { - Player player = playerProvider.createPlayer(UUID.randomUUID(), "RandName", playerConnection); - player.eventNode().addListener(PlayerLoginEvent.class, event -> { - event.setSpawningInstance(instance); - event.getPlayer().setRespawnPoint(pos); - }); - - return process.connection().startPlayState(player, true) - .thenApply(unused -> { - process.connection().updateWaitingPlayers(); - return player; - }); - } - - @Override - public @NotNull Collector trackIncoming(@NotNull Class type) { - var tracker = new IncomingCollector<>(type); - this.incomingTrackers.add((IncomingCollector) tracker); - return tracker; - } - - final class PlayerConnectionImpl extends PlayerConnection { - @Override - public void sendPacket(@NotNull SendablePacket packet) { - for (var tracker : incomingTrackers) { - final var serverPacket = SendablePacket.extractServerPacket(packet); - if (tracker.type.isAssignableFrom(serverPacket.getClass())) tracker.packets.add(serverPacket); - } - } - - @Override - public @NotNull SocketAddress getRemoteAddress() { - return new InetSocketAddress("localhost", 25565); - } - - @Override - public void disconnect() { - - } - } - - final class IncomingCollector implements Collector { - private final Class type; - private final List packets = new CopyOnWriteArrayList<>(); - - public IncomingCollector(Class type) { - this.type = type; - } - - @Override - public @NotNull List collect() { - incomingTrackers.remove(this); - return List.copyOf(packets); - } - } -} diff --git a/modules/test/src/main/java/net/minestom/server/test/TestUtils.java b/modules/test/src/main/java/net/minestom/server/test/TestUtils.java deleted file mode 100644 index 7f50e043..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/TestUtils.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.minestom.server.test; - -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.nbt.NBTException; -import org.jglrxavpok.hephaistos.parser.SNBTParser; - -import java.io.StringReader; -import java.lang.ref.WeakReference; - -import static org.junit.jupiter.api.Assertions.*; - -public class TestUtils { - public static void waitUntilCleared(WeakReference ref) { - while (ref.get() != null) { - System.gc(); - try { - Thread.sleep(50); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - } - - public static void assertEqualsSNBT(String snbt, NBTCompound compound) { - try { - final var converted = (NBTCompound) new SNBTParser(new StringReader(snbt)).parse(); - assertEquals(converted, compound); - } catch (NBTException e) { - fail(e); - } - } - - public static void assertEqualsIgnoreSpace(String s1, String s2, boolean matchCase) { - final String val1 = stripExtraSpaces(s1); - final String val2 = stripExtraSpaces(s2); - if (matchCase) { - assertEquals(val1, val2); - } else { - assertTrue(val1.equalsIgnoreCase(val2)); - } - } - - public static void assertEqualsIgnoreSpace(String s1, String s2) { - assertEqualsIgnoreSpace(s1, s2, true); - } - - private static String stripExtraSpaces(String s) { - StringBuilder formattedString = new StringBuilder(); - java.util.StringTokenizer st = new java.util.StringTokenizer(s); - while (st.hasMoreTokens()) { - formattedString.append(st.nextToken()); - } - return formattedString.toString().trim(); - } -} diff --git a/modules/test/src/main/java/net/minestom/server/test/truth/AbstractInventorySubject.java b/modules/test/src/main/java/net/minestom/server/test/truth/AbstractInventorySubject.java deleted file mode 100644 index 0f04b12c..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/truth/AbstractInventorySubject.java +++ /dev/null @@ -1,60 +0,0 @@ -package net.minestom.server.test.truth; - -import com.google.common.truth.Fact; -import com.google.common.truth.FailureMetadata; -import com.google.common.truth.Subject; -import com.google.common.truth.Truth; -import net.minestom.server.inventory.AbstractInventory; -import net.minestom.server.item.ItemStack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.List; -import java.util.function.Predicate; - -import static com.google.common.truth.Truth.assertAbout; - -public class AbstractInventorySubject extends Subject { - private final AbstractInventory actual; - - public static AbstractInventorySubject assertThat(AbstractInventory actual) { - return assertAbout(abstractInventories()).that(actual); - } - - protected AbstractInventorySubject(FailureMetadata metadata, @Nullable AbstractInventory actual) { - super(metadata, actual); - this.actual = actual; - } - - public void isEmpty() { - if (!itemStacks().isEmpty()) { - failWithActual(Fact.simpleFact("expected to be empty")); - } - } - - public void isNotEmpty() { - if (itemStacks().isEmpty()) { - failWithActual(Fact.simpleFact("expected not to be empty")); - } - } - - public void containsExactly(@NotNull ItemStack... itemStacks) { - Truth.assertThat(itemStacks()).containsExactly((Object[]) itemStacks); - } - - public void doesNotContain(@NotNull ItemStack itemStack) { - Truth.assertThat(itemStacks()).doesNotContain(itemStack); - } - - private List itemStacks() { - return Arrays.stream(actual.getItemStacks()) - .filter(Predicate.not(ItemStack::isAir)) - .toList(); - } - - private static Factory abstractInventories() { - return AbstractInventorySubject::new; - } - -} diff --git a/modules/test/src/main/java/net/minestom/server/test/truth/EntitySubject.java b/modules/test/src/main/java/net/minestom/server/test/truth/EntitySubject.java deleted file mode 100644 index 6aae0b55..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/truth/EntitySubject.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.minestom.server.test.truth; - -import com.google.common.truth.Fact; -import com.google.common.truth.FailureMetadata; -import com.google.common.truth.Subject; -import com.google.common.truth.Truth; -import net.minestom.server.entity.Entity; -import org.jetbrains.annotations.Nullable; - -@SuppressWarnings("ConstantConditions") -public class EntitySubject extends Subject { - private final Entity actual; - - public static EntitySubject assertThat(@Nullable Entity entity) { - return Truth.assertAbout(entities()).that(entity); - } - - protected EntitySubject(FailureMetadata metadata, @Nullable Entity actual) { - super(metadata, actual); - this.actual = actual; - } - - public void isRemoved() { - if (!actual.isRemoved()) { - failWithActual(Fact.simpleFact("expected to be removed")); - } - } - - public void isNotRemoved() { - if (actual.isRemoved()) { - failWithActual(Fact.simpleFact("expected not to be removed")); - } - } - - public static Factory entities() { - return EntitySubject::new; - } - -} diff --git a/modules/test/src/main/java/net/minestom/server/test/truth/ItemStackSubject.java b/modules/test/src/main/java/net/minestom/server/test/truth/ItemStackSubject.java deleted file mode 100644 index c06cb8c6..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/truth/ItemStackSubject.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.minestom.server.test.truth; - -import com.google.common.truth.FailureMetadata; -import com.google.common.truth.Subject; -import com.google.common.truth.Truth; -import net.minestom.server.item.ItemStack; -import org.jetbrains.annotations.Nullable; - -@SuppressWarnings("ConstantConditions") -public class ItemStackSubject extends Subject { - private final ItemStack actual; - - public static ItemStackSubject assertThat(@Nullable ItemStack actual) { - return Truth.assertAbout(itemStacks()).that(actual); - } - - protected ItemStackSubject(FailureMetadata metadata, @Nullable ItemStack actual) { - super(metadata, actual); - this.actual = actual; - } - - public void hasAmount(int expectedAmount) { - check("amount()").that(actual.amount()).isEqualTo(expectedAmount); - } - - - public static Factory itemStacks() { - return ItemStackSubject::new; - } - -} diff --git a/modules/test/src/main/java/net/minestom/server/test/truth/MinestomTruth.java b/modules/test/src/main/java/net/minestom/server/test/truth/MinestomTruth.java deleted file mode 100644 index 4974adfa..00000000 --- a/modules/test/src/main/java/net/minestom/server/test/truth/MinestomTruth.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.minestom.server.test.truth; - -import net.minestom.server.entity.Entity; -import net.minestom.server.inventory.AbstractInventory; -import net.minestom.server.item.ItemStack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public final class MinestomTruth { - private MinestomTruth() {} - - public static @NotNull EntitySubject assertThat(@Nullable Entity actual) { - return EntitySubject.assertThat(actual); - } - - public static @NotNull AbstractInventorySubject assertThat(@Nullable AbstractInventory actual) { - return AbstractInventorySubject.assertThat(actual); - } - - public static @NotNull ItemStackSubject assertThat(@Nullable ItemStack actual) { - return ItemStackSubject.assertThat(actual); - } - -} diff --git a/settings.gradle.kts b/settings.gradle.kts index c5b0e5d5..fa5d9f70 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,8 +1,29 @@ -rootProject.name = "JointMMO" +var ext = (gradle as ExtensionAware).extra + +rootProject.name = "libmmo" + +val env = mutableMapOf() +file(".env").readLines().forEach { + //todo add regular env vars, just use this as a fallback. + if (it.isNotEmpty() && !it.startsWith("#")) { + val pos = it.indexOf("=") + val key = it.substring(0, pos) + var value = it.substring(pos + 1) + if (System.getenv(key) != null) + value = System.getenv(key) + env[key] = value + } +} + +val commonPath = env["COMMON_LIB_PATH"] +if (commonPath != null) { + includeBuild(commonPath) +} else { + System.err.println("COMMON_LIB_PATH not set, using maven dependency instead. NOT CURRENTLY IMPLEMENTED") +} include(":modules") include(":modules:common") -include(":modules:test") include(":modules:chat") include(":modules:item") include(":modules:block-interactions")