From 5b6f429bbeb0229410f94c466a45335d3b8c269d Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 9 Jan 2021 20:17:01 +0800 Subject: [PATCH] Add test mod --- build.gradle | 9 +- .../architectury/test/ConsoleMessageSink.java | 13 ++ .../architectury/test/MessageSink.java | 9 + .../shedaniel/architectury/test/TestMod.java | 211 ++++++++++++++++++ .../test/client/ClientOverlayMessageSink.java | 80 +++++++ common/src/test/resources/fabric.mod.json | 17 ++ fabric/build.gradle | 2 + 7 files changed, 339 insertions(+), 2 deletions(-) create mode 100644 common/src/test/java/me/shedaniel/architectury/test/ConsoleMessageSink.java create mode 100644 common/src/test/java/me/shedaniel/architectury/test/MessageSink.java create mode 100644 common/src/test/java/me/shedaniel/architectury/test/TestMod.java create mode 100644 common/src/test/java/me/shedaniel/architectury/test/client/ClientOverlayMessageSink.java create mode 100644 common/src/test/resources/fabric.mod.json diff --git a/build.gradle b/build.gradle index a6d6350f..afaef1e7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ plugins { - id "architect-plugin" version "1.2.33" + id "architectury-plugin" version "1.3.41" + id "forgified-fabric-loom" version "0.5.22" apply false id "org.cadixdev.licenser" version "0.5.0" id "com.jfrog.bintray" version "1.8.4" id "com.matthewprenger.cursegradle" version "1.4.0" apply false @@ -13,11 +14,15 @@ architectury { subprojects { apply plugin: "forgified-fabric-loom" + + dependencies { + testCompile sourceSets.main.output + } } allprojects { apply plugin: "java" - apply plugin: "architect-plugin" + apply plugin: "architectury-plugin" apply plugin: "org.cadixdev.licenser" archivesBaseName = rootProject.archives_base_name diff --git a/common/src/test/java/me/shedaniel/architectury/test/ConsoleMessageSink.java b/common/src/test/java/me/shedaniel/architectury/test/ConsoleMessageSink.java new file mode 100644 index 00000000..289e7471 --- /dev/null +++ b/common/src/test/java/me/shedaniel/architectury/test/ConsoleMessageSink.java @@ -0,0 +1,13 @@ +package me.shedaniel.architectury.test; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class ConsoleMessageSink implements MessageSink { + protected final Logger logger = LogManager.getLogger("Architectury Test"); + + @Override + public void accept(String message) { + logger.info(message); + } +} diff --git a/common/src/test/java/me/shedaniel/architectury/test/MessageSink.java b/common/src/test/java/me/shedaniel/architectury/test/MessageSink.java new file mode 100644 index 00000000..28710d5b --- /dev/null +++ b/common/src/test/java/me/shedaniel/architectury/test/MessageSink.java @@ -0,0 +1,9 @@ +package me.shedaniel.architectury.test; + +public interface MessageSink { + void accept(String message); + + default void accept(String message, Object... args) { + accept(String.format(message, args)); + } +} diff --git a/common/src/test/java/me/shedaniel/architectury/test/TestMod.java b/common/src/test/java/me/shedaniel/architectury/test/TestMod.java new file mode 100644 index 00000000..1bf85cd6 --- /dev/null +++ b/common/src/test/java/me/shedaniel/architectury/test/TestMod.java @@ -0,0 +1,211 @@ +package me.shedaniel.architectury.test; + +import me.shedaniel.architectury.event.events.*; +import me.shedaniel.architectury.event.events.client.ClientChatEvent; +import me.shedaniel.architectury.event.events.client.ClientLifecycleEvent; +import me.shedaniel.architectury.event.events.client.ClientPlayerEvent; +import me.shedaniel.architectury.hooks.ExplosionHooks; +import me.shedaniel.architectury.platform.Platform; +import me.shedaniel.architectury.test.client.ClientOverlayMessageSink; +import me.shedaniel.architectury.utils.Env; +import me.shedaniel.architectury.utils.EnvExecutor; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.core.Position; +import net.minecraft.core.Vec3i; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; + +import java.util.Optional; + +public class TestMod { + public static final MessageSink SINK = EnvExecutor.getEnvSpecific(() -> ClientOverlayMessageSink::new, () -> ConsoleMessageSink::new); + + public static void initialize() { + debugEvents(); + if (Platform.getEnvironment() == Env.CLIENT) + debugEventsClient(); + } + + public static void debugEvents() { + ChatEvent.SERVER.register((player, message, component) -> { + SINK.accept("Server chat received: " + message); + return InteractionResultHolder.pass(component); + }); + CommandPerformEvent.EVENT.register(event -> { + SINK.accept("Server command performed: " + event.getResults().getReader().getString()); + return InteractionResult.PASS; + }); + CommandRegistrationEvent.EVENT.register((dispatcher, selection) -> { + SINK.accept("Server commands registers"); + }); + EntityEvent.LIVING_DEATH.register((entity, source) -> { + if (entity instanceof Player) { + SINK.accept(entity.getScoreboardName() + " died to " + source.getMsgId() + logSide(entity.level)); + } + return InteractionResult.PASS; + }); + EntityEvent.LIVING_ATTACK.register((entity, source, amount) -> { + if (source.getDirectEntity() instanceof Player) { + SINK.accept(source.getDirectEntity().getScoreboardName() + " deals %.2f damage" + logSide(entity.level), amount); + } + return InteractionResult.PASS; + }); + EntityEvent.ADD.register((entity, level) -> { + if (entity instanceof Player) { + SINK.accept(entity.getScoreboardName() + " was added to " + level.dimension().location().toString() + logSide(level)); + } + return InteractionResult.PASS; + }); + EntityEvent.PLACE_BLOCK.register((world, pos, state, placer) -> { + SINK.accept(Optional.ofNullable(placer).map(Entity::getScoreboardName).orElse("null") + " places block at " + toShortString(pos) + logSide(world)); + return InteractionResult.PASS; + }); + ExplosionEvent.DETONATE.register((world, explosion, affectedEntities) -> { + SINK.accept(world.dimension().location() + " explodes at " + toShortString(ExplosionHooks.getPosition(explosion)) + logSide(world)); + }); + InteractionEvent.LEFT_CLICK_BLOCK.register((player, hand, pos, face) -> { + SINK.accept(player.getScoreboardName() + " left clicks " + toShortString(pos) + logSide(player.level)); + return InteractionResult.PASS; + }); + InteractionEvent.RIGHT_CLICK_BLOCK.register((player, hand, pos, face) -> { + SINK.accept(player.getScoreboardName() + " right clicks " + toShortString(pos) + logSide(player.level)); + return InteractionResult.PASS; + }); + InteractionEvent.RIGHT_CLICK_ITEM.register((player, hand) -> { + SINK.accept(player.getScoreboardName() + " uses " + (hand == InteractionHand.MAIN_HAND ? "main hand" : "off hand") + logSide(player.level)); + return InteractionResultHolder.pass(player.getItemInHand(hand)); + }); + InteractionEvent.INTERACT_ENTITY.register((player, entity, hand) -> { + SINK.accept(player.getScoreboardName() + " interacts with " + entity.getScoreboardName() + " using " + (hand == InteractionHand.MAIN_HAND ? "main hand" : "off hand") + logSide(player.level)); + return InteractionResult.PASS; + }); + LifecycleEvent.SERVER_BEFORE_START.register(instance -> { + SINK.accept("Server ready to start"); + }); + LifecycleEvent.SERVER_STARTING.register(instance -> { + SINK.accept("Server starting"); + }); + LifecycleEvent.SERVER_STARTED.register(instance -> { + SINK.accept("Server started"); + }); + LifecycleEvent.SERVER_STOPPING.register(instance -> { + SINK.accept("Server stopping"); + }); + LifecycleEvent.SERVER_STOPPED.register(instance -> { + SINK.accept("Server stopped"); + }); + LifecycleEvent.SERVER_WORLD_LOAD.register(instance -> { + SINK.accept("Server world loaded: " + instance.dimension().location()); + }); + LifecycleEvent.SERVER_WORLD_UNLOAD.register(instance -> { + SINK.accept("Server world unloaded: " + instance.dimension().location()); + }); + LifecycleEvent.SERVER_WORLD_SAVE.register(instance -> { + SINK.accept("Server world saved: " + instance.dimension().location()); + }); + PlayerEvent.PLAYER_JOIN.register(player -> { + SINK.accept(player.getScoreboardName() + " joined" + logSide(player.level)); + }); + PlayerEvent.PLAYER_QUIT.register(player -> { + SINK.accept(player.getScoreboardName() + " quit" + logSide(player.level)); + }); + PlayerEvent.PLAYER_RESPAWN.register((player, conqueredEnd) -> { + if (!conqueredEnd) { + SINK.accept(player.getScoreboardName() + " respawns " + logSide(player.level)); + } + }); + PlayerEvent.PLAYER_CLONE.register((oldPlayer, newPlayer, wonGame) -> { + SINK.accept("Player cloned: " + newPlayer.getScoreboardName() + logSide(newPlayer.level)); + }); + PlayerEvent.PLAYER_ADVANCEMENT.register((player, advancement) -> { + SINK.accept(player.getScoreboardName() + " was awarded with %s" + logSide(player.level), advancement.getChatComponent().getString()); + }); + PlayerEvent.CRAFT_ITEM.register((player, constructed, inventory) -> { + SINK.accept(player.getScoreboardName() + " crafts " + new TranslatableComponent(constructed.getDescriptionId()).getString() + logSide(player.level)); + }); + PlayerEvent.SMELT_ITEM.register((player, smelted) -> { + SINK.accept(player.getScoreboardName() + " smelts " + new TranslatableComponent(smelted.getDescriptionId()).getString() + logSide(player.level)); + }); + PlayerEvent.PICKUP_ITEM_POST.register((player, entity, stack) -> { + SINK.accept(player.getScoreboardName() + " picks up " + new TranslatableComponent(stack.getDescriptionId()).getString() + logSide(player.level)); + }); + PlayerEvent.DROP_ITEM.register((player, entity) -> { + SINK.accept(player.getScoreboardName() + " drops " + new TranslatableComponent(entity.getItem().getDescriptionId()).getString() + logSide(player.level)); + return InteractionResult.PASS; + }); + PlayerEvent.BREAK_BLOCK.register((world, pos, state, player, xp) -> { + SINK.accept(player.getScoreboardName() + " breaks " + toShortString(pos) + logSide(player.level)); + return InteractionResult.PASS; + }); + PlayerEvent.OPEN_MENU.register((player, menu) -> { + SINK.accept(player.getScoreboardName() + " opens " + toSimpleName(menu) + logSide(player.level)); + }); + PlayerEvent.CLOSE_MENU.register((player, menu) -> { + SINK.accept(player.getScoreboardName() + " closes " + toSimpleName(menu) + logSide(player.level)); + }); + } + + public static String toShortString(Vec3i pos) { + return pos.getX() + ", " + pos.getY() + ", " + pos.getZ(); + } + + public static String toShortString(Position pos) { + return pos.x() + ", " + pos.y() + ", " + pos.z(); + } + + public static String logSide(Level level) { + if (level.isClientSide()) + return " (client)"; + return " (server)"; + } + + @Environment(EnvType.CLIENT) + public static void debugEventsClient() { + ClientChatEvent.CLIENT.register(message -> { + SINK.accept("Client chat sent: " + message); + return InteractionResultHolder.pass(message); + }); + ClientChatEvent.CLIENT_RECEIVED.register((type, message, sender) -> { + SINK.accept("Client chat received: " + message.getString()); + return InteractionResultHolder.pass(message); + }); + ClientLifecycleEvent.CLIENT_WORLD_LOAD.register(world -> { + SINK.accept("Client world loaded: " + world.dimension().location().toString()); + }); + ClientPlayerEvent.CLIENT_PLAYER_JOIN.register(player -> { + SINK.accept(player.getScoreboardName() + " joined (client)"); + }); + ClientPlayerEvent.CLIENT_PLAYER_QUIT.register(player -> { + SINK.accept(player.getScoreboardName() + " quit (client)"); + }); + ClientPlayerEvent.CLIENT_PLAYER_RESPAWN.register((oldPlayer, newPlayer) -> { + SINK.accept(newPlayer.getScoreboardName() + " respawned (client)"); + }); + GuiEvent.INIT_PRE.register((screen, widgets, children) -> { + SINK.accept(toSimpleName(screen) + " initializes"); + return InteractionResult.PASS; + }); + InteractionEvent.CLIENT_LEFT_CLICK_AIR.register((player, hand) -> { + SINK.accept(player.getScoreboardName() + " left clicks air" + logSide(player.level)); + }); + InteractionEvent.CLIENT_RIGHT_CLICK_AIR.register((player, hand) -> { + SINK.accept(player.getScoreboardName() + " right clicks air" + logSide(player.level)); + }); + RecipeUpdateEvent.EVENT.register(recipeManager -> { + SINK.accept("Client recipes received"); + }); + TextureStitchEvent.POST.register(atlas -> { + SINK.accept("Client texture stitched: " + atlas.location()); + }); + } + + private static String toSimpleName(Object o) { + return o.getClass().getSimpleName() + "@" + Integer.toHexString(o.hashCode()); + } +} diff --git a/common/src/test/java/me/shedaniel/architectury/test/client/ClientOverlayMessageSink.java b/common/src/test/java/me/shedaniel/architectury/test/client/ClientOverlayMessageSink.java new file mode 100644 index 00000000..0af96bcd --- /dev/null +++ b/common/src/test/java/me/shedaniel/architectury/test/client/ClientOverlayMessageSink.java @@ -0,0 +1,80 @@ +package me.shedaniel.architectury.test.client; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.architectury.event.events.GuiEvent; +import me.shedaniel.architectury.test.ConsoleMessageSink; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.util.Mth; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +@Environment(EnvType.CLIENT) +public class ClientOverlayMessageSink extends ConsoleMessageSink { + private final List messages = Collections.synchronizedList(Lists.newArrayList()); + + public ClientOverlayMessageSink() { + GuiEvent.RENDER_POST.register((screen, matrices, mouseX, mouseY, delta) -> render(matrices, delta)); + GuiEvent.RENDER_HUD.register((matrices, tickDelta) -> { + if (Minecraft.getInstance().screen == null && !Minecraft.getInstance().options.renderDebug) { + render(matrices, tickDelta); + } + }); + } + + @Override + public void accept(String message) { + super.accept(message); + messages.add(0, new Message(new TextComponent(message), Util.getMillis())); + } + + public void render(PoseStack matrices, float delta) { + Minecraft minecraft = Minecraft.getInstance(); + long currentMills = Util.getMillis(); + int lineHeight = minecraft.font.lineHeight; + + synchronized (messages) { + Iterator messageIterator = messages.iterator(); + int y = 1; + + RenderSystem.enableBlend(); + + while (messageIterator.hasNext()) { + Message message = messageIterator.next(); + int timeExisted = (int) (currentMills - message.created); + + if (timeExisted >= 5000) { + messageIterator.remove(); + } else { + int textWidth = minecraft.font.width(message.text); + int alpha = (int) Mth.clamp((5000 - timeExisted) / 5000f * 400f + 8, 0, 255); + GuiComponent.fill(matrices, 0, y - 1, 2 + textWidth + 1, y + lineHeight - 1, 0x505050 + ((alpha * 144 / 255) << 24)); + minecraft.font.draw(matrices, message.text, 1, y, 0xE0E0E0 + (alpha << 24)); + y += lineHeight; + } + } + } + + RenderSystem.disableAlphaTest(); + RenderSystem.disableBlend(); + } + + private static class Message { + private final Component text; + private final long created; + + public Message(Component text, long created) { + this.text = text; + this.created = created; + } + } +} diff --git a/common/src/test/resources/fabric.mod.json b/common/src/test/resources/fabric.mod.json new file mode 100644 index 00000000..04202eb8 --- /dev/null +++ b/common/src/test/resources/fabric.mod.json @@ -0,0 +1,17 @@ +{ + "schemaVersion": 1, + "id": "architectury-test", + "version": "${version}", + "name": "Architectury Test", + "description": "A intermediary api aimed to ease developing multiplatform mods.", + "authors": [ + "shedaniel" + ], + "license": "LGPL-3", + "environment": "*", + "entrypoints": { + "main": [ + "me.shedaniel.architectury.test.TestMod::initialize" + ] + } +} \ No newline at end of file diff --git a/fabric/build.gradle b/fabric/build.gradle index 99c065b6..83353a7a 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -40,6 +40,8 @@ dependencies { shadow(project(path: ":common", configuration: "transformed")) { transitive = false } + + testCompile project(":common").sourceSets.test.output } processResources {