aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.gradle4
-rw-r--r--settings.gradle12
-rw-r--r--spark-fabric/build.gradle55
-rw-r--r--spark-fabric/src/main/java/me/lucko/spark/fabric/FabricClientSparkPlugin.java104
-rw-r--r--spark-fabric/src/main/java/me/lucko/spark/fabric/FabricCommandSender.java94
-rw-r--r--spark-fabric/src/main/java/me/lucko/spark/fabric/FabricServerSparkPlugin.java84
-rw-r--r--spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkMod.java106
-rw-r--r--spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkPlugin.java89
-rw-r--r--spark-fabric/src/main/java/me/lucko/spark/fabric/FabricTickCounter.java72
-rw-r--r--spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/ClientPlayerEntityMixin.java49
-rw-r--r--spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftClientMixin.java51
-rw-r--r--spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftServerMixin.java52
-rw-r--r--spark-fabric/src/main/resources/assets/spark/icon.pngbin0 -> 2932 bytes
-rw-r--r--spark-fabric/src/main/resources/fabric.mod.json29
-rw-r--r--spark-fabric/src/main/resources/pack.mcmeta6
-rw-r--r--spark-fabric/src/main/resources/spark.mixins.json15
16 files changed, 822 insertions, 0 deletions
diff --git a/build.gradle b/build.gradle
index 831ed9b..76bbdca 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,10 @@
allprojects {
group = 'me.lucko'
version = '1.3-SNAPSHOT'
+
+ configurations {
+ compileClasspath // Fabric-loom needs this for remap jar for some reason
+ }
}
subprojects {
diff --git a/settings.gradle b/settings.gradle
index 908e607..4457134 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,3 +1,14 @@
+pluginManagement {
+ repositories {
+ jcenter()
+ maven {
+ name = 'Fabric'
+ url = 'https://maven.fabricmc.net/'
+ }
+ gradlePluginPortal()
+ }
+}
+
rootProject.name = 'spark'
include (
'spark-common',
@@ -6,5 +17,6 @@ include (
'spark-velocity',
'spark-sponge',
'spark-forge',
+ 'spark-fabric',
'spark-universal'
)
diff --git a/spark-fabric/build.gradle b/spark-fabric/build.gradle
new file mode 100644
index 0000000..ca0ce24
--- /dev/null
+++ b/spark-fabric/build.gradle
@@ -0,0 +1,55 @@
+plugins {
+ id 'fabric-loom' version '0.2.5-SNAPSHOT'
+ id 'com.github.johnrengelman.shadow' version '4.0.1'
+}
+
+configurations {
+ shade
+ compile.extendsFrom shade
+}
+
+dependencies {
+ minecraft "com.mojang:minecraft:19w34a"
+ mappings "net.fabricmc:yarn:19w34a+build.8"
+ modCompile "net.fabricmc:fabric-loader:0.4.9+build.161"
+
+ shade project(':spark-common')
+}
+
+processResources {
+ inputs.property "version", project.version
+
+ from(sourceSets.main.resources.srcDirs) {
+ include "fabric.mod.json"
+ expand "pluginVersion": project.pluginVersion, "pluginDescription": project.pluginDescription
+ }
+
+ from(sourceSets.main.resources.srcDirs) {
+ exclude "fabric.mod.json"
+ }
+}
+
+shadowJar {
+ archiveFileName = 'spark-fabric-dev.jar'
+ configurations = [project.configurations.shade]
+
+ relocate 'okio', 'me.lucko.spark.lib.okio'
+ relocate 'okhttp3', 'me.lucko.spark.lib.okhttp3'
+ relocate 'net.kyori.text', 'me.lucko.spark.lib.text'
+ relocate 'org.tukaani.xz', 'me.lucko.spark.lib.xz'
+ relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf'
+}
+
+task remappedShadowJar(type: net.fabricmc.loom.task.RemapJarTask) {
+ dependsOn tasks.shadowJar
+ input = tasks.shadowJar.archiveFile
+ addNestedDependencies = true
+ archiveFileName = 'spark-fabric.jar'
+}
+
+tasks.assemble.dependsOn tasks.remappedShadowJar
+
+artifacts {
+ archives remappedShadowJar
+ shadow shadowJar
+}
diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricClientSparkPlugin.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricClientSparkPlugin.java
new file mode 100644
index 0000000..1421779
--- /dev/null
+++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricClientSparkPlugin.java
@@ -0,0 +1,104 @@
+/*
+ * This file is part of spark.
+ *
+ * Copyright (c) lucko (Luck) <luck@lucko.me>
+ * Copyright (c) contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package me.lucko.spark.fabric;
+
+import com.mojang.brigadier.CommandDispatcher;
+import me.lucko.spark.common.sampler.TickCounter;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.network.ClientPlayNetworkHandler;
+import net.minecraft.client.network.ClientPlayerEntity;
+import net.minecraft.server.command.CommandSource;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+
+public class FabricClientSparkPlugin extends FabricSparkPlugin {
+
+ private final MinecraftClient minecraft;
+ private CommandDispatcher<CommandSource> dispatcher;
+
+ public FabricClientSparkPlugin(FabricSparkMod mod, MinecraftClient minecraft) {
+ super(mod);
+ this.minecraft = minecraft;
+ }
+
+ public static void register(FabricSparkMod mod, MinecraftClient client) {
+ FabricClientSparkPlugin plugin = new FabricClientSparkPlugin(mod, client);
+
+ plugin.scheduler.scheduleWithFixedDelay(plugin::checkCommandRegistered, 10, 10, TimeUnit.SECONDS);
+ }
+
+ private void checkCommandRegistered() {
+ ClientPlayerEntity player = this.minecraft.player;
+ if (player == null) {
+ return;
+ }
+
+ ClientPlayNetworkHandler connection = player.networkHandler;
+ if (connection == null) {
+ return;
+ }
+
+ try {
+ CommandDispatcher<CommandSource> dispatcher = connection.getCommandDispatcher();
+ if (dispatcher != this.dispatcher) {
+ this.dispatcher = dispatcher;
+ registerCommands(this.dispatcher, c -> 0, "sparkc", "sparkclient");
+ this.mod.setChatSendCallback(this::onClientChat);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private FabricCommandSender createClientSender() {
+ return new FabricCommandSender(this.minecraft.player.networkHandler.getCommandSource()::hasPermissionLevel, this.minecraft.player);
+ }
+
+ public boolean onClientChat(String chat) {
+ String[] split = chat.split(" ");
+ if (split.length == 0 || (!split[0].equals("/sparkc") && !split[0].equals("/sparkclient"))) {
+ return false;
+ }
+
+ String[] args = Arrays.copyOfRange(split, 1, split.length);
+ this.platform.executeCommand(createClientSender(), args);
+ this.minecraft.inGameHud.getChatHud().addToMessageHistory(chat);
+ return true;
+ }
+
+ @Override
+ public Stream<FabricCommandSender> getSendersWithPermission(String permission) {
+ return Stream.of(createClientSender());
+ }
+
+ @Override
+ public TickCounter createTickCounter() {
+ return new FabricTickCounter(FabricSparkMod.getInstance()::addClientCounter, FabricSparkMod.getInstance()::removeClientCounter);
+ }
+
+ @Override
+ public String getCommandName() {
+ return "sparkc";
+ }
+
+}
diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricCommandSender.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricCommandSender.java
new file mode 100644
index 0000000..3a8d128
--- /dev/null
+++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricCommandSender.java
@@ -0,0 +1,94 @@
+/*
+ * This file is part of spark.
+ *
+ * Copyright (c) lucko (Luck) <luck@lucko.me>
+ * Copyright (c) contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package me.lucko.spark.fabric;
+
+import me.lucko.spark.common.CommandSender;
+import net.kyori.text.Component;
+import net.kyori.text.serializer.gson.GsonComponentSerializer;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.server.command.CommandOutput;
+import net.minecraft.server.dedicated.DedicatedServer;
+import net.minecraft.text.Text;
+
+import java.util.UUID;
+
+public class FabricCommandSender implements CommandSender {
+
+ private final VanillaPermission permission;
+ private final CommandOutput sender;
+
+ public FabricCommandSender(VanillaPermission permission, CommandOutput sender) {
+ this.permission = permission;
+ this.sender = sender;
+ }
+
+ @Override
+ public String getName() {
+ if (this.sender instanceof PlayerEntity) {
+ return ((PlayerEntity) this.sender).getGameProfile().getName();
+ } else if (this.sender instanceof DedicatedServer) {
+ return "Console";
+ } else {
+ return "unknown:" + this.sender.getClass().getSimpleName();
+ }
+ }
+
+ @Override
+ public UUID getUniqueId() {
+ if (this.sender instanceof PlayerEntity) {
+ return ((PlayerEntity) this.sender).getUuid();
+ }
+ return null;
+ }
+
+ @Override
+ public void sendMessage(Component message) {
+ Text component = Text.Serializer.fromJson(GsonComponentSerializer.INSTANCE.serialize(message));
+ this.sender.sendMessage(component);
+ }
+
+ @Override
+ public boolean hasPermission(String permission) {
+ return this.permission.hasPermissionLevel(4); // Require /stop access, reasonable
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ FabricCommandSender that = (FabricCommandSender) o;
+ return this.sender.equals(that.sender);
+ }
+
+ @Override
+ public int hashCode() {
+ return this.sender.hashCode();
+ }
+
+ public interface VanillaPermission {
+
+ boolean hasPermissionLevel(int level);
+ }
+}
diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricServerSparkPlugin.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricServerSparkPlugin.java
new file mode 100644
index 0000000..01bc442
--- /dev/null
+++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricServerSparkPlugin.java
@@ -0,0 +1,84 @@
+/*
+ * This file is part of spark.
+ *
+ * Copyright (c) lucko (Luck) <luck@lucko.me>
+ * Copyright (c) contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package me.lucko.spark.fabric;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import me.lucko.spark.common.sampler.TickCounter;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.command.ServerCommandSource;
+import net.minecraft.text.LiteralText;
+
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+public class FabricServerSparkPlugin extends FabricSparkPlugin implements Command<ServerCommandSource> {
+
+ private final MinecraftServer server;
+
+ public FabricServerSparkPlugin(FabricSparkMod mod, MinecraftServer server) {
+ super(mod);
+ this.server = server;
+ }
+
+ public static void register(FabricSparkMod mod, MinecraftServer server) {
+ CommandDispatcher<ServerCommandSource> dispatcher = server.getCommandManager().getDispatcher();
+
+ FabricServerSparkPlugin plugin = new FabricServerSparkPlugin(mod, server);
+ registerCommands(dispatcher, plugin, "spark");
+ // PermissionAPI.registerNode("spark", DefaultPermissionLevel.OP, "Access to the spark command");
+ }
+
+ @Override
+ public int run(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
+ String[] split = context.getInput().split(" ");
+ if (split.length == 0 || !split[0].equals("/spark")) {
+ context.getSource().sendError(new LiteralText("Wrong split started with " + (split.length == 0 ? "nothing" : split[0])));
+ return 0;
+ }
+
+ String[] args = Arrays.copyOfRange(split, 1, split.length);
+
+ this.platform.executeCommand(new FabricCommandSender(context.getSource()::hasPermissionLevel, context.getSource().getPlayer()), args);
+ return 1;
+ }
+
+ @Override
+ public Stream<FabricCommandSender> getSendersWithPermission(String permission) {
+ return Stream.concat(
+ this.server.getPlayerManager().getPlayerList().stream()
+ .filter(player -> this.server.getPermissionLevel(player.getGameProfile()) == 4),
+ Stream.of(this.server)
+ ).map(sender -> new FabricCommandSender(i -> true, sender));
+ }
+
+ @Override
+ public TickCounter createTickCounter() {
+ return new FabricTickCounter(FabricSparkMod.getInstance()::addServerCounter, FabricSparkMod.getInstance()::removeServerCounter);
+ }
+
+ @Override
+ public String getCommandName() {
+ return "spark";
+ }
+}
diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkMod.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkMod.java
new file mode 100644
index 0000000..4e4468b
--- /dev/null
+++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkMod.java
@@ -0,0 +1,106 @@
+/*
+ * This file is part of spark.
+ *
+ * Copyright (c) lucko (Luck) <luck@lucko.me>
+ * Copyright (c) contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package me.lucko.spark.fabric;
+
+import net.fabricmc.api.ModInitializer;
+import net.fabricmc.loader.api.FabricLoader;
+
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Predicate;
+
+public class FabricSparkMod implements ModInitializer {
+
+ private static FabricSparkMod instance;
+ private final Set<FabricTickCounter> clientCounters = new HashSet<>();
+ private final Set<FabricTickCounter> serverCounters = new HashSet<>();
+ private String version;
+ private Path configDir;
+ // Use events from Fabric API later
+ // Return true to abort sending to server
+ private Predicate<String> chatSendCallback = s -> false;
+
+ public FabricSparkMod() {
+ }
+
+ public static FabricSparkMod getInstance() {
+ return instance;
+ }
+
+ @Override
+ public void onInitialize() {
+ FabricSparkMod.instance = this;
+ FabricLoader loader = FabricLoader.getInstance();
+ this.version = loader.getModContainer("spark")
+ .orElseThrow(() -> new IllegalStateException("Spark loaded incorrectly!"))
+ .getMetadata()
+ .getVersion()
+ .getFriendlyString();
+ this.configDir = loader.getConfigDirectory().toPath().resolve("spark");
+
+ // When Fabric API is available, we will register event listeners here
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public Path getConfigDirectory() {
+ return configDir;
+ }
+
+ public void setChatSendCallback(Predicate<String> callback) {
+ this.chatSendCallback = callback;
+ }
+
+ public boolean tryProcessChat(String message) {
+ return chatSendCallback.test(message);
+ }
+
+ public void addClientCounter(FabricTickCounter counter) {
+ this.clientCounters.add(counter);
+ }
+
+ public void removeClientCounter(FabricTickCounter counter) {
+ this.clientCounters.remove(counter);
+ }
+
+ public void addServerCounter(FabricTickCounter counter) {
+ this.serverCounters.add(counter);
+ }
+
+ public void removeServerCounter(FabricTickCounter counter) {
+ this.serverCounters.remove(counter);
+ }
+
+ public void tickClientCounters() {
+ for (FabricTickCounter each : clientCounters) {
+ each.onTick();
+ }
+ }
+
+ public void tickServerCounters() {
+ for (FabricTickCounter each : serverCounters) {
+ each.onTick();
+ }
+ }
+}
diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkPlugin.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkPlugin.java
new file mode 100644
index 0000000..a0f6cf0
--- /dev/null
+++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkPlugin.java
@@ -0,0 +1,89 @@
+/*
+ * This file is part of spark.
+ *
+ * Copyright (c) lucko (Luck) <luck@lucko.me>
+ * Copyright (c) contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package me.lucko.spark.fabric;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.tree.LiteralCommandNode;
+import me.lucko.spark.common.SparkPlatform;
+import me.lucko.spark.common.SparkPlugin;
+import me.lucko.spark.common.sampler.ThreadDumper;
+
+import java.nio.file.Path;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+public abstract class FabricSparkPlugin implements SparkPlugin {
+
+ protected final ScheduledExecutorService scheduler;
+ protected final SparkPlatform platform;
+ protected final FabricSparkMod mod;
+
+ protected FabricSparkPlugin(FabricSparkMod mod) {
+ this.mod = mod;
+ this.scheduler = Executors.newSingleThreadScheduledExecutor(
+ new ThreadFactoryBuilder().setNameFormat("spark-fabric-async-worker").build()
+ );
+ this.platform = new SparkPlatform(this);
+ this.platform.enable();
+ }
+
+ public static <T> void registerCommands(CommandDispatcher<T> dispatcher, Command<T> executor, String... aliases) {
+ if (aliases.length == 0) {
+ return;
+ }
+ String mainName = aliases[0];
+ LiteralArgumentBuilder<T> command = LiteralArgumentBuilder.<T>literal(mainName)
+ .executes(executor)
+ .then(RequiredArgumentBuilder.<T, String>argument("args", StringArgumentType.greedyString())
+ .executes(executor)
+ );
+
+ LiteralCommandNode<T> node = dispatcher.register(command);
+ for (int i = 1; i < aliases.length; i++) {
+ dispatcher.register(LiteralArgumentBuilder.<T>literal(aliases[i]).redirect(node));
+ }
+ }
+
+ @Override
+ public String getVersion() {
+ return this.mod.getVersion();
+ }
+
+ @Override
+ public Path getPluginDirectory() {
+ return this.mod.getConfigDirectory();
+ }
+
+ @Override
+ public void executeAsync(Runnable task) {
+ this.scheduler.execute(task);
+ }
+
+ @Override
+ public ThreadDumper getDefaultThreadDumper() {
+ return new ThreadDumper.Specific(new long[]{Thread.currentThread().getId()});
+ }
+}
diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricTickCounter.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricTickCounter.java
new file mode 100644
index 0000000..03d00b2
--- /dev/null
+++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricTickCounter.java
@@ -0,0 +1,72 @@
+/*
+ * This file is part of spark.
+ *
+ * Copyright (c) lucko (Luck) <luck@lucko.me>
+ * Copyright (c) contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package me.lucko.spark.fabric;
+
+import me.lucko.spark.common.sampler.TickCounter;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Consumer;
+
+public class FabricTickCounter implements TickCounter {
+
+ private final Set<TickTask> tasks = new HashSet<>();
+ private final Consumer<FabricTickCounter> adder;
+ private final Consumer<FabricTickCounter> remover;
+ private int tick = 0;
+
+ public FabricTickCounter(Consumer<FabricTickCounter> adder, Consumer<FabricTickCounter> remover) {
+ this.adder = adder;
+ this.remover = remover;
+ }
+
+ public void onTick() {
+ for (TickTask r : this.tasks) {
+ r.onTick(this);
+ }
+ this.tick++;
+ }
+
+ @Override
+ public void start() {
+ this.adder.accept(this);
+ }
+
+ @Override
+ public void close() {
+ this.remover.accept(this);
+ }
+
+ @Override
+ public int getCurrentTick() {
+ return this.tick;
+ }
+
+ @Override
+ public void addTickTask(TickTask runnable) {
+ this.tasks.add(runnable);
+ }
+
+ @Override
+ public void removeTickTask(TickTask runnable) {
+ this.tasks.remove(runnable);
+ }
+}
diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/ClientPlayerEntityMixin.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/ClientPlayerEntityMixin.java
new file mode 100644
index 0000000..3ce57b1
--- /dev/null
+++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/ClientPlayerEntityMixin.java
@@ -0,0 +1,49 @@
+/*
+ * This file is part of spark.
+ *
+ * Copyright (c) lucko (Luck) <luck@lucko.me>
+ * Copyright (c) contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package me.lucko.spark.fabric.mixin;
+
+import com.mojang.authlib.GameProfile;
+import me.lucko.spark.fabric.FabricSparkMod;
+import net.minecraft.client.network.AbstractClientPlayerEntity;
+import net.minecraft.client.network.ClientPlayerEntity;
+import net.minecraft.client.world.ClientWorld;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+
+@Mixin(ClientPlayerEntity.class)
+public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity {
+
+ public ClientPlayerEntityMixin(ClientWorld clientWorld_1, GameProfile gameProfile_1) {
+ super(clientWorld_1, gameProfile_1);
+ }
+
+ @Inject(method = "sendChatMessage(Ljava/lang/String;)V", at = @At("HEAD"),
+ locals = LocalCapture.CAPTURE_FAILHARD,
+ cancellable = true)
+ public void onSendChatMessage(String message, CallbackInfo ci) {
+ if (FabricSparkMod.getInstance().tryProcessChat(message)) {
+ ci.cancel();
+ }
+ }
+}
diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftClientMixin.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftClientMixin.java
new file mode 100644
index 0000000..b987ca6
--- /dev/null
+++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftClientMixin.java
@@ -0,0 +1,51 @@
+/*
+ * This file is part of spark.
+ *
+ * Copyright (c) lucko (Luck) <luck@lucko.me>
+ * Copyright (c) contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package me.lucko.spark.fabric.mixin;
+
+import me.lucko.spark.fabric.FabricClientSparkPlugin;
+import me.lucko.spark.fabric.FabricSparkMod;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.util.NonBlockingThreadExecutor;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(MinecraftClient.class)
+public abstract class MinecraftClientMixin extends NonBlockingThreadExecutor<Runnable> {
+
+ public MinecraftClientMixin(String string_1) {
+ super(string_1);
+ }
+
+ // Inject at when menu pops up
+ @Inject(method = "init()V", at = @At(value = "INVOKE",
+ target = "Lnet/minecraft/client/gui/screen/SplashScreen;method_18819(Lnet/minecraft/client/MinecraftClient;)V"))
+ public void onInit(CallbackInfo ci) {
+ FabricClientSparkPlugin.register(FabricSparkMod.getInstance(), (MinecraftClient) (Object) this);
+ }
+
+ @Inject(method = "tick()V", at = @At("RETURN"))
+ public void onTick(CallbackInfo ci) {
+ FabricSparkMod.getInstance().tickClientCounters();
+ }
+
+}
diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftServerMixin.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftServerMixin.java
new file mode 100644
index 0000000..bb14b64
--- /dev/null
+++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftServerMixin.java
@@ -0,0 +1,52 @@
+/*
+ * This file is part of spark.
+ *
+ * Copyright (c) lucko (Luck) <luck@lucko.me>
+ * Copyright (c) contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package me.lucko.spark.fabric.mixin;
+
+import me.lucko.spark.fabric.FabricServerSparkPlugin;
+import me.lucko.spark.fabric.FabricSparkMod;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.ServerTask;
+import net.minecraft.util.NonBlockingThreadExecutor;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(MinecraftServer.class)
+public abstract class MinecraftServerMixin extends NonBlockingThreadExecutor<ServerTask> {
+
+ public MinecraftServerMixin(String string_1) {
+ super(string_1);
+ }
+
+ // Inject before set favicon call
+ @Inject(method = "run()V",
+ at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;setFavicon(Lnet/minecraft/server/ServerMetadata;)V"))
+ public void onRun(CallbackInfo ci) {
+ FabricServerSparkPlugin.register(FabricSparkMod.getInstance(), (MinecraftServer) (Object) this);
+ }
+
+ @Inject(method = "tick(Ljava/util/function/BooleanSupplier;)V", at = @At("RETURN"))
+ public void onTick(CallbackInfo ci) {
+ FabricSparkMod.getInstance().tickServerCounters();
+ }
+
+}
diff --git a/spark-fabric/src/main/resources/assets/spark/icon.png b/spark-fabric/src/main/resources/assets/spark/icon.png
new file mode 100644
index 0000000..fef8f70
--- /dev/null
+++ b/spark-fabric/src/main/resources/assets/spark/icon.png
Binary files differ
diff --git a/spark-fabric/src/main/resources/fabric.mod.json b/spark-fabric/src/main/resources/fabric.mod.json
new file mode 100644
index 0000000..13a352d
--- /dev/null
+++ b/spark-fabric/src/main/resources/fabric.mod.json
@@ -0,0 +1,29 @@
+{
+ "schemaVersion": 1,
+ "id": "spark",
+ "version": "${pluginVersion}",
+ "name": "Spark",
+ "icon": "assets/spark/icon.png",
+ "description": "${pluginDescription}",
+ "authors": [
+ "Lucko"
+ ],
+ "contact": {
+ "homepage": "https://sparkprofiler.github.io/",
+ "sources": "https://github.com/lucko/spark",
+ "issues": "https://github.com/lucko/spark/issues"
+ },
+ "license": "GNU General Public License v3.0",
+ "environment": "*",
+ "entrypoints": {
+ "main": [
+ "me.lucko.spark.fabric.FabricSparkMod"
+ ]
+ },
+ "mixins": [
+ "spark.mixins.json"
+ ],
+ "depends": {
+ "fabricloader": ">=0.4.0"
+ }
+}
diff --git a/spark-fabric/src/main/resources/pack.mcmeta b/spark-fabric/src/main/resources/pack.mcmeta
new file mode 100644
index 0000000..e6c4c25
--- /dev/null
+++ b/spark-fabric/src/main/resources/pack.mcmeta
@@ -0,0 +1,6 @@
+{
+ "pack": {
+ "description": "spark resources",
+ "pack_format": 4
+ }
+}
diff --git a/spark-fabric/src/main/resources/spark.mixins.json b/spark-fabric/src/main/resources/spark.mixins.json
new file mode 100644
index 0000000..bde03fb
--- /dev/null
+++ b/spark-fabric/src/main/resources/spark.mixins.json
@@ -0,0 +1,15 @@
+{
+ "required": true,
+ "package": "me.lucko.spark.fabric.mixin",
+ "compatibilityLevel": "JAVA_8",
+ "mixins": [
+ "MinecraftServerMixin"
+ ],
+ "client": [
+ "MinecraftClientMixin",
+ "ClientPlayerEntityMixin"
+ ],
+ "injectors": {
+ "defaultRequire": 1
+ }
+}