From 684710f2e0c54e31768522ade65f6f779b3e5a33 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sun, 21 Jul 2024 17:31:46 +0800 Subject: [PATCH] refactor: move common classes into `common` package + add: module dependency checker + fix: the `production work` in `works module` can't work if `resource world module` is disabled. --- build.gradle | 15 +- fuji-fabric.wiki | 2 +- .../generator/structure/Reference.java | 31 ++++ .../job}/MentionPlayersJob.java | 2 +- .../module/common/manager/BossBarManager.java | 1 - .../random_teleport/HeightFinder.java | 2 +- .../HeightFindingStrategy.java | 2 +- .../random_teleport/RandomTeleport.java | 2 +- .../initializer/chat/ChatInitializer.java | 2 +- .../NewbieWelcomeInitializer.java | 2 +- .../ResourceWorldInitializer.java | 2 +- .../top_chunks/TopChunksInitializer.java | 2 +- .../initializer/tpa/TpaInitializer.java | 2 +- .../works/work_type/ProductionWork.java | 2 +- .../ThreadedAnvilChunkStorageMixin.java | 2 +- .../io/github/sakurawald/util/JsonUtil.java | 21 +++ src/main/resources/fuji.mixins.json | 2 +- .../CheckMixinRegistryTest.java} | 6 +- .../checker/CheckModuleDependencyTest.java | 156 ++++++++++++++++++ 19 files changed, 236 insertions(+), 20 deletions(-) create mode 100644 src/main/java/io/github/sakurawald/generator/structure/Reference.java rename src/main/java/io/github/sakurawald/module/{initializer/chat/mention => common/job}/MentionPlayersJob.java (96%) rename src/main/java/io/github/sakurawald/module/{initializer/newbie_welcome => common}/random_teleport/HeightFinder.java (81%) rename src/main/java/io/github/sakurawald/module/{initializer/newbie_welcome => common}/random_teleport/HeightFindingStrategy.java (98%) rename src/main/java/io/github/sakurawald/module/{initializer/newbie_welcome => common}/random_teleport/RandomTeleport.java (98%) rename src/main/java/io/github/sakurawald/module/mixin/{top_chunks => _internal/low_level}/ThreadedAnvilChunkStorageMixin.java (85%) create mode 100644 src/main/java/io/github/sakurawald/util/JsonUtil.java rename src/test/java/{generator/MixinRegistryGenTest.java => checker/CheckMixinRegistryTest.java} (96%) create mode 100644 src/test/java/checker/CheckModuleDependencyTest.java diff --git a/build.gradle b/build.gradle index f314deae9..83bd11ae5 100755 --- a/build.gradle +++ b/build.gradle @@ -158,13 +158,22 @@ tasks.register('generateDocs') { } tasks.modrinthSyncBody.dependsOn(generateDocs) -tasks.register('generateMixinRegistry') { +tasks.register('checkMixinRegistryTest') { outputs.upToDateWhen { false } test { filter { - includeTestsMatching 'MixinRegistryGenTest.generate' + includeTestsMatching 'CheckMixinRegistryTest.test' } } } -tasks.compileJava.dependsOn(generateMixinRegistry) +tasks.compileJava.dependsOn(checkMixinRegistryTest) +tasks.register('checkModuleDependencyTest') { + outputs.upToDateWhen { false } + test { + filter { + includeTestsMatching 'CheckModuleDependencyTest.test' + } + } +} +tasks.compileJava.dependsOn(checkModuleDependencyTest) diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki index c2becb367..f63cdf022 160000 --- a/fuji-fabric.wiki +++ b/fuji-fabric.wiki @@ -1 +1 @@ -Subproject commit c2becb367e3de39aff4ea50a81c2cf155b43cac4 +Subproject commit f63cdf022bbe028bc75d9955fad34775cbd26c69 diff --git a/src/main/java/io/github/sakurawald/generator/structure/Reference.java b/src/main/java/io/github/sakurawald/generator/structure/Reference.java new file mode 100644 index 000000000..582597c3f --- /dev/null +++ b/src/main/java/io/github/sakurawald/generator/structure/Reference.java @@ -0,0 +1,31 @@ +package io.github.sakurawald.generator.structure; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.*; + +@Data +@AllArgsConstructor +public class Reference { + String definition; + List reference; + + public static List reduce(List references) { + // merge + Map map = new HashMap<>(); + for (Reference reference : references) { + map.putIfAbsent(reference.definition, reference); + map.get(reference.definition).getReference().addAll(reference.reference); + } + + //reduce + for (Reference reference : map.values()) { + Set set = new HashSet<>(reference.reference); + reference.reference.clear(); + reference.reference.addAll(set); + } + + return map.values().stream().toList(); + } +} diff --git a/src/main/java/io/github/sakurawald/module/initializer/chat/mention/MentionPlayersJob.java b/src/main/java/io/github/sakurawald/module/common/job/MentionPlayersJob.java similarity index 96% rename from src/main/java/io/github/sakurawald/module/initializer/chat/mention/MentionPlayersJob.java rename to src/main/java/io/github/sakurawald/module/common/job/MentionPlayersJob.java index 7251e8336..9e822664e 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/chat/mention/MentionPlayersJob.java +++ b/src/main/java/io/github/sakurawald/module/common/job/MentionPlayersJob.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.initializer.chat.mention; +package io.github.sakurawald.module.common.job; import io.github.sakurawald.config.Configs; import io.github.sakurawald.config.model.ConfigModel; diff --git a/src/main/java/io/github/sakurawald/module/common/manager/BossBarManager.java b/src/main/java/io/github/sakurawald/module/common/manager/BossBarManager.java index f867fa97f..22fe19b10 100644 --- a/src/main/java/io/github/sakurawald/module/common/manager/BossBarManager.java +++ b/src/main/java/io/github/sakurawald/module/common/manager/BossBarManager.java @@ -12,7 +12,6 @@ import java.util.ArrayList; import java.util.List; -@SuppressWarnings("LombokGetterMayBeUsed") @Slf4j public class BossBarManager { diff --git a/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/random_teleport/HeightFinder.java b/src/main/java/io/github/sakurawald/module/common/random_teleport/HeightFinder.java similarity index 81% rename from src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/random_teleport/HeightFinder.java rename to src/main/java/io/github/sakurawald/module/common/random_teleport/HeightFinder.java index dad40cb74..3a698a721 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/random_teleport/HeightFinder.java +++ b/src/main/java/io/github/sakurawald/module/common/random_teleport/HeightFinder.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.initializer.newbie_welcome.random_teleport; +package io.github.sakurawald.module.common.random_teleport; import java.util.OptionalInt; import net.minecraft.world.chunk.Chunk; diff --git a/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/random_teleport/HeightFindingStrategy.java b/src/main/java/io/github/sakurawald/module/common/random_teleport/HeightFindingStrategy.java similarity index 98% rename from src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/random_teleport/HeightFindingStrategy.java rename to src/main/java/io/github/sakurawald/module/common/random_teleport/HeightFindingStrategy.java index be4bcefd0..a03ad2c8b 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/random_teleport/HeightFindingStrategy.java +++ b/src/main/java/io/github/sakurawald/module/common/random_teleport/HeightFindingStrategy.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.initializer.newbie_welcome.random_teleport; +package io.github.sakurawald.module.common.random_teleport; import java.util.Optional; import java.util.OptionalInt; diff --git a/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/random_teleport/RandomTeleport.java b/src/main/java/io/github/sakurawald/module/common/random_teleport/RandomTeleport.java similarity index 98% rename from src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/random_teleport/RandomTeleport.java rename to src/main/java/io/github/sakurawald/module/common/random_teleport/RandomTeleport.java index 3af0babee..2d894fca7 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/random_teleport/RandomTeleport.java +++ b/src/main/java/io/github/sakurawald/module/common/random_teleport/RandomTeleport.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.initializer.newbie_welcome.random_teleport; +package io.github.sakurawald.module.common.random_teleport; import com.google.common.base.Stopwatch; import io.github.sakurawald.Fuji; diff --git a/src/main/java/io/github/sakurawald/module/initializer/chat/ChatInitializer.java b/src/main/java/io/github/sakurawald/module/initializer/chat/ChatInitializer.java index 5a6bb2ae7..8d12a2d64 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/chat/ChatInitializer.java +++ b/src/main/java/io/github/sakurawald/module/initializer/chat/ChatInitializer.java @@ -14,7 +14,7 @@ import io.github.sakurawald.config.model.ChatModel; import io.github.sakurawald.module.initializer.ModuleInitializer; import io.github.sakurawald.module.initializer.chat.display.DisplayHelper; -import io.github.sakurawald.module.initializer.chat.mention.MentionPlayersJob; +import io.github.sakurawald.module.common.job.MentionPlayersJob; import io.github.sakurawald.util.CommandUtil; import io.github.sakurawald.util.DateUtil; import io.github.sakurawald.util.PermissionUtil; diff --git a/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/NewbieWelcomeInitializer.java b/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/NewbieWelcomeInitializer.java index a01a9957b..f4682c762 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/NewbieWelcomeInitializer.java +++ b/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/NewbieWelcomeInitializer.java @@ -1,7 +1,7 @@ package io.github.sakurawald.module.initializer.newbie_welcome; import io.github.sakurawald.module.initializer.ModuleInitializer; -import io.github.sakurawald.module.initializer.newbie_welcome.random_teleport.RandomTeleport; +import io.github.sakurawald.module.common.random_teleport.RandomTeleport; import io.github.sakurawald.util.MessageUtil; import net.minecraft.server.network.ServerPlayerEntity; diff --git a/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldInitializer.java b/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldInitializer.java index e082e4531..04a406ce9 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldInitializer.java +++ b/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldInitializer.java @@ -8,7 +8,7 @@ import io.github.sakurawald.config.Configs; import io.github.sakurawald.config.model.ConfigModel; import io.github.sakurawald.module.initializer.ModuleInitializer; -import io.github.sakurawald.module.initializer.newbie_welcome.random_teleport.RandomTeleport; +import io.github.sakurawald.module.common.random_teleport.RandomTeleport; import io.github.sakurawald.module.initializer.resource_world.interfaces.DimensionOptionsMixinInterface; import io.github.sakurawald.module.common.accessor.SimpleRegistryMixinInterface; import io.github.sakurawald.util.CommandUtil; diff --git a/src/main/java/io/github/sakurawald/module/initializer/top_chunks/TopChunksInitializer.java b/src/main/java/io/github/sakurawald/module/initializer/top_chunks/TopChunksInitializer.java index c7d517b2b..2c65a8aa3 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/top_chunks/TopChunksInitializer.java +++ b/src/main/java/io/github/sakurawald/module/initializer/top_chunks/TopChunksInitializer.java @@ -6,7 +6,7 @@ import io.github.sakurawald.config.Configs; import io.github.sakurawald.config.model.ConfigModel; import io.github.sakurawald.module.initializer.ModuleInitializer; -import io.github.sakurawald.module.mixin.top_chunks.ThreadedAnvilChunkStorageMixin; +import io.github.sakurawald.module.mixin._internal.low_level.ThreadedAnvilChunkStorageMixin; import io.github.sakurawald.util.MessageUtil; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; diff --git a/src/main/java/io/github/sakurawald/module/initializer/tpa/TpaInitializer.java b/src/main/java/io/github/sakurawald/module/initializer/tpa/TpaInitializer.java index 3f2a1e852..5211a80ff 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/tpa/TpaInitializer.java +++ b/src/main/java/io/github/sakurawald/module/initializer/tpa/TpaInitializer.java @@ -5,7 +5,7 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import io.github.sakurawald.module.initializer.ModuleInitializer; -import io.github.sakurawald.module.initializer.chat.mention.MentionPlayersJob; +import io.github.sakurawald.module.common.job.MentionPlayersJob; import io.github.sakurawald.util.CommandUtil; import io.github.sakurawald.util.MessageUtil; import lombok.Getter; diff --git a/src/main/java/io/github/sakurawald/module/initializer/works/work_type/ProductionWork.java b/src/main/java/io/github/sakurawald/module/initializer/works/work_type/ProductionWork.java index cc3717b19..04f4a2713 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/works/work_type/ProductionWork.java +++ b/src/main/java/io/github/sakurawald/module/initializer/works/work_type/ProductionWork.java @@ -7,7 +7,7 @@ import io.github.sakurawald.module.initializer.works.WorksCache; import io.github.sakurawald.module.common.gui.ConfirmGui; import io.github.sakurawald.module.common.gui.InputSignGui; -import io.github.sakurawald.module.mixin.top_chunks.ThreadedAnvilChunkStorageMixin; +import io.github.sakurawald.module.mixin._internal.low_level.ThreadedAnvilChunkStorageMixin; import io.github.sakurawald.util.DateUtil; import io.github.sakurawald.util.GuiUtil; import io.github.sakurawald.util.MessageUtil; diff --git a/src/main/java/io/github/sakurawald/module/mixin/top_chunks/ThreadedAnvilChunkStorageMixin.java b/src/main/java/io/github/sakurawald/module/mixin/_internal/low_level/ThreadedAnvilChunkStorageMixin.java similarity index 85% rename from src/main/java/io/github/sakurawald/module/mixin/top_chunks/ThreadedAnvilChunkStorageMixin.java rename to src/main/java/io/github/sakurawald/module/mixin/_internal/low_level/ThreadedAnvilChunkStorageMixin.java index 375814236..6643f70e5 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/top_chunks/ThreadedAnvilChunkStorageMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/_internal/low_level/ThreadedAnvilChunkStorageMixin.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.mixin.top_chunks; +package io.github.sakurawald.module.mixin._internal.low_level; import net.minecraft.server.world.ChunkHolder; import net.minecraft.server.world.ServerChunkLoadingManager; diff --git a/src/main/java/io/github/sakurawald/util/JsonUtil.java b/src/main/java/io/github/sakurawald/util/JsonUtil.java new file mode 100644 index 000000000..ecc1a57b7 --- /dev/null +++ b/src/main/java/io/github/sakurawald/util/JsonUtil.java @@ -0,0 +1,21 @@ +package io.github.sakurawald.util; + +import com.google.gson.JsonObject; +import lombok.experimental.UtilityClass; + +@UtilityClass +public class JsonUtil { + + public static boolean existsNode(JsonObject root, String path){ + String[] nodes = path.split("\\."); + for (int i = 0; i < nodes.length - 1; i++) { + String node = nodes[i]; + if (!root.has(node)) return false; + if (!root.isJsonObject()) return false; + + root = root.getAsJsonObject(node); + } + + return root.has(nodes[nodes.length - 1]); + } +} diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index d088054a9..2058d570b 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -57,7 +57,7 @@ "language.ServerPlayerMixin", "chat.PlayerListMixin", "_internal.low_level.SimpleRegistryMixin", - "top_chunks.ThreadedAnvilChunkStorageMixin", + "_internal.low_level.ThreadedAnvilChunkStorageMixin", "command_permission.CommandNodeAccessor", "anti_build.EntityMixin", "carpet.fake_player_manager.PlayerListMixin", diff --git a/src/test/java/generator/MixinRegistryGenTest.java b/src/test/java/checker/CheckMixinRegistryTest.java similarity index 96% rename from src/test/java/generator/MixinRegistryGenTest.java rename to src/test/java/checker/CheckMixinRegistryTest.java index ca43330ec..8980e26d4 100644 --- a/src/test/java/generator/MixinRegistryGenTest.java +++ b/src/test/java/checker/CheckMixinRegistryTest.java @@ -1,4 +1,4 @@ -package generator; +package checker; import com.google.gson.*; import io.github.sakurawald.module.ModuleManager; @@ -12,7 +12,7 @@ import java.util.ArrayList; import java.util.List; -public class MixinRegistryGenTest { +public class CheckMixinRegistryTest { private List collectJsonArray(JsonElement jsonElement, String key) { JsonObject jsonObject = jsonElement.getAsJsonObject(); @@ -29,7 +29,7 @@ private List collectMixins(JsonElement jsonElement, String key) { @SneakyThrows @Test - void generate() { + void test() { /* read file */ File file = new File("src/main/resources/fuji.mixins.json"); diff --git a/src/test/java/checker/CheckModuleDependencyTest.java b/src/test/java/checker/CheckModuleDependencyTest.java new file mode 100644 index 000000000..2cb727d5f --- /dev/null +++ b/src/test/java/checker/CheckModuleDependencyTest.java @@ -0,0 +1,156 @@ +package checker; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import io.github.sakurawald.Fuji; +import io.github.sakurawald.config.model.ConfigModel; +import io.github.sakurawald.generator.structure.Reference; +import io.github.sakurawald.util.JsonUtil; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.Test; + +import java.nio.charset.Charset; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Slf4j +public class CheckModuleDependencyTest { + + public static final String COMMON = "common"; + private static final Pattern importPattern = Pattern.compile("import\\s+(\\S+);"); + private static final Pattern staticImportPattern = Pattern.compile("import\\s+static\\s+(\\S+)\\.\\S+;"); + private static final Pattern moduleNamePattern = Pattern.compile("io\\.github\\.sakurawald\\.module\\.(?:initializer|mixin)\\.(\\S+)\\.\\S+;?"); + private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + private List extractMatches(Pattern pattern, String text, int group) { + Matcher matcher = pattern.matcher(text); + + List ret = new ArrayList<>(); + while (matcher.find()) { + ret.add(matcher.group(group)); + } + + return ret; + } + + @SneakyThrows + private List getRefClassNameList(String path) { + String text = FileUtils.readFileToString(Path.of(path).toFile(), Charset.defaultCharset()); + + List ret = new ArrayList<>(); + ret.addAll(extractMatches(importPattern, text, 1)); + ret.addAll(extractMatches(staticImportPattern, text, 1)); + return ret; + } + + private List filterClassName(List className, String prefix) { + return className.stream().filter(s -> s.startsWith(prefix)).toList(); + } + + private Path getCodebasePath() { + return Path.of("src", "main", "java"); + } + + private Reference makeClassRef(Path file) { + String className = file.toString().replace("/", ".").replace("src.main.java.", "").replace(".java", ""); + List refClassNameList = getRefClassNameList(file.toString()); + + // filter only project class ref + refClassNameList = filterClassName(refClassNameList, Fuji.class.getPackage().getName()); + + return new Reference(className, refClassNameList); + } + + private String extractModuleName(String className) { + List moduleNameList = extractMatches(moduleNamePattern, className, 1); + if (moduleNameList.isEmpty()) { + return COMMON; + } + return moduleNameList.getFirst(); + } + + private boolean isRealModulePath(String moduleName) { + JsonElement root = gson.toJsonTree(new ConfigModel()); + return JsonUtil.existsNode((JsonObject) root, "modules.%s.enable".formatted(moduleName)); + } + + private boolean isSibling(String a, String b) { + String[] A = a.split("\\."); + String[] B = b.split("\\."); + + if (A.length != B.length) return false; + for (int i = 0; i < A.length - 1; i++) { + if (!A[i].equals(B[i])) return false; + } + return true; + } + + private Reference makeModuleRef(Reference classRef) { + String definition = extractModuleName(classRef.getDefinition()); + List reference = new ArrayList<>(); + for (String ref : classRef.getReference()) { + String str = extractModuleName(ref); + // skip -> common reference + if (str.equals(COMMON)) continue; + // skip -> self reference + if (definition.equals(str) || definition.startsWith(str)) continue; + if (str.startsWith(definition) && !isRealModulePath(str)) continue; + if (isSibling(definition, str) && !isRealModulePath(definition) && !isRealModulePath(str)) continue; + // skip -> reference internal module + if (str.startsWith("_")) continue; + + reference.add(str); + } + + if (definition.equals(COMMON)) return null; + if (reference.isEmpty()) return null; + return new Reference(definition, reference); + } + + + @SneakyThrows + private List walk(Path path) { + /* per class reference */ + List refs = new ArrayList<>(); + Files.walkFileTree(path, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + Reference reference = makeModuleRef(makeClassRef(file)); + if (reference != null) { + refs.add(reference); + } + + return FileVisitResult.CONTINUE; + } + }); + + /* reduce */ + return Reference.reduce(refs); + } + + @Test + void test() { + CheckModuleDependencyTest gen = new CheckModuleDependencyTest(); + + List refs = gen.walk(gen.getCodebasePath()); + + System.out.println("\n=== module dependency analysis ==="); + refs.forEach(System.out::println); + System.out.println(); + + if (!refs.isEmpty()) { + throw new RuntimeException("module dependency is not pure !"); + } + } +}