diff options
author | Linnea Gräf <nea@nea.moe> | 2025-02-28 14:17:45 +0100 |
---|---|---|
committer | Linnea Gräf <nea@nea.moe> | 2025-02-28 14:37:10 +0100 |
commit | 3738efb56b920d29918aceb42c30698884389caf (patch) | |
tree | 3800c10d7abcfb42c687bfc8e9a61ffff3590d3e | |
parent | cccd48323b9987274a14bd2cbc9e009b0ed8e407 (diff) | |
download | spark-3738efb56b920d29918aceb42c30698884389caf.tar.gz spark-3738efb56b920d29918aceb42c30698884389caf.tar.bz2 spark-3738efb56b920d29918aceb42c30698884389caf.zip |
Port to 1.8.91.10.127+b.neamaster
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 |