aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2025-02-28 14:17:45 +0100
committerLinnea Gräf <nea@nea.moe>2025-02-28 14:37:10 +0100
commit3738efb56b920d29918aceb42c30698884389caf (patch)
tree3800c10d7abcfb42c687bfc8e9a61ffff3590d3e
parentcccd48323b9987274a14bd2cbc9e009b0ed8e407 (diff)
downloadspark-3738efb56b920d29918aceb42c30698884389caf.tar.gz
spark-3738efb56b920d29918aceb42c30698884389caf.tar.bz2
spark-3738efb56b920d29918aceb42c30698884389caf.zip
-rw-r--r--settings.gradle4
-rw-r--r--spark-forge/build.gradle44
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/ForgeClassSourceLookup.java26
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/ForgeClientCommandSender.java69
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/ForgeClientTickHook.java50
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/ForgeClientTickReporter.java (renamed from spark-forge/src/main/java/me/lucko/spark/forge/ForgeTickReporter.java)62
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/ForgePlatformInfo.java15
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/ForgePlayerPingProvider.java30
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/ForgeServerCommandSender.java90
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/ForgeServerTickHook.java (renamed from spark-forge/src/main/java/me/lucko/spark/forge/ForgeTickHook.java)17
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/ForgeServerTickReporter.java54
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/ForgeSparkMod.java64
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/ForgeWorldInfoProvider.java323
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/SidedExecutor.java41
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeClientSparkPlugin.java188
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeServerSparkPlugin.java322
-rw-r--r--spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeSparkPlugin.java254
-rw-r--r--spark-forge/src/main/resources/mcmod.info8
18 files changed, 803 insertions, 858 deletions
diff --git a/settings.gradle b/settings.gradle
index d689d80..7822e61 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -13,6 +13,10 @@ pluginManagement {
name = 'NeoForge'
url = 'https://maven.neoforged.net/releases'
}
+ maven {
+ name = "WagYourMaven"
+ url = "https://maven.wagyourtail.xyz/releases"
+ }
}
}
diff --git a/spark-forge/build.gradle b/spark-forge/build.gradle
index 6ab62da..a939d6c 100644
--- a/spark-forge/build.gradle
+++ b/spark-forge/build.gradle
@@ -1,17 +1,22 @@
plugins {
id 'com.gradleup.shadow' version '8.3.0'
- id 'net.minecraftforge.gradle' version '[6.0.24,6.2)'
+ id "xyz.wagyourtail.unimined" version "1.2.14"
}
tasks.withType(JavaCompile) {
- // override, compile targeting J21
- options.release = 21
+ // override, compile targeting J8
+ options.release = 8
}
-minecraft {
- mappings channel: 'official', version: '1.21.4'
- accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
- reobf = false
+unimined.minecraft {
+ version "1.8.9"
+ mappings {
+ searge()
+ mcp "stable", "22-1.8.9"
+ }
+ minecraftForge {
+ loader "11.15.1.2318-1.8.9"
+ }
}
configurations {
@@ -20,26 +25,19 @@ configurations {
}
dependencies {
- minecraft 'net.minecraftforge:forge:1.21.4-54.0.6'
shade project(':spark-common')
}
processResources {
- from(sourceSets.main.resources.srcDirs) {
- include 'META-INF/mods.toml'
- expand (
- 'pluginVersion': project.pluginVersion,
- 'pluginDescription': project.pluginDescription
- )
- }
-
- from(sourceSets.main.resources.srcDirs) {
- exclude 'META-INF/mods.toml'
+ inputs.property 'pluginVersion', project.pluginVersion
+ inputs.property 'pluginDescription', project.pluginDescription
+ filesMatching("mcmod.info") {
+ expand(inputs.properties)
}
}
shadowJar {
- archiveFileName = "spark-${project.pluginVersion}-forge.jar"
+ archiveFileName = "spark-${project.pluginVersion}-legacy-forge-1.8.9-dev.jar"
configurations = [project.configurations.shade]
relocate 'net.kyori.adventure', 'me.lucko.spark.lib.adventure'
@@ -55,7 +53,13 @@ shadowJar {
project.applyExcludes(delegate)
}
+remapJar {
+ inputFile = tasks.shadowJar.archiveFile
+ dependsOn tasks.shadowJar
+ archiveFileName = "spark-${project.pluginVersion}-legacy-forge-1.8.9.jar"
+}
+
artifacts {
- archives shadowJar
+ archives remapJar
shadow shadowJar
}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClassSourceLookup.java b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClassSourceLookup.java
index 1f7d90d..264cd40 100644
--- a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClassSourceLookup.java
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClassSourceLookup.java
@@ -20,17 +20,31 @@
package me.lucko.spark.forge;
-import cpw.mods.modlauncher.TransformingClassLoader;
import me.lucko.spark.common.sampler.source.ClassSourceLookup;
+import net.minecraftforge.fml.common.Loader;
+import net.minecraftforge.fml.common.ModContainer;
+
+import java.util.HashMap;
+import java.util.Map;
public class ForgeClassSourceLookup implements ClassSourceLookup {
+ Map<String, ModContainer> packageLUT = new HashMap<>();
+
+ public ForgeClassSourceLookup() {
+ for (ModContainer modContainer : Loader.instance().getModList()) {
+ for (String ownedPackage : modContainer.getOwnedPackages()) {
+ packageLUT.put(ownedPackage, modContainer);
+ }
+ }
+ }
+
@Override
public String identify(Class<?> clazz) {
- if (clazz.getClassLoader() instanceof TransformingClassLoader) {
- String name = clazz.getModule().getName();
- return name.equals("forge") || name.equals("minecraft") ? null : name;
- }
- return null;
+ ModContainer modContainer = packageLUT.get(clazz.getPackage().getName());
+ String modId = modContainer != null ? modContainer.getModId() : null;
+ if ("forge".equals(modId) || "minecraft".equals(modId) || "fml".equals(modId))
+ return null;
+ return modId;
}
}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClientCommandSender.java b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClientCommandSender.java
index 5416370..f54a111 100644
--- a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClientCommandSender.java
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClientCommandSender.java
@@ -23,49 +23,34 @@ package me.lucko.spark.forge;
import me.lucko.spark.common.command.sender.AbstractCommandSender;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
-import net.minecraft.client.player.LocalPlayer;
-import net.minecraft.commands.CommandSourceStack;
-import net.minecraft.core.RegistryAccess;
-import net.minecraft.network.chat.Component.Serializer;
-import net.minecraft.network.chat.MutableComponent;
-import net.minecraft.world.entity.Entity;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.util.IChatComponent;
-import java.util.Objects;
import java.util.UUID;
-public class ForgeClientCommandSender extends AbstractCommandSender<CommandSourceStack> {
- public ForgeClientCommandSender(CommandSourceStack source) {
- super(source);
- }
-
- @Override
- public String getName() {
- return this.delegate.getTextName();
- }
-
- @Override
- public UUID getUniqueId() {
- Entity entity = this.delegate.getEntity();
- if (entity instanceof LocalPlayer player) {
- return player.getUUID();
- }
- return null;
- }
-
- @Override
- public void sendMessage(Component message) {
- MutableComponent component = Serializer.fromJson(GsonComponentSerializer.gson().serializeToTree(message), RegistryAccess.EMPTY);
- Objects.requireNonNull(component, "component");
- super.delegate.sendSystemMessage(component);
- }
-
- @Override
- public boolean hasPermission(String permission) {
- return true;
- }
-
- @Override
- protected Object getObjectForComparison() {
- return this.delegate.getEntity();
- }
+public class ForgeClientCommandSender extends AbstractCommandSender<EntityPlayerSP> {
+ public ForgeClientCommandSender(EntityPlayerSP source) {
+ super(source);
+ }
+
+ @Override
+ public String getName() {
+ return delegate.getName();
+ }
+
+ @Override
+ public UUID getUniqueId() {
+ return delegate.getUniqueID();
+ }
+
+ @Override
+ public void sendMessage(Component message) {
+ IChatComponent component = IChatComponent.Serializer.jsonToComponent(GsonComponentSerializer.gson().serialize(message));
+ delegate.addChatMessage(component);
+ }
+
+ @Override
+ public boolean hasPermission(String permission) {
+ return true;
+ }
}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClientTickHook.java b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClientTickHook.java
new file mode 100644
index 0000000..dba0b94
--- /dev/null
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClientTickHook.java
@@ -0,0 +1,50 @@
+/*
+ * 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.forge;
+
+import me.lucko.spark.common.tick.AbstractTickHook;
+import me.lucko.spark.common.tick.TickHook;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+public class ForgeClientTickHook extends AbstractTickHook implements TickHook {
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent e) {
+ if (e.phase != TickEvent.Phase.START) {
+ return;
+ }
+
+ onTick();
+ }
+
+ @Override
+ public void start() {
+ MinecraftForge.EVENT_BUS.register(this);
+ }
+
+ @Override
+ public void close() {
+ MinecraftForge.EVENT_BUS.unregister(this);
+ }
+
+}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeTickReporter.java b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClientTickReporter.java
index 06d0f3e..cce9a40 100644
--- a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeTickReporter.java
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeClientTickReporter.java
@@ -20,41 +20,37 @@
package me.lucko.spark.forge;
+
import me.lucko.spark.common.tick.SimpleTickReporter;
import me.lucko.spark.common.tick.TickReporter;
import net.minecraftforge.common.MinecraftForge;
-import net.minecraftforge.event.TickEvent;
-import net.minecraftforge.eventbus.api.SubscribeEvent;
-
-public class ForgeTickReporter extends SimpleTickReporter implements TickReporter {
- private final TickEvent.Type type;
-
- public ForgeTickReporter(TickEvent.Type type) {
- this.type = type;
- }
-
- @SubscribeEvent
- public void onTick(TickEvent e) {
- if (e.type != this.type) {
- return;
- }
-
- switch (e.phase) {
- case START -> onStart();
- case END -> onEnd();
- default -> throw new AssertionError(e.phase);
- }
- }
-
- @Override
- public void start() {
- MinecraftForge.EVENT_BUS.register(this);
- }
-
- @Override
- public void close() {
- MinecraftForge.EVENT_BUS.unregister(this);
- super.close();
- }
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+public class ForgeClientTickReporter extends SimpleTickReporter implements TickReporter {
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent e) {
+
+ switch (e.phase) {
+ case START:
+ onStart();
+ break;
+ case END:
+ onEnd();
+ break;
+ }
+ }
+
+ @Override
+ public void start() {
+ MinecraftForge.EVENT_BUS.register(this);
+ }
+
+ @Override
+ public void close() {
+ MinecraftForge.EVENT_BUS.unregister(this);
+ super.close();
+ }
}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/ForgePlatformInfo.java b/spark-forge/src/main/java/me/lucko/spark/forge/ForgePlatformInfo.java
index ede1996..b1906c1 100644
--- a/spark-forge/src/main/java/me/lucko/spark/forge/ForgePlatformInfo.java
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/ForgePlatformInfo.java
@@ -21,11 +21,9 @@
package me.lucko.spark.forge;
import me.lucko.spark.common.platform.PlatformInfo;
-import net.minecraftforge.fml.ModContainer;
-import net.minecraftforge.fml.ModList;
-import net.minecraftforge.forgespi.language.IModInfo;
-import net.minecraftforge.versions.forge.ForgeVersion;
-import net.minecraftforge.versions.mcp.MCPVersion;
+import net.minecraftforge.common.ForgeVersion;
+import net.minecraftforge.fml.common.FMLCommonHandler;
+import net.minecraftforge.fml.common.Loader;
public class ForgePlatformInfo implements PlatformInfo {
private final Type type;
@@ -46,10 +44,7 @@ public class ForgePlatformInfo implements PlatformInfo {
@Override
public String getBrand() {
- return ModList.get().getModContainerById(ForgeVersion.MOD_ID)
- .map(ModContainer::getModInfo)
- .map(IModInfo::getDisplayName)
- .orElse("Forge");
+ return FMLCommonHandler.instance().getModName();
}
@Override
@@ -59,6 +54,6 @@ public class ForgePlatformInfo implements PlatformInfo {
@Override
public String getMinecraftVersion() {
- return MCPVersion.getMCVersion();
+ return Loader.instance().getMinecraftModContainer().getVersion();
}
}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/ForgePlayerPingProvider.java b/spark-forge/src/main/java/me/lucko/spark/forge/ForgePlayerPingProvider.java
index 8b96b65..7b7795a 100644
--- a/spark-forge/src/main/java/me/lucko/spark/forge/ForgePlayerPingProvider.java
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/ForgePlayerPingProvider.java
@@ -22,24 +22,28 @@ package me.lucko.spark.forge;
import com.google.common.collect.ImmutableMap;
import me.lucko.spark.common.monitor.ping.PlayerPingProvider;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.WorldServer;
import java.util.Map;
public class ForgePlayerPingProvider implements PlayerPingProvider {
- private final MinecraftServer server;
+ private final MinecraftServer server;
- public ForgePlayerPingProvider(MinecraftServer server) {
- this.server = server;
- }
+ public ForgePlayerPingProvider(MinecraftServer server) {
+ this.server = server;
+ }
- @Override
- public Map<String, Integer> poll() {
- ImmutableMap.Builder<String, Integer> builder = ImmutableMap.builder();
- for (ServerPlayer player : this.server.getPlayerList().getPlayers()) {
- builder.put(player.getGameProfile().getName(), player.connection.latency());
- }
- return builder.build();
- }
+ @Override
+ public Map<String, Integer> poll() {
+ ImmutableMap.Builder<String, Integer> builder = ImmutableMap.builder();
+ for (WorldServer world : this.server.worldServers) {
+ for (EntityPlayer player : world.playerEntities) {
+ builder.put(player.getGameProfile().getName(), ((EntityPlayerMP) player).ping);
+ }
+ }
+ return builder.build();
+ }
}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeServerCommandSender.java b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeServerCommandSender.java
index 6951d9a..e825dce 100644
--- a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeServerCommandSender.java
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeServerCommandSender.java
@@ -21,63 +21,57 @@
package me.lucko.spark.forge;
import me.lucko.spark.common.command.sender.AbstractCommandSender;
-import me.lucko.spark.forge.plugin.ForgeServerSparkPlugin;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
-import net.minecraft.commands.CommandSourceStack;
-import net.minecraft.core.RegistryAccess;
-import net.minecraft.network.chat.Component.Serializer;
-import net.minecraft.network.chat.MutableComponent;
-import net.minecraft.world.entity.Entity;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.Entity;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.IChatComponent;
-import java.util.Objects;
import java.util.UUID;
-public class ForgeServerCommandSender extends AbstractCommandSender<CommandSourceStack> {
- private final ForgeServerSparkPlugin plugin;
+public class ForgeServerCommandSender extends AbstractCommandSender<ICommandSender> {
- public ForgeServerCommandSender(CommandSourceStack commandSource, ForgeServerSparkPlugin plugin) {
- super(commandSource);
- this.plugin = plugin;
- }
+ public ForgeServerCommandSender(ICommandSender commandSource) {
+ super(commandSource);
+ }
- @Override
- public String getName() {
- String name = this.delegate.getTextName();
- if (this.delegate.getEntity() != null && name.equals("Server")) {
- return "Console";
- }
- return name;
- }
+ @Override
+ public String getName() {
+ String name = this.delegate.getName();
+ if (delegate instanceof MinecraftServer) {
+ return "Console";
+ }
+ return name;
+ }
- @Override
- public UUID getUniqueId() {
- Entity entity = this.delegate.getEntity();
- return entity != null ? entity.getUUID() : null;
- }
+ @Override
+ public UUID getUniqueId() {
+ Entity entity = this.delegate.getCommandSenderEntity();
+ return entity != null ? entity.getUniqueID() : null;
+ }
- @Override
- public void sendMessage(Component message) {
- MutableComponent component = Serializer.fromJson(GsonComponentSerializer.gson().serializeToTree(message), RegistryAccess.EMPTY);
- Objects.requireNonNull(component, "component");
- super.delegate.sendSystemMessage(component);
- }
+ @Override
+ public void sendMessage(Component message) {
+ IChatComponent component = IChatComponent.Serializer.jsonToComponent(GsonComponentSerializer.gson().serialize(message));
+ delegate.addChatMessage(component);
+ }
- @Override
- public boolean hasPermission(String permission) {
- return this.plugin.hasPermission(this.delegate, permission);
- }
+ @Override
+ public boolean hasPermission(String permission) {
+ return this.delegate.canCommandSenderUseCommand(3, permission);
+ }
- @Override
- protected Object getObjectForComparison() {
- UUID uniqueId = getUniqueId();
- if (uniqueId != null) {
- return uniqueId;
- }
- Entity entity = this.delegate.getEntity();
- if (entity != null) {
- return entity;
- }
- return getName();
- }
+ @Override
+ protected Object getObjectForComparison() {
+ UUID uniqueId = getUniqueId();
+ if (uniqueId != null) {
+ return uniqueId;
+ }
+ Entity entity = this.delegate.getCommandSenderEntity();
+ if (entity != null) {
+ return entity;
+ }
+ return getName();
+ }
}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeTickHook.java b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeServerTickHook.java
index 84de970..bd750fa 100644
--- a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeTickHook.java
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeServerTickHook.java
@@ -23,26 +23,17 @@ package me.lucko.spark.forge;
import me.lucko.spark.common.tick.AbstractTickHook;
import me.lucko.spark.common.tick.TickHook;
import net.minecraftforge.common.MinecraftForge;
-import net.minecraftforge.event.TickEvent;
-import net.minecraftforge.eventbus.api.SubscribeEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
-public class ForgeTickHook extends AbstractTickHook implements TickHook {
- private final TickEvent.Type type;
-
- public ForgeTickHook(TickEvent.Type type) {
- this.type = type;
- }
+public class ForgeServerTickHook extends AbstractTickHook implements TickHook {
@SubscribeEvent
- public void onTick(TickEvent e) {
+ public void onTick(TickEvent.ServerTickEvent e) {
if (e.phase != TickEvent.Phase.START) {
return;
}
- if (e.type != this.type) {
- return;
- }
-
onTick();
}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeServerTickReporter.java b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeServerTickReporter.java
new file mode 100644
index 0000000..292f0b1
--- /dev/null
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeServerTickReporter.java
@@ -0,0 +1,54 @@
+/*
+ * 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.forge;
+
+import me.lucko.spark.common.tick.SimpleTickReporter;
+import me.lucko.spark.common.tick.TickReporter;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+public class ForgeServerTickReporter extends SimpleTickReporter implements TickReporter {
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ServerTickEvent e) {
+ switch (e.phase) {
+ case START:
+ onStart();
+ break;
+ case END:
+ onEnd();
+ break;
+ }
+ }
+
+ @Override
+ public void start() {
+ MinecraftForge.EVENT_BUS.register(this);
+ }
+
+ @Override
+ public void close() {
+ MinecraftForge.EVENT_BUS.unregister(this);
+ super.close();
+ }
+
+}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeSparkMod.java b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeSparkMod.java
index 07dce65..5ade1ea 100644
--- a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeSparkMod.java
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeSparkMod.java
@@ -22,48 +22,44 @@ package me.lucko.spark.forge;
import me.lucko.spark.forge.plugin.ForgeClientSparkPlugin;
import me.lucko.spark.forge.plugin.ForgeServerSparkPlugin;
-import net.minecraftforge.common.MinecraftForge;
-import net.minecraftforge.event.server.ServerAboutToStartEvent;
-import net.minecraftforge.eventbus.api.SubscribeEvent;
-import net.minecraftforge.fml.IExtensionPoint;
-import net.minecraftforge.fml.ModContainer;
+import me.lucko.spark.forge.plugin.ForgeSparkPlugin;
+import net.minecraft.client.Minecraft;
+import net.minecraft.server.MinecraftServer;
+import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.Mod;
-import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
-import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
-import net.minecraftforge.fml.loading.FMLPaths;
+import net.minecraftforge.fml.common.ModContainer;
+import net.minecraftforge.fml.common.event.FMLInitializationEvent;
+import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
+import java.io.File;
import java.nio.file.Path;
-@Mod("spark")
+@Mod(modid = "spark", useMetadata = true)
public class ForgeSparkMod {
- private final ModContainer container;
- private final Path configDirectory;
+ private ModContainer container;
+ private Path configDirectory;
+ ForgeSparkPlugin plugin;
- public ForgeSparkMod(FMLJavaModLoadingContext ctx) {
- this.container = ctx.getContainer();
- this.configDirectory = FMLPaths.CONFIGDIR.get().resolve(this.container.getModId());
+ @Mod.EventHandler
+ public void preInit(FMLPreInitializationEvent event) {
+ container = Loader.instance().activeModContainer();
+ configDirectory = new File(event.getModConfigurationDirectory(), container.getModId()).toPath();
+ }
- ctx.getModEventBus().addListener(this::clientInit);
- ctx.registerDisplayTest(IExtensionPoint.DisplayTest.IGNORE_ALL_VERSION);
+ @Mod.EventHandler
+ public void init(FMLInitializationEvent event) {
+ plugin = SidedExecutor.executeIf(
+ () -> () -> ForgeClientSparkPlugin.register(this, Minecraft.getMinecraft()),
+ () -> () -> ForgeServerSparkPlugin.register(this, MinecraftServer.getServer())
+ );
+ }
- MinecraftForge.EVENT_BUS.register(this);
- }
+ public String getVersion() {
+ return this.container.getMetadata().version;
+ }
- public String getVersion() {
- return this.container.getModInfo().getVersion().toString();
- }
-
- public void clientInit(FMLClientSetupEvent e) {
- ForgeClientSparkPlugin.register(this, e);
- }
-
- @SubscribeEvent
- public void serverInit(ServerAboutToStartEvent e) {
- ForgeServerSparkPlugin.register(this, e);
- }
-
- public Path getConfigDirectory() {
- return this.configDirectory;
- }
+ public Path getConfigDirectory() {
+ return this.configDirectory;
+ }
}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeWorldInfoProvider.java b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeWorldInfoProvider.java
index a87aa03..84ba2f9 100644
--- a/spark-forge/src/main/java/me/lucko/spark/forge/ForgeWorldInfoProvider.java
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/ForgeWorldInfoProvider.java
@@ -20,205 +20,156 @@
package me.lucko.spark.forge;
-import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+import com.mojang.realmsclient.util.Pair;
import me.lucko.spark.common.platform.world.AbstractChunkInfo;
import me.lucko.spark.common.platform.world.CountMap;
import me.lucko.spark.common.platform.world.WorldInfoProvider;
import net.minecraft.client.Minecraft;
-import net.minecraft.client.multiplayer.ClientLevel;
+import net.minecraft.client.multiplayer.WorldClient;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EntityList;
import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.level.ServerLevel;
-import net.minecraft.server.packs.repository.PackRepository;
-import net.minecraft.server.packs.repository.PackSource;
-import net.minecraft.world.entity.Entity;
-import net.minecraft.world.entity.EntityType;
-import net.minecraft.world.level.ChunkPos;
-import net.minecraft.world.level.GameRules;
-import net.minecraft.world.level.entity.EntityLookup;
-import net.minecraft.world.level.entity.PersistentEntitySectionManager;
-import net.minecraft.world.level.entity.TransientEntitySectionManager;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldServer;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
-import java.util.stream.Collectors;
+import java.util.Map;
public abstract class ForgeWorldInfoProvider implements WorldInfoProvider {
- protected abstract PackRepository getPackRepository();
-
- @Override
- public Collection<DataPackInfo> pollDataPacks() {
- return getPackRepository().getSelectedPacks().stream()
- .map(pack -> new DataPackInfo(
- pack.getId(),
- pack.getDescription().getString(),
- resourcePackSource(pack.getPackSource())
- ))
- .collect(Collectors.toList());
- }
-
- private static String resourcePackSource(PackSource source) {
- if (source == PackSource.DEFAULT) {
- return "none";
- } else if (source == PackSource.BUILT_IN) {
- return "builtin";
- } else if (source == PackSource.WORLD) {
- return "world";
- } else if (source == PackSource.SERVER) {
- return "server";
- } else {
- return "unknown";
- }
- }
-
- public static final class Server extends ForgeWorldInfoProvider {
- private final MinecraftServer server;
-
- public Server(MinecraftServer server) {
- this.server = server;
- }
-
- @Override
- public CountsResult pollCounts() {
- int players = this.server.getPlayerCount();
- int entities = 0;
- int chunks = 0;
-
- for (ServerLevel level : this.server.getAllLevels()) {
- PersistentEntitySectionManager<Entity> entityManager = level.entityManager;
- EntityLookup<Entity> entityIndex = entityManager.visibleEntityStorage;
-
- entities += entityIndex.count();
- chunks += level.getChunkSource().getLoadedChunksCount();
- }
-
- return new CountsResult(players, entities, -1, chunks);
- }
-
- @Override
- public ChunksResult<ForgeChunkInfo> pollChunks() {
- ChunksResult<ForgeChunkInfo> data = new ChunksResult<>();
-
- for (ServerLevel level : this.server.getAllLevels()) {
- Long2ObjectOpenHashMap<ForgeChunkInfo> levelInfos = new Long2ObjectOpenHashMap<>();
-
- for (Entity entity : level.getEntities().getAll()) {
- ForgeChunkInfo info = levelInfos.computeIfAbsent(
- entity.chunkPosition().toLong(), ForgeChunkInfo::new);
- info.entityCounts.increment(entity.getType());
- }
-
- data.put(level.dimension().location().getPath(), List.copyOf(levelInfos.values()));
- }
-
- return data;
- }
-
- @Override
- public GameRulesResult pollGameRules() {
- GameRulesResult data = new GameRulesResult();
- Iterable<ServerLevel> levels = this.server.getAllLevels();
-
- for (ServerLevel level : levels) {
- String levelName = level.dimension().location().getPath();
-
- level.getGameRules().visitGameRuleTypes(new GameRules.GameRuleTypeVisitor() {
- @Override
- public <T extends GameRules.Value<T>> void visit(GameRules.Key<T> key, GameRules.Type<T> type) {
- String defaultValue = type.createRule().serialize();
- data.putDefault(key.getId(), defaultValue);
-
- String value = level.getGameRules().getRule(key).serialize();
- data.put(key.getId(), levelName, value);
- }
- });
- }
-
- return data;
- }
-
- @Override
- protected PackRepository getPackRepository() {
- return this.server.getPackRepository();
- }
- }
-
- public static final class Client extends ForgeWorldInfoProvider {
- private final Minecraft client;
-
- public Client(Minecraft client) {
- this.client = client;
- }
-
- @Override
- public CountsResult pollCounts() {
- ClientLevel level = this.client.level;
- if (level == null) {
- return null;
- }
-
- TransientEntitySectionManager<Entity> entityManager = level.entityStorage;
- EntityLookup<Entity> entityIndex = entityManager.entityStorage;
-
- int entities = entityIndex.count();
- int chunks = level.getChunkSource().getLoadedChunksCount();
-
- return new CountsResult(-1, entities, -1, chunks);
- }
-
- @Override
- public ChunksResult<ForgeChunkInfo> pollChunks() {
- ClientLevel level = this.client.level;
- if (level == null) {
- return null;
- }
-
- ChunksResult<ForgeChunkInfo> data = new ChunksResult<>();
-
- Long2ObjectOpenHashMap<ForgeChunkInfo> levelInfos = new Long2ObjectOpenHashMap<>();
-
- for (Entity entity : level.getEntities().getAll()) {
- ForgeChunkInfo info = levelInfos.computeIfAbsent(entity.chunkPosition().toLong(), ForgeChunkInfo::new);
- info.entityCounts.increment(entity.getType());
- }
-
- data.put(level.dimension().location().getPath(), List.copyOf(levelInfos.values()));
+ protected void fillLevelChunkEntityCounts(World level, ChunksResult<ForgeChunkInfo> data) {
+ Map<Pair<Integer, Integer>, ForgeChunkInfo> levelInfos = new HashMap<>();
- return data;
- }
-
- @Override
- public GameRulesResult pollGameRules() {
- // Not available on client since 24w39a
- return null;
- }
-
- @Override
- protected PackRepository getPackRepository() {
- return this.client.getResourcePackRepository();
- }
- }
-
- public static final class ForgeChunkInfo extends AbstractChunkInfo<EntityType<?>> {
- private final CountMap<EntityType<?>> entityCounts;
-
- ForgeChunkInfo(long chunkPos) {
- super(ChunkPos.getX(chunkPos), ChunkPos.getZ(chunkPos));
-
- this.entityCounts = new CountMap.Simple<>(new HashMap<>());
- }
+ for (Entity entity : level.loadedEntityList) {
+ ForgeChunkInfo info = levelInfos.computeIfAbsent(
+ // TODO: pack ints to long
+ Pair.of(entity.chunkCoordX, entity.chunkCoordZ), ForgeChunkInfo::new);
+ info.entityCounts.increment(EntityList.getEntityID(entity));
+ }
- @Override
- public CountMap<EntityType<?>> getEntityCounts() {
- return this.entityCounts;
- }
-
- @Override
- public String entityTypeName(EntityType<?> type) {
- return EntityType.getKey(type).toString();
- }
- }
+ data.put(level.getWorldInfo().getWorldName(), new ArrayList<>(levelInfos.values()));
+ }
+
+ @Override
+ public Collection<DataPackInfo> pollDataPacks() {
+ return Collections.emptyList();
+ }
+
+ public static final class Server extends ForgeWorldInfoProvider {
+ private final MinecraftServer server;
+
+ public Server(MinecraftServer server) {
+ this.server = server;
+ }
+
+ @Override
+ public CountsResult pollCounts() {
+ int players = this.server.getCurrentPlayerCount();
+ int entities = 0;
+ int chunks = 0;
+ int tileEntities = 0;
+
+ for (WorldServer level : this.server.worldServers) {
+ entities += level.loadedEntityList.size();
+ chunks += level.theChunkProviderServer.getLoadedChunkCount();
+ tileEntities += level.loadedTileEntityList.size();
+ }
+
+ return new CountsResult(players, entities, tileEntities, chunks);
+ }
+
+ @Override
+ public ChunksResult<ForgeChunkInfo> pollChunks() {
+ ChunksResult<ForgeChunkInfo> data = new ChunksResult<>();
+
+ for (WorldServer level : this.server.worldServers) {
+ fillLevelChunkEntityCounts(level, data);
+ }
+
+ return data;
+ }
+
+ @Override
+ public GameRulesResult pollGameRules() {
+ GameRulesResult data = new GameRulesResult();
+
+ for (WorldServer level : this.server.worldServers) {
+ String levelName = level.getWorldInfo().getWorldName();
+
+ for (String rule : level.getGameRules().getRules()) {
+ data.put(rule, levelName, level.getGameRules().getString(rule));
+ }
+ }
+
+ return data;
+ }
+
+ }
+
+ public static final class Client extends ForgeWorldInfoProvider {
+ private final Minecraft client;
+
+ public Client(Minecraft client) {
+ this.client = client;
+ }
+
+ @Override
+ public CountsResult pollCounts() {
+ WorldClient level = this.client.theWorld;
+ if (level == null) {
+ return null;
+ }
+
+
+ int entities = level.loadedEntityList.size();
+ int chunks = level.getChunkProvider().getLoadedChunkCount();
+
+ return new CountsResult(-1, entities, -1, chunks);
+ }
+
+ @Override
+ public ChunksResult<ForgeChunkInfo> pollChunks() {
+ WorldClient level = this.client.theWorld;
+ if (level == null) {
+ return null;
+ }
+
+ ChunksResult<ForgeChunkInfo> data = new ChunksResult<>();
+
+ fillLevelChunkEntityCounts(level, data);
+
+ return data;
+ }
+
+ @Override
+ public GameRulesResult pollGameRules() {
+ // Not available on client since 24w39a
+ return null;
+ }
+ }
+
+ public static final class ForgeChunkInfo extends AbstractChunkInfo<Integer> {
+ private final CountMap<Integer> entityCounts;
+
+ ForgeChunkInfo(Pair<Integer, Integer> chunkPos) {
+ super(chunkPos.first(), chunkPos.second());
+
+ this.entityCounts = new CountMap.Simple<>(new HashMap<>());
+ }
+
+ @Override
+ public CountMap<Integer> getEntityCounts() {
+ return this.entityCounts;
+ }
+
+ @Override
+ public String entityTypeName(Integer type) {
+ return EntityList.getStringFromID(type);
+ }
+ }
}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/SidedExecutor.java b/spark-forge/src/main/java/me/lucko/spark/forge/SidedExecutor.java
new file mode 100644
index 0000000..588fdb3
--- /dev/null
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/SidedExecutor.java
@@ -0,0 +1,41 @@
+/*
+ * 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.forge;
+
+import net.minecraftforge.fml.common.FMLCommonHandler;
+
+import java.util.function.Supplier;
+
+public class SidedExecutor {
+ public static <T> T executeIf(
+ Supplier<? extends Supplier<? extends T>> onClient,
+ Supplier<? extends Supplier<? extends T>> onServer
+ ) {
+ switch (FMLCommonHandler.instance().getSide()) {
+ case CLIENT:
+ return onClient.get().get();
+ case SERVER:
+ return onServer.get().get();
+ }
+ throw new AssertionError();
+ }
+
+}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeClientSparkPlugin.java b/spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeClientSparkPlugin.java
index 607dbe1..b81103b 100644
--- a/spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeClientSparkPlugin.java
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeClientSparkPlugin.java
@@ -20,122 +20,104 @@
package me.lucko.spark.forge.plugin;
-import com.mojang.brigadier.Command;
-import com.mojang.brigadier.context.CommandContext;
-import com.mojang.brigadier.exceptions.CommandSyntaxException;
-import com.mojang.brigadier.suggestion.SuggestionProvider;
-import com.mojang.brigadier.suggestion.Suggestions;
-import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import me.lucko.spark.common.SparkPlatform;
+import me.lucko.spark.common.command.sender.CommandSender;
import me.lucko.spark.common.platform.PlatformInfo;
import me.lucko.spark.common.platform.world.WorldInfoProvider;
import me.lucko.spark.common.sampler.ThreadDumper;
import me.lucko.spark.common.tick.TickHook;
import me.lucko.spark.common.tick.TickReporter;
import me.lucko.spark.forge.ForgeClientCommandSender;
+import me.lucko.spark.forge.ForgeClientTickHook;
+import me.lucko.spark.forge.ForgeClientTickReporter;
import me.lucko.spark.forge.ForgePlatformInfo;
+import me.lucko.spark.forge.ForgeServerCommandSender;
import me.lucko.spark.forge.ForgeSparkMod;
-import me.lucko.spark.forge.ForgeTickHook;
-import me.lucko.spark.forge.ForgeTickReporter;
import me.lucko.spark.forge.ForgeWorldInfoProvider;
import net.minecraft.client.Minecraft;
-import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.command.ICommandSender;
import net.minecraftforge.client.ClientCommandHandler;
-import net.minecraftforge.client.event.RegisterClientCommandsEvent;
import net.minecraftforge.common.MinecraftForge;
-import net.minecraftforge.event.TickEvent;
-import net.minecraftforge.eventbus.api.SubscribeEvent;
-import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
-import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
-public class ForgeClientSparkPlugin extends ForgeSparkPlugin implements Command<CommandSourceStack>, SuggestionProvider<CommandSourceStack> {
-
- public static void register(ForgeSparkMod mod, FMLClientSetupEvent event) {
- ForgeClientSparkPlugin plugin = new ForgeClientSparkPlugin(mod, Minecraft.getInstance());
- plugin.enable();
- }
-
- private final Minecraft minecraft;
- private final ThreadDumper gameThreadDumper;
-
- public ForgeClientSparkPlugin(ForgeSparkMod mod, Minecraft minecraft) {
- super(mod);
- this.minecraft = minecraft;
- this.gameThreadDumper = new ThreadDumper.Specific(minecraft.gameThread);
- }
-
- @Override
- public void enable() {
- super.enable();
-
- // register listeners
- MinecraftForge.EVENT_BUS.register(this);
- }
-
- @SubscribeEvent
- public void onCommandRegister(RegisterClientCommandsEvent e) {
- registerCommands(e.getDispatcher(), this, this, "sparkc", "sparkclient");
- }
-
- @Override
- public int run(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
- String[] args = processArgs(context, false, "sparkc", "sparkclient");
- if (args == null) {
- return 0;
- }
-
- this.platform.executeCommand(new ForgeClientCommandSender(context.getSource()), args);
- return Command.SINGLE_SUCCESS;
- }
-
- @Override
- public CompletableFuture<Suggestions> getSuggestions(CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) throws CommandSyntaxException {
- String[] args = processArgs(context, true, "/sparkc", "/sparkclient");
- if (args == null) {
- return Suggestions.empty();
- }
-
- return generateSuggestions(new ForgeClientCommandSender(context.getSource()), args, builder);
- }
-
- @Override
- public Stream<ForgeClientCommandSender> getCommandSenders() {
- return Stream.of(new ForgeClientCommandSender(ClientCommandHandler.getSource()));
- }
-
- @Override
- public void executeSync(Runnable task) {
- this.minecraft.executeIfPossible(task);
- }
-
- @Override
- public ThreadDumper getDefaultThreadDumper() {
- return this.gameThreadDumper;
- }
-
- @Override
- public TickHook createTickHook() {
- return new ForgeTickHook(TickEvent.Type.CLIENT);
- }
-
- @Override
- public TickReporter createTickReporter() {
- return new ForgeTickReporter(TickEvent.Type.CLIENT);
- }
-
- @Override
- public WorldInfoProvider createWorldInfoProvider() {
- return new ForgeWorldInfoProvider.Client(this.minecraft);
- }
-
- @Override
- public PlatformInfo getPlatformInfo() {
- return new ForgePlatformInfo(PlatformInfo.Type.CLIENT);
- }
-
- @Override
- public String getCommandName() {
- return "sparkc";
- }
+public class ForgeClientSparkPlugin extends ForgeSparkPlugin {
+
+ public static ForgeClientSparkPlugin register(ForgeSparkMod mod, Minecraft minecraft) {
+ ForgeClientSparkPlugin plugin = new ForgeClientSparkPlugin(mod, minecraft);
+ plugin.enable();
+ return plugin;
+ }
+
+ private final Minecraft minecraft;
+ private final ThreadDumper gameThreadDumper;
+
+ public ForgeClientSparkPlugin(ForgeSparkMod mod, Minecraft minecraft) {
+ super(mod);
+ this.minecraft = minecraft;
+ assert minecraft.isCallingFromMinecraftThread();
+ this.gameThreadDumper = new ThreadDumper.Specific(Thread.currentThread());
+ registerCommands(ClientCommandHandler.instance, "sparkc", "sparkclient");
+ }
+
+ @Override
+ public void enable() {
+ super.enable();
+
+ // register listeners
+ MinecraftForge.EVENT_BUS.register(this);
+ }
+
+ @Override
+ public SparkPlatform getPlatform() {
+ return platform;
+ }
+
+ @Override
+ public CommandSender getCommandSender(ICommandSender sender) {
+ return sender instanceof EntityPlayerSP
+ ? new ForgeClientCommandSender((EntityPlayerSP) sender)
+ : new ForgeServerCommandSender(sender);
+ }
+
+ @Override
+ public Stream<ForgeClientCommandSender> getCommandSenders() {
+ return Stream.of(new ForgeClientCommandSender(minecraft.thePlayer));
+ }
+
+ @Override
+ public void executeSync(Runnable task) {
+ this.minecraft.addScheduledTask(task);
+ }
+
+ @Override
+ public ThreadDumper getDefaultThreadDumper() {
+ return this.gameThreadDumper;
+ }
+
+ @Override
+ public TickHook createTickHook() {
+ return new ForgeClientTickHook();
+ }
+
+ @Override
+ public TickReporter createTickReporter() {
+ return new ForgeClientTickReporter();
+ }
+
+ @Override
+ public WorldInfoProvider createWorldInfoProvider() {
+ return new ForgeWorldInfoProvider.Client(this.minecraft);
+ }
+
+ @Override
+ public PlatformInfo getPlatformInfo() {
+ return new ForgePlatformInfo(PlatformInfo.Type.CLIENT);
+ }
+
+ @Override
+ public String getCommandName() {
+ return "sparkc";
+ }
}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeServerSparkPlugin.java b/spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeServerSparkPlugin.java
index 368ae60..05060e7 100644
--- a/spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeServerSparkPlugin.java
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeServerSparkPlugin.java
@@ -20,14 +20,8 @@
package me.lucko.spark.forge.plugin;
-import com.google.common.collect.ImmutableMap;
-import com.mojang.brigadier.Command;
-import com.mojang.brigadier.CommandDispatcher;
-import com.mojang.brigadier.context.CommandContext;
-import com.mojang.brigadier.exceptions.CommandSyntaxException;
-import com.mojang.brigadier.suggestion.SuggestionProvider;
-import com.mojang.brigadier.suggestion.Suggestions;
-import com.mojang.brigadier.suggestion.SuggestionsBuilder;
+import me.lucko.spark.common.SparkPlatform;
+import me.lucko.spark.common.command.sender.CommandSender;
import me.lucko.spark.common.monitor.ping.PlayerPingProvider;
import me.lucko.spark.common.platform.PlatformInfo;
import me.lucko.spark.common.platform.serverconfig.ServerConfigProvider;
@@ -40,219 +34,113 @@ import me.lucko.spark.forge.ForgePlayerPingProvider;
import me.lucko.spark.forge.ForgeServerCommandSender;
import me.lucko.spark.forge.ForgeServerConfigProvider;
import me.lucko.spark.forge.ForgeSparkMod;
-import me.lucko.spark.forge.ForgeTickHook;
-import me.lucko.spark.forge.ForgeTickReporter;
+import me.lucko.spark.forge.ForgeServerTickHook;
+import me.lucko.spark.forge.ForgeServerTickReporter;
import me.lucko.spark.forge.ForgeWorldInfoProvider;
-import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.command.ServerCommandManager;
import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.common.MinecraftForge;
-import net.minecraftforge.event.RegisterCommandsEvent;
-import net.minecraftforge.event.TickEvent;
-import net.minecraftforge.event.server.ServerAboutToStartEvent;
-import net.minecraftforge.event.server.ServerStoppingEvent;
-import net.minecraftforge.eventbus.api.SubscribeEvent;
-import net.minecraftforge.server.permission.PermissionAPI;
-import net.minecraftforge.server.permission.events.PermissionGatherEvent;
-import net.minecraftforge.server.permission.nodes.PermissionNode;
-import net.minecraftforge.server.permission.nodes.PermissionNode.PermissionResolver;
-import net.minecraftforge.server.permission.nodes.PermissionTypes;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-import java.util.function.Function;
-import java.util.stream.Collectors;
+import java.util.Arrays;
import java.util.stream.Stream;
-public class ForgeServerSparkPlugin extends ForgeSparkPlugin implements Command<CommandSourceStack>, SuggestionProvider<CommandSourceStack> {
-
- public static void register(ForgeSparkMod mod, ServerAboutToStartEvent event) {
- ForgeServerSparkPlugin plugin = new ForgeServerSparkPlugin(mod, event.getServer());
- plugin.enable();
- }
-
- private static final PermissionResolver<Boolean> DEFAULT_PERMISSION_VALUE = (player, playerUUID, context) -> {
- if (player == null) {
- return false;
- }
-
- MinecraftServer server = player.getServer();
- if (server != null && server.isSingleplayerOwner(player.getGameProfile())) {
- return true;
- }
-
- return player.hasPermissions(4);
- };
-
- private final MinecraftServer server;
- private final ThreadDumper gameThreadDumper;
- private Map<String, PermissionNode<Boolean>> registeredPermissions = Collections.emptyMap();
-
- public ForgeServerSparkPlugin(ForgeSparkMod mod, MinecraftServer server) {
- super(mod);
- this.server = server;
- this.gameThreadDumper = new ThreadDumper.Specific(server.getRunningThread());
- }
-
- @Override
- public void enable() {
- super.enable();
-
- // register commands
- registerCommands(this.server.getCommands().getDispatcher());
-
- // register listeners
- MinecraftForge.EVENT_BUS.register(this);
- }
-
- @Override
- public void disable() {
- super.disable();
-
- // unregister listeners
- MinecraftForge.EVENT_BUS.unregister(this);
- }
-
- @SubscribeEvent
- public void onDisable(ServerStoppingEvent event) {
- if (event.getServer() == this.server) {
- disable();
- }
- }
-
- @SubscribeEvent
- public void onPermissionGather(PermissionGatherEvent.Nodes e) {
- // collect all possible permissions
- List<String> permissions = this.platform.getCommands().stream()
- .map(me.lucko.spark.common.command.Command::primaryAlias)
- .collect(Collectors.toList());
-
- // special case for the "spark" permission: map it to "spark.all"
- permissions.add("all");
-
- // register permissions with forge & keep a copy for lookup
- ImmutableMap.Builder<String, PermissionNode<Boolean>> builder = ImmutableMap.builder();
-
- Map<String, PermissionNode<?>> alreadyRegistered = e.getNodes().stream().collect(Collectors.toMap(PermissionNode::getNodeName, Function.identity()));
-
- for (String permission : permissions) {
- String permissionString = "spark." + permission;
-
- // there's a weird bug where it seems that this listener can be called twice, causing an
- // IllegalArgumentException to be thrown the second time e.addNodes is called.
- PermissionNode<?> existing = alreadyRegistered.get(permissionString);
- if (existing != null) {
- //noinspection unchecked
- builder.put(permissionString, (PermissionNode<Boolean>) existing);
- continue;
- }
-
- PermissionNode<Boolean> node = new PermissionNode<>("spark", permission, PermissionTypes.BOOLEAN, DEFAULT_PERMISSION_VALUE);
- e.addNodes(node);
- builder.put(permissionString, node);
- }
- this.registeredPermissions = builder.build();
- }
-
- @SubscribeEvent
- public void onCommandRegister(RegisterCommandsEvent e) {
- registerCommands(e.getDispatcher());
- }
-
- private void registerCommands(CommandDispatcher<CommandSourceStack> dispatcher) {
- registerCommands(dispatcher, this, this, "spark");
- }
-
- @Override
- public int run(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
- String[] args = processArgs(context, false, "/spark", "spark");
- if (args == null) {
- return 0;
- }
-
- this.platform.executeCommand(new ForgeServerCommandSender(context.getSource(), this), args);
- return Command.SINGLE_SUCCESS;
- }
-
- @Override
- public CompletableFuture<Suggestions> getSuggestions(CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) throws CommandSyntaxException {
- String[] args = processArgs(context, true, "/spark", "spark");
- if (args == null) {
- return Suggestions.empty();
- }
-
- return generateSuggestions(new ForgeServerCommandSender(context.getSource(), this), args, builder);
- }
-
- public boolean hasPermission(CommandSourceStack stack, String permission) {
- ServerPlayer player = stack.getPlayer();
- if (player != null) {
- if (permission.equals("spark")) {
- permission = "spark.all";
- }
-
- PermissionNode<Boolean> permissionNode = this.registeredPermissions.get(permission);
- if (permissionNode == null) {
- throw new IllegalStateException("spark permission not registered: " + permission);
- }
- return PermissionAPI.getPermission(player, permissionNode);
- } else {
- return true;
- }
- }
-
- @Override
- public Stream<ForgeServerCommandSender> getCommandSenders() {
- return Stream.concat(
- this.server.getPlayerList().getPlayers().stream().map(ServerPlayer::createCommandSourceStack),
- Stream.of(this.server.createCommandSourceStack())
- ).map(stack -> new ForgeServerCommandSender(stack, this));
- }
-
- @Override
- public void executeSync(Runnable task) {
- this.server.executeIfPossible(task);
- }
-
- @Override
- public ThreadDumper getDefaultThreadDumper() {
- return this.gameThreadDumper;
- }
-
- @Override
- public TickHook createTickHook() {
- return new ForgeTickHook(TickEvent.Type.SERVER);
- }
-
- @Override
- public TickReporter createTickReporter() {
- return new ForgeTickReporter(TickEvent.Type.SERVER);
- }
-
- @Override
- public PlayerPingProvider createPlayerPingProvider() {
- return new ForgePlayerPingProvider(this.server);
- }
-
- @Override
- public ServerConfigProvider createServerConfigProvider() {
- return new ForgeServerConfigProvider();
- }
-
- @Override
- public WorldInfoProvider createWorldInfoProvider() {
- return new ForgeWorldInfoProvider.Server(this.server);
- }
-
- @Override
- public PlatformInfo getPlatformInfo() {
- return new ForgePlatformInfo(PlatformInfo.Type.SERVER);
- }
-
- @Override
- public String getCommandName() {
- return "spark";
- }
+public class ForgeServerSparkPlugin extends ForgeSparkPlugin {
+
+ public static ForgeServerSparkPlugin register(ForgeSparkMod mod, MinecraftServer server) {
+ ForgeServerSparkPlugin plugin = new ForgeServerSparkPlugin(mod, server);
+ plugin.enable();
+ return plugin;
+ }
+
+ private final MinecraftServer server;
+ private final ThreadDumper gameThreadDumper;
+
+ public ForgeServerSparkPlugin(ForgeSparkMod mod, MinecraftServer server) {
+ super(mod);
+ this.server = server;
+ this.gameThreadDumper = new ThreadDumper.Specific(server.getServerThread());
+ }
+
+ @Override
+ public void enable() {
+ super.enable();
+
+ // register commands
+ registerCommands((ServerCommandManager) this.server.getCommandManager(), "spark", "sparkf");
+
+ // register listeners
+ MinecraftForge.EVENT_BUS.register(this);
+ }
+
+ @Override
+ public void disable() {
+ super.disable();
+
+ // unregister listeners
+ MinecraftForge.EVENT_BUS.unregister(this);
+ }
+
+ @Override
+ public SparkPlatform getPlatform() {
+ return platform;
+ }
+
+ @Override
+ public CommandSender getCommandSender(ICommandSender sender) {
+ return new ForgeServerCommandSender(sender);
+ }
+
+ @Override
+ public Stream<ForgeServerCommandSender> getCommandSenders() {
+ return Stream.concat(
+ Arrays.stream(server.worldServers).flatMap(it -> it.playerEntities.stream()),
+ Stream.of(server)
+ ).map(ForgeServerCommandSender::new);
+ }
+
+ @Override
+ public void executeSync(Runnable task) {
+ this.server.addScheduledTask(task);
+ }
+
+ @Override
+ public ThreadDumper getDefaultThreadDumper() {
+ return this.gameThreadDumper;
+ }
+
+ @Override
+ public TickHook createTickHook() {
+ return new ForgeServerTickHook();
+ }
+
+ @Override
+ public TickReporter createTickReporter() {
+ return new ForgeServerTickReporter();
+ }
+
+ @Override
+ public PlayerPingProvider createPlayerPingProvider() {
+ return new ForgePlayerPingProvider(this.server);
+ }
+
+ @Override
+ public ServerConfigProvider createServerConfigProvider() {
+ return new ForgeServerConfigProvider();
+ }
+
+ @Override
+ public WorldInfoProvider createWorldInfoProvider() {
+ return new ForgeWorldInfoProvider.Server(this.server);
+ }
+
+ @Override
+ public PlatformInfo getPlatformInfo() {
+ return new ForgePlatformInfo(PlatformInfo.Type.SERVER);
+ }
+
+ @Override
+ public String getCommandName() {
+ return "spark";
+ }
}
diff --git a/spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeSparkPlugin.java b/spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeSparkPlugin.java
index a543bfe..d57f1c1 100644
--- a/spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeSparkPlugin.java
+++ b/spark-forge/src/main/java/me/lucko/spark/forge/plugin/ForgeSparkPlugin.java
@@ -20,157 +20,145 @@
package me.lucko.spark.forge.plugin;
-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.context.CommandContext;
-import com.mojang.brigadier.suggestion.SuggestionProvider;
-import com.mojang.brigadier.suggestion.Suggestions;
-import com.mojang.brigadier.suggestion.SuggestionsBuilder;
-import com.mojang.brigadier.tree.LiteralCommandNode;
import me.lucko.spark.common.SparkPlatform;
import me.lucko.spark.common.SparkPlugin;
import me.lucko.spark.common.command.sender.CommandSender;
+import me.lucko.spark.common.platform.PlatformInfo;
import me.lucko.spark.common.sampler.source.ClassSourceLookup;
import me.lucko.spark.common.sampler.source.SourceMetadata;
import me.lucko.spark.common.util.SparkThreadFactory;
import me.lucko.spark.forge.ForgeClassSourceLookup;
import me.lucko.spark.forge.ForgeSparkMod;
-import net.minecraftforge.fml.ModList;
-import net.minecraftforge.forgespi.language.IModInfo;
+import net.minecraft.command.CommandBase;
+import net.minecraft.command.CommandException;
+import net.minecraft.command.CommandHandler;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.util.BlockPos;
+import net.minecraftforge.fml.common.Loader;
+import net.minecraftforge.fml.common.ModContainer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
-import java.util.concurrent.CompletableFuture;
+import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Level;
public abstract class ForgeSparkPlugin implements SparkPlugin {
- private final ForgeSparkMod mod;
- private final Logger logger;
- protected final ScheduledExecutorService scheduler;
-
- protected SparkPlatform platform;
-
- protected ForgeSparkPlugin(ForgeSparkMod mod) {
- this.mod = mod;
- this.logger = LogManager.getLogger("spark");
- this.scheduler = Executors.newScheduledThreadPool(4, new SparkThreadFactory());
- }
-
- public void enable() {
- this.platform = new SparkPlatform(this);
- this.platform.enable();
- }
-
- public void disable() {
- this.platform.disable();
- this.scheduler.shutdown();
- }
-
- @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 void log(Level level, String msg) {
- if (level.intValue() >= 1000) { // severe
- this.logger.error(msg);
- } else if (level.intValue() >= 900) { // warning
- this.logger.warn(msg);
- } else {
- this.logger.info(msg);
- }
- }
-
- @Override
- public void log(Level level, String msg, Throwable throwable) {
- if (level.intValue() >= 1000) { // severe
- this.logger.error(msg, throwable);
- } else if (level.intValue() >= 900) { // warning
- this.logger.warn(msg, throwable);
- } else {
- this.logger.info(msg, throwable);
- }
- }
-
- @Override
- public ClassSourceLookup createClassSourceLookup() {
- return new ForgeClassSourceLookup();
- }
-
- @Override
- public Collection<SourceMetadata> getKnownSources() {
- return SourceMetadata.gather(
- ModList.get().getMods(),
- IModInfo::getModId,
- mod -> mod.getVersion().toString(),
- mod -> null, // ?
- IModInfo::getDescription
- );
- }
-
- protected CompletableFuture<Suggestions> generateSuggestions(CommandSender sender, String[] args, SuggestionsBuilder builder) {
- SuggestionsBuilder suggestions;
-
- int lastSpaceIdx = builder.getRemaining().lastIndexOf(' ');
- if (lastSpaceIdx != -1) {
- suggestions = builder.createOffset(builder.getStart() + lastSpaceIdx + 1);
- } else {
- suggestions = builder;
- }
-
- return CompletableFuture.supplyAsync(() -> {
- for (String suggestion : this.platform.tabCompleteCommand(sender, args)) {
- suggestions.suggest(suggestion);
- }
- return suggestions.build();
- });
- }
-
- protected static <T> void registerCommands(CommandDispatcher<T> dispatcher, Command<T> executor, SuggestionProvider<T> suggestor, 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())
- .suggests(suggestor)
- .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));
- }
- }
-
- protected static String[] processArgs(CommandContext<?> context, boolean tabComplete, String... aliases) {
- String[] split = context.getInput().split(" ", tabComplete ? -1 : 0);
- if (split.length == 0 || !Arrays.asList(aliases).contains(split[0])) {
- return null;
- }
-
- return Arrays.copyOfRange(split, 1, split.length);
- }
+ private final ForgeSparkMod mod;
+ private final Logger logger;
+ protected final ScheduledExecutorService scheduler;
+
+ protected SparkPlatform platform;
+
+ protected ForgeSparkPlugin(ForgeSparkMod mod) {
+ this.mod = mod;
+ this.logger = LogManager.getLogger("spark");
+ this.scheduler = Executors.newScheduledThreadPool(4, new SparkThreadFactory());
+ }
+
+ public void enable() {
+ this.platform = new SparkPlatform(this);
+ this.platform.enable();
+ }
+
+ public void disable() {
+ this.platform.disable();
+ this.scheduler.shutdown();
+ }
+
+ @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 void log(Level level, String msg) {
+ if (level.intValue() >= 1000) { // severe
+ this.logger.error(msg);
+ } else if (level.intValue() >= 900) { // warning
+ this.logger.warn(msg);
+ } else {
+ this.logger.info(msg);
+ }
+ }
+
+ @Override
+ public void log(Level level, String msg, Throwable throwable) {
+ if (level.intValue() >= 1000) { // severe
+ this.logger.error(msg, throwable);
+ } else if (level.intValue() >= 900) { // warning
+ this.logger.warn(msg, throwable);
+ } else {
+ this.logger.info(msg, throwable);
+ }
+ }
+
+ @Override
+ public ClassSourceLookup createClassSourceLookup() {
+ return new ForgeClassSourceLookup();
+ }
+
+ @Override
+ public Collection<SourceMetadata> getKnownSources() {
+ return SourceMetadata.gather(
+ Loader.instance().getActiveModList(),
+ ModContainer::getModId,
+ ModContainer::getVersion,
+ mod -> mod.getMetadata().getAuthorList(), // ?
+ mod -> mod.getMetadata().description
+ );
+ }
+
+ public abstract SparkPlatform getPlatform();
+
+ public abstract CommandSender getCommandSender(ICommandSender sender) ;
+
+ protected void registerCommands(CommandHandler handler, String name, String... aliases) {
+ handler.registerCommand(new CommandBase() {
+ @Override
+ public String getCommandName() {
+ return name;
+ }
+
+ @Override
+ public List<String> getCommandAliases() {
+ return Arrays.asList(aliases);
+ }
+
+ @Override
+ public String getCommandUsage(ICommandSender sender) {
+ return name + " help";
+ }
+
+ @Override
+ public boolean canCommandSenderUseCommand(ICommandSender sender) {
+ return super.canCommandSenderUseCommand(sender) || getPlatformInfo().getType() == PlatformInfo.Type.CLIENT;
+ }
+
+ @Override
+ public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {
+ return getPlatform().tabCompleteCommand(getCommandSender(sender), args);
+ }
+
+ @Override
+ public void processCommand(ICommandSender sender, String[] args) throws CommandException {
+ getPlatform().executeCommand(getCommandSender(sender), args);
+ }
+ });
+ }
}
diff --git a/spark-forge/src/main/resources/mcmod.info b/spark-forge/src/main/resources/mcmod.info
new file mode 100644
index 0000000..567016e
--- /dev/null
+++ b/spark-forge/src/main/resources/mcmod.info
@@ -0,0 +1,8 @@
+[
+ {
+ "modid": "spark",
+ "name": "spark",
+ "version": "${pluginVersion}",
+ "description": "${pluginDescription}"
+ }
+] \ No newline at end of file