Downgrade gradle to 8.14.3, remove fabric support, update README.md

This commit is contained in:
NotAlexNoyle committed 2025-11-28 09:25:26 -05:00
1 parent 49742a9ddc
commit 3ae1e32813
96 files changed
+126 -4241

No files matched your search

+11 -17
View File
@@ -1,5 +1,5 @@
<div align="center">
<h1>GrimAC</h1>
<h1>GrimAC (LightningGrim Fork)</h1>
<div>
<a href="https://github.com/GrimAnticheat/Grim/actions/workflows/gradle-publish.yml">
@@ -23,15 +23,15 @@ It currently supports minecraft versions 1.8–1.21. Geyser players are fully ex
This project is considered feature-complete for the 2.0 (open-source) branch. If you would like a bug fix or enhancement and cannot sponsor the work, pull requests are welcome.
A premium version is planned, which will offer additional subscription-based paid checks, such as heuristics.
## Downloads
## Changes over Grim:
- Latest updates:
- **[Modrinth](https://modrinth.com/plugin/grimac)** *(recommended)*
- GitHub
artifacts: [Bukkit](https://nightly.link/GrimAnticheat/Grim/workflows/gradle-publish/2.0/grimac-bukkit.zip), [Fabric](https://nightly.link/GrimAnticheat/Grim/workflows/gradle-publish/2.0/grimac-fabric.zip) *(bleeding edge)*
- Major releases only:
- ~~[Hangar](https://hangar.papermc.io/GrimAnticheat/GrimAnticheat)~~
- ~~[SpigotMC](https://www.spigotmc.org/resources/grim-anticheat.99923/)~~
- WallHit - checks for hitting through walls
- EntityPierce - checks for hitting through other entities
- Bukkit Event Piston Optimizations
- Optimized Hitbox/Collision Boxes
- Optimized Reach calculations
- Checks for PacketOrder (patches lots of noslow, autoblocks, etc...)
- Checks for Inventory interactions (prevents using crafting slots as extra storage, moving while having inventory open, etc...)
## Resources
@@ -40,17 +40,11 @@ A premium version is planned, which will offer additional subscription-based pai
- For community support and project discussion join our [Discord](https://discord.grim.ac).
## Pull Requests
See [Contributing](CONTRIBUTING.md) for more information about contributing and what our guidelines
are.
## Requirements & Installation
- Java 17 or higher. *For more details
see [Updating-to-Java-17](https://github.com/GrimAnticheat/Grim/wiki/Updating-to-Java-17).*
- A Spigot, Paper, Folia, or Fabric server environment. *For more details
- A Spigot, Paper, or Folia, server environment. *For more details
see [Supported-environments](https://github.com/GrimAnticheat/Grim/wiki/Supported-environments).*
- If you use Geyser, place Floodgate on the backend server so grim can exempt bedrock players. Grim
cannot access the Floodgate API if it is on the proxy.
@@ -67,7 +61,7 @@ information.
1. `git clone https://github.com/Axionize/LightningGrim`
2. `cd LightningGrim`
3. `./gradlew build`
3. `./gradlew build clean eclipse --warning-mode all`
4. The final jars will compile into the `<platform>/build/libs` folders
## Grim Supremacy
+18
View File
@@ -9,6 +9,12 @@
* Logic in: buildSrc/versioning/BuildConfig.kt & VersionUtil.kt
*/
plugins {
base
}
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.compile.JavaCompile
import versioning.BuildConfig
import versioning.VersionUtil
@@ -47,3 +53,15 @@ subprojects {
options.isIncremental = true
}
}
tasks.register<Copy>("copyBukkitJarToRoot") {
dependsOn(":bukkit:shadowJar")
from(project(":bukkit").layout.buildDirectory.dir("libs"))
include("LightningGrim-bukkit-*.jar")
into(layout.buildDirectory.dir("libs"))
}
tasks.named("build") {
dependsOn("copyBukkitJarToRoot")
}
@@ -66,7 +66,6 @@ tasks {
listOf(
"bungee.yml",
"velocity-plugin.json",
"fabric.mod.json",
"grimac.properties"
)
) {
+1 -3
View File
@@ -76,7 +76,6 @@ repositories {
mavenCentral()
}
dependencies {
compileOnly(libs.paper.api)
compileOnly(libs.placeholderapi)
@@ -185,12 +184,11 @@ bukkit {
"Shows lists of specific data"
default = Permission.Default.FALSE
}
}
}
publishing.publications.create<MavenPublication>("maven") {
artifact(tasks["shadowJar"])
artifact(tasks.named("shadowJar"))
}
tasks {
+1
View File
@@ -1,6 +1,7 @@
import versioning.BuildConfig
plugins {
eclipse
`maven-publish`
grim.`base-conventions`
}
-196
View File
@@ -1,196 +0,0 @@
import versioning.BuildConfig
val minecraft_version: String by project
val yarn_mappings: String by project
val fabric_version: String by project
plugins {
`maven-publish`
alias(libs.plugins.fabric.loom)
grim.`base-conventions`
grim.`jij-conventions`
}
dependencies {
minecraft("com.mojang:minecraft:$minecraft_version")
mappings(loom.officialMojangMappings())
modImplementation(fabricApi.module("fabric-lifecycle-events-v1", fabric_version))
modImplementation("me.lucko:fabric-permissions-api:0.3.1")
modImplementation(libs.cloud.fabric)
modImplementation(libs.fabric.loader)
if (BuildConfig.shadePE) {
modImplementation(libs.packetevents.fabric)
} else {
compileOnly(libs.packetevents.fabric)
}
compileOnly("org.slf4j:slf4j-api:2.0.17")
compileOnly("org.apache.logging.log4j:log4j-api:2.24.3")
modApi(libs.packetevents.fabric)
}
// The configurations below will only apply to :fabric and its submodules, not its siblings or the root project
allprojects {
apply(plugin = "fabric-loom")
apply(plugin = "grim.base-conventions")
apply(plugin = "maven-publish")
repositories {
if (BuildConfig.mavenLocalOverride) {
mavenLocal()
}
exclusiveContent {
forRepository {
maven("https://maven.fabricmc.net/")
}
filter {
includeGroup("net.fabricmc")
includeGroup("net.fabricmc.fabric-api")
}
}
exclusiveContent {
forRepository {
maven("https://repo.grim.ac/snapshots") // Grim API & PacketEvents
}
filter {
includeGroup("ac.grim.grimac")
includeGroup("com.github.retrooper")
}
}
exclusiveContent {
forRepository {
maven("https://jitpack.io") { // Conditional Mixin
mavenContent { releasesOnly() }
}
}
filter {
includeGroup("com.github.Fallen-Breath.conditional-mixin")
}
}
exclusiveContent {
// The repository URL is determined by the project's name
if (project.name == "mc1161") {
// For the 1.16.1 subproject, the old snapshot is on the Grim repo
forRepository {
maven("https://repo.grim.ac/snapshots")
}
} else {
// For all other subprojects, the releases are on Maven Central
forRepository {
mavenCentral()
}
}
// This filter applies to whichever repository was chosen above
filter {
includeGroup("me.lucko")
}
}
exclusiveContent {
forRepository {
maven("https://repo.viaversion.com") { // ViaVersion
mavenContent { releasesOnly() }
}
}
filter {
includeGroup("com.viaversion")
}
}
exclusiveContent {
forRepository {
maven("https://nexus.scarsz.me/content/repositories/releases") { // Configuralize
mavenContent { releasesOnly() }
}
}
filter {
includeGroup("github.scarsz")
}
}
exclusiveContent {
forRepository {
maven("https://repo.opencollab.dev/maven-releases/") { // Cumulus (for Floodgate)
mavenContent { releasesOnly() }
}
}
filter {
includeGroup("org.geysermc.api")
}
}
exclusiveContent {
forRepository {
maven("https://repo.opencollab.dev/maven-snapshots/") { // Floodgate
mavenContent { snapshotsOnly() }
}
}
filter {
includeGroup("org.geysermc.floodgate")
includeGroup("org.geysermc.cumulus")
includeModule("org.geysermc", "common")
includeModule("org.geysermc", "geyser-parent")
}
}
mavenCentral()
}
loom {
accessWidenerPath = file("src/main/resources/grimac.accesswidener")
}
dependencies {
// I hate this syntax, is there an alternative to make modCompileOnly(libs.package.name) work?
val libsx = rootProject.extensions.getByType<VersionCatalogsExtension>().named("libs")
// Use the libs extension from the root project
modImplementation(libsx.findLibrary("cloud-fabric").get()) {
exclude(group = "net.fabricmc.fabric-api")
}
modImplementation(libsx.findLibrary("fabric-loader").get())
implementation(project(":common"))
}
publishing.publications.create<MavenPublication>("maven") {
artifact(tasks["remapJar"])
}
tasks {
remapJar {
archiveBaseName = "${rootProject.name}-fabric${if (project.name != "fabric") "-${project.name}" else ""}"
archiveVersion = rootProject.version as String
}
remapSourcesJar {
archiveVersion = rootProject.version as String
}
}
}
subprojects {
dependencies {
// configuration = "namedElements" required when depending on another loom project
implementation(project(":fabric", configuration = "namedElements"))
}
}
subprojects.forEach {
tasks.named("remapJar").configure {
dependsOn("${it.path}:remapJar")
}
}
tasks.remapJar.configure {
subprojects.forEach { subproject ->
subproject.tasks.matching { it.name == "remapJar" }.configureEach {
nestedJars.from(this)
}
}
}
-11
View File
@@ -1,11 +0,0 @@
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx2G
org.gradle.parallel=true
# Fabric Properties
# check these on https://fabricmc.net/develop
minecraft_version=1.16.1
yarn_mappings=1.16.1+build.21
loader_version=0.16.13
# Fabric API
fabric_version=0.42.0+1.16
-11
View File
@@ -1,11 +0,0 @@
dependencies {
minecraft("com.mojang:minecraft:1.16.1")
mappings(loom.officialMojangMappings())
modImplementation(fabricApi.module("fabric-lifecycle-events-v1", "0.42.0+1.16"))
modImplementation("me.lucko:fabric-permissions-api:0.1-SNAPSHOT")
}
loom {
accessWidenerPath = file("src/main/resources/grimac.accesswidener")
}
@@ -1,21 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1161;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.fabric.AbstractFabricPlatformServer;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import net.minecraft.commands.CommandSourceStack;
public class Fabric1140PlatformServer extends AbstractFabricPlatformServer {
@Override
public void dispatchCommand(Sender sender, String command) {
CommandSourceStack commandSource = GrimACFabricLoaderPlugin.LOADER.getFabricSenderFactory().reverse(sender);
GrimACFabricLoaderPlugin.FABRIC_SERVER.getCommands().performCommand(commandSource, command);
}
// TODO (Cross-platform) implement proper bukkit equivalent for getting TPS over time
@Override
public double getTPS() {
return Math.min(1000.0 / GrimACFabricLoaderPlugin.FABRIC_SERVER.getAverageTickTime(), 20.0);
}
}
@@ -1,52 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1161;
import ac.grim.grimac.platform.fabric.AbstractFabricPlatformServer;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.command.FabricPlayerSelectorParser;
import ac.grim.grimac.platform.fabric.manager.FabricParserDescriptorFactory;
import ac.grim.grimac.platform.fabric.mc1161.command.Fabric1161PlayerSelectorAdapter;
import ac.grim.grimac.platform.fabric.mc1161.entity.Fabric1161GrimEntity;
import ac.grim.grimac.platform.fabric.mc1161.player.Fabric1161PlatformInventory;
import ac.grim.grimac.platform.fabric.mc1161.player.Fabric1161PlatformPlayer;
import ac.grim.grimac.platform.fabric.mc1161.util.convert.Fabric1140ConversionUtil;
import ac.grim.grimac.platform.fabric.mc1161.util.convert.Fabric1161MessageUtil;
import ac.grim.grimac.platform.fabric.player.FabricPlatformPlayerFactory;
import ac.grim.grimac.platform.fabric.utils.convert.IFabricConversionUtil;
import ac.grim.grimac.platform.fabric.utils.message.IFabricMessageUtil;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
public class GrimACFabric1161LoaderPlugin extends GrimACFabricLoaderPlugin {
public GrimACFabric1161LoaderPlugin() {
this(
new FabricPlatformPlayerFactory(
Fabric1161PlatformPlayer::new,
Fabric1161GrimEntity::new,
Fabric1161PlatformInventory::new
),
new Fabric1140PlatformServer(),
new Fabric1161MessageUtil(),
new Fabric1140ConversionUtil()
);
}
protected GrimACFabric1161LoaderPlugin(
FabricPlatformPlayerFactory playerFactory,
AbstractFabricPlatformServer platformServer,
IFabricMessageUtil fabricMessageUtil,
IFabricConversionUtil fabricConversionUtil
) {
super(
new FabricParserDescriptorFactory(new FabricPlayerSelectorParser<>(Fabric1161PlayerSelectorAdapter::new)),
playerFactory,
platformServer,
fabricMessageUtil,
fabricConversionUtil
);
}
@Override
public ServerVersion getNativeVersion() {
return ServerVersion.V_1_16_1;
}
}
@@ -1,38 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1161.command;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.platform.api.command.PlayerSelector;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.fabric.sender.FabricSenderFactory;
import org.incendo.cloud.minecraft.modded.data.SinglePlayerSelector;
import java.util.Collection;
import java.util.Collections;
public class Fabric1161PlayerSelectorAdapter implements PlayerSelector {
protected final SinglePlayerSelector fabricSelector;
public Fabric1161PlayerSelectorAdapter(SinglePlayerSelector fabricSelector) {
this.fabricSelector = fabricSelector;
}
@Override
public boolean isSingle() {
return true;
}
@Override
public Sender getSinglePlayer() {
return ((FabricSenderFactory) GrimAPI.INSTANCE.getSenderFactory()).map(fabricSelector.single().createCommandSourceStack());
}
@Override
public Collection<Sender> getPlayers() {
return Collections.singletonList(getSinglePlayer()); // Assuming your ServerPlayer can be cast to Player
}
@Override
public String inputString() {
return fabricSelector.inputString();
}
}
@@ -1,36 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1161.entity;
import ac.grim.grimac.platform.fabric.entity.AbstractFabricGrimEntity;
import ac.grim.grimac.platform.fabric.utils.thread.FabricFutureUtil;
import ac.grim.grimac.utils.math.Location;
import java.util.concurrent.CompletableFuture;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
public class Fabric1161GrimEntity extends AbstractFabricGrimEntity {
public Fabric1161GrimEntity(Entity entity) {
super(entity);
}
@Override
public CompletableFuture<Boolean> teleportAsync(Location location) {
return FabricFutureUtil.supplySync(() -> {
if (entity.getCommandSenderWorld() instanceof ServerLevel) {
entity.teleportToWithTicket(
location.getX(),
location.getY(),
location.getZ()
);
return true;
}
return false;
});
}
@Override
public boolean isDead() {
return entity instanceof LivingEntity living ? living.isDeadOrDying() : entity.removed;
}
}
@@ -1,82 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1161.player;
import ac.grim.grimac.platform.fabric.player.AbstractFabricPlatformInventory;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.inventory.MenuType;
import org.jetbrains.annotations.Nullable;
public class Fabric1161PlatformInventory extends AbstractFabricPlatformInventory {
public Fabric1161PlatformInventory(ServerPlayer player) {
super(player);
}
// TODO
// I don't understand why we do this on Bukkit, so I'm replicating the behaviour without high-level understanding of purpose
// This method is only used to check if the inventory matches one of the following
// private static final Set<String> SUPPORTED_INVENTORIES = new HashSet<>(
// Arrays.asList("CHEST", "DISPENSER", "DROPPER", "PLAYER", "ENDER_CHEST", "SHULKER_BOX", "BARREL", "CRAFTING", "CREATIVE")
// );
// And is slated to be replaced by packet based behaviour, this should do for now
@Override
public String getOpenInventoryKey() {
AbstractContainerMenu handler = fabricPlayer.containerMenu;
MenuType<?> type = getSafeType(handler);
// Handle null types (player crafting and creative)
if (type == null) {
// 4x4 CRAFTING -> CRAFTING
if (handler instanceof InventoryMenu) {
return "CRAFTING";
// Not sure if creative mode check here is correct
} else if (this.isPlayerCreative()) {
return "CREATIVE";
}
}
// should we handle crafters here also??
// CRAFTING -> CRAFTING
if (type == MenuType.CRAFTING) {
return "CRAFTING";
// PLAYER -> PLAYER
} else if (type == MenuType.GENERIC_9x4) {
return "PLAYER";
// CHEST, ENDER_CHEST, or BARREL -> CHEST
} else if (type == MenuType.GENERIC_9x3) {
return "CHEST";
// DISPENSER, DROPPER -> DISPENSER
} else if (type == MenuType.GENERIC_3x3) {
return "DISPENSER";
} else {
// Registry handles:
// SHULKER_BOX -> SHULKER_BOX
// CRAFTIING -> CRAFTING
ResourceLocation registryKey = this.getScreenID(type);
if (registryKey != null) {
return registryKey.getPath();
}
return handler.getClass().getSimpleName(); // Default fallback
}
}
protected ResourceLocation getScreenID(MenuType<?> type) {
return Registry.MENU.getKey(type);
}
protected boolean isPlayerCreative() {
return fabricPlayer.isCreative();
}
protected @Nullable MenuType<?> getSafeType(AbstractContainerMenu handler) {
try {
return handler.getType();
} catch (UnsupportedOperationException e) {
return null;
}
}
}
@@ -1,36 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1161.player;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.player.AbstractFabricPlatformPlayer;
import ac.grim.grimac.platform.fabric.utils.thread.FabricFutureUtil;
import ac.grim.grimac.utils.math.Location;
import java.util.concurrent.CompletableFuture;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
public class Fabric1161PlatformPlayer extends AbstractFabricPlatformPlayer {
public Fabric1161PlatformPlayer(ServerPlayer player) {
super(player);
}
@Override
public Sender getSender() {
return GrimACFabricLoaderPlugin.LOADER.getFabricSenderFactory().map(entity.createCommandSourceStack());
}
@Override
public CompletableFuture<Boolean> teleportAsync(Location location) {
return FabricFutureUtil.supplySync(() -> {
fabricPlayer.teleportTo(
(ServerLevel) location.getWorld(),
location.getX(),
location.getY(),
location.getZ(),
location.getYaw(),
location.getPitch()
);
return true;
});
}
}
@@ -1,37 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1161.util.convert;
import ac.grim.grimac.platform.fabric.utils.convert.IFabricConversionUtil;
import ac.grim.grimac.utils.anticheat.LogUtil;
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import io.github.retrooper.packetevents.adventure.serializer.gson.GsonComponentSerializer;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import net.kyori.adventure.text.Component;
import net.minecraft.network.FriendlyByteBuf;
public class Fabric1140ConversionUtil implements IFabricConversionUtil {
public ItemStack fromFabricItemStack(net.minecraft.world.item.ItemStack fabricStack) {
if (fabricStack.isEmpty()) {
return ItemStack.EMPTY;
}
ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer();
try {
FriendlyByteBuf packetByteBuf = new FriendlyByteBuf(buffer);
packetByteBuf.writeItem(fabricStack);
PacketWrapper<?> wrapper = PacketWrapper.createUniversalPacketWrapper(buffer);
return wrapper.readItemStack();
} catch (Exception e) {
LogUtil.error("Failed to encode ItemStack: {}" + fabricStack, e);
return ItemStack.EMPTY;
} finally {
ByteBufHelper.release(buffer);
}
}
public net.minecraft.network.chat.Component toNativeText(Component component) {
return net.minecraft.network.chat.Component.Serializer.fromJson(GsonComponentSerializer.gson().serializeToTree(component));
}
}
@@ -1,18 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1161.util.convert;
import ac.grim.grimac.platform.fabric.utils.message.IFabricMessageUtil;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
public class Fabric1161MessageUtil implements IFabricMessageUtil {
@Override
public Component textLiteral(String message) {
return new TextComponent(message);
}
@Override
public void sendMessage(CommandSourceStack target, Component message, boolean overlay) {
target.sendSuccess(message, overlay);
}
}
@@ -1,23 +0,0 @@
{
"schemaVersion": 1,
"id": "grimac-mc1161",
"version": "${version}",
"name": "GrimAC for 1.16.1",
"description": "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0.",
"authors": [
"GrimAC"
],
"license": "GPLv3",
"environment": "server",
"entrypoints": {
"grimMainLoad": [
"ac.grim.grimac.platform.fabric.mc1161.GrimACFabric1161LoaderPlugin"
]
},
"accessWidener": "grimac.accesswidener",
"depends": {
"fabricloader": "\u003e\u003d0.16",
"minecraft": ">=1.16.1",
"fabric-resource-loader-v0": "*"
}
}
@@ -1,3 +0,0 @@
accessWidener v2 named
accessible field net/minecraft/server/level/ServerLevel serverLevelData Lnet/minecraft/world/level/storage/ServerLevelData;
accessible field net/minecraft/commands/CommandSourceStack source Lnet/minecraft/commands/CommandSource;
-8
View File
@@ -1,8 +0,0 @@
dependencies {
minecraft("com.mojang:minecraft:1.17.1")
mappings(loom.officialMojangMappings())
compileOnly(project(":fabric:mc1161", configuration = "namedElements"))
modImplementation(fabricApi.module("fabric-lifecycle-events-v1", "0.46.1+1.17"))
modImplementation("me.lucko:fabric-permissions-api:0.3.1")
}
@@ -1,16 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1171;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.mc1161.Fabric1140PlatformServer;
import com.mojang.authlib.GameProfile;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class Fabric1171PlatformServer extends Fabric1140PlatformServer {
@Override
public @Nullable GameProfile getProfileByName(String name) {
Optional<GameProfile> gameProfile = GrimACFabricLoaderPlugin.FABRIC_SERVER.getProfileCache().get(name);
return gameProfile.orElse(null);
}
}
@@ -1,57 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1171;
import ac.grim.grimac.platform.fabric.AbstractFabricPlatformServer;
import ac.grim.grimac.platform.api.manager.CommandAdapter;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.command.FabricPlayerSelectorParser;
import ac.grim.grimac.platform.fabric.manager.FabricParserDescriptorFactory;
import ac.grim.grimac.platform.fabric.mc1171.player.Fabric1170PlatformPlayer;
import ac.grim.grimac.platform.fabric.mc1161.Fabric1140PlatformServer;
import ac.grim.grimac.platform.fabric.mc1161.command.Fabric1161PlayerSelectorAdapter;
import ac.grim.grimac.platform.fabric.mc1161.player.Fabric1161PlatformInventory;
import ac.grim.grimac.platform.fabric.mc1171.entity.Fabric1170GrimEntity;
import ac.grim.grimac.platform.fabric.mc1161.util.convert.Fabric1140ConversionUtil;
import ac.grim.grimac.platform.fabric.mc1161.util.convert.Fabric1161MessageUtil;
import ac.grim.grimac.platform.fabric.player.FabricPlatformPlayerFactory;
import ac.grim.grimac.platform.fabric.utils.convert.IFabricConversionUtil;
import ac.grim.grimac.platform.fabric.utils.message.IFabricMessageUtil;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
public class GrimACFabric1170LoaderPlugin extends GrimACFabricLoaderPlugin {
public GrimACFabric1170LoaderPlugin() {
this( new FabricParserDescriptorFactory(
new FabricPlayerSelectorParser<>(Fabric1161PlayerSelectorAdapter::new)
),
new FabricPlatformPlayerFactory(
Fabric1170PlatformPlayer::new,
Fabric1170GrimEntity::new,
Fabric1161PlatformInventory::new
),
PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_17)
? new Fabric1171PlatformServer() : new Fabric1140PlatformServer(),
new Fabric1161MessageUtil(),
new Fabric1140ConversionUtil()
);
}
protected GrimACFabric1170LoaderPlugin(CommandAdapter parserDescriptorFactory,
FabricPlatformPlayerFactory playerFactory,
AbstractFabricPlatformServer platformServer,
IFabricMessageUtil fabricMessageUtil,
IFabricConversionUtil fabricConversionUtil) {
super(
parserDescriptorFactory,
playerFactory,
platformServer,
fabricMessageUtil,
fabricConversionUtil
);
}
@Override
public ServerVersion getNativeVersion() {
return ServerVersion.V_1_17_1;
}
}
@@ -1,17 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1171.entity;
import ac.grim.grimac.platform.fabric.mc1161.entity.Fabric1161GrimEntity;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
public class Fabric1170GrimEntity extends Fabric1161GrimEntity {
public Fabric1170GrimEntity(Entity entity) {
super(entity);
}
@Override
public boolean isDead() {
return this.entity instanceof LivingEntity living ? living.isDeadOrDying() : this.entity.isRemoved();
}
}
@@ -1,17 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1171.player;
import ac.grim.grimac.platform.fabric.mc1161.player.Fabric1161PlatformPlayer;
import ac.grim.grimac.platform.fabric.utils.convert.FabricConversionUtil;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import net.minecraft.server.level.ServerPlayer;
public class Fabric1170PlatformPlayer extends Fabric1161PlatformPlayer {
public Fabric1170PlatformPlayer(ServerPlayer player) {
super(player);
}
@Override
public void setGameMode(GameMode gameMode) {
fabricPlayer.setGameMode(FabricConversionUtil.toFabricGameMode(gameMode));
}
}
@@ -1,22 +0,0 @@
{
"schemaVersion": 1,
"id": "grimac-mc1171",
"version": "${version}",
"name": "GrimAC for 1.17+ built against 1.17.1",
"description": "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0.",
"authors": [
"GrimAC"
],
"license": "GPLv3",
"environment": "server",
"entrypoints": {
"grimMainLoad": [
"ac.grim.grimac.platform.fabric.mc1171.GrimACFabric1170LoaderPlugin"
]
},
"accessWidener": "grimac.accesswidener",
"depends": {
"minecraft": ">=1.17",
"fabric-lifecycle-events-v1": "*"
}
}
@@ -1,3 +0,0 @@
accessWidener v2 named
accessible field net/minecraft/server/level/ServerLevel serverLevelData Lnet/minecraft/world/level/storage/ServerLevelData;
accessible field net/minecraft/commands/CommandSourceStack source Lnet/minecraft/commands/CommandSource;
-13
View File
@@ -1,13 +0,0 @@
dependencies {
minecraft("com.mojang:minecraft:1.19.4")
mappings(loom.officialMojangMappings())
compileOnly(project(":fabric:mc1161", configuration = "namedElements"))
compileOnly(project(":fabric:mc1171", configuration = "namedElements"))
modImplementation(fabricApi.module("fabric-lifecycle-events-v1", "0.87.2+1.19.4"))
modImplementation("me.lucko:fabric-permissions-api:0.3.1")
}
tasks.compileJava {
options.release.set(17)
}
@@ -1,14 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1194;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.mc1171.Fabric1171PlatformServer;
import net.minecraft.commands.CommandSourceStack;
public class Fabric1190PlatformServer extends Fabric1171PlatformServer {
@Override
public void dispatchCommand(Sender sender, String command) {
CommandSourceStack commandSource = GrimACFabricLoaderPlugin.LOADER.getFabricSenderFactory().reverse(sender);
GrimACFabricLoaderPlugin.FABRIC_SERVER.getCommands().performPrefixedCommand(commandSource, command);
}
}
@@ -1,53 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1194;
import ac.grim.grimac.platform.fabric.AbstractFabricPlatformServer;
import ac.grim.grimac.platform.api.manager.CommandAdapter;
import ac.grim.grimac.platform.fabric.mc1161.command.Fabric1161PlayerSelectorAdapter;
import ac.grim.grimac.platform.fabric.command.FabricPlayerSelectorParser;
import ac.grim.grimac.platform.fabric.manager.FabricParserDescriptorFactory;
import ac.grim.grimac.platform.fabric.mc1171.GrimACFabric1170LoaderPlugin;
import ac.grim.grimac.platform.fabric.mc1171.player.Fabric1170PlatformPlayer;
import ac.grim.grimac.platform.fabric.mc1194.convert.Fabric1190MessageUtil;
import ac.grim.grimac.platform.fabric.mc1194.entity.Fabric1194GrimEntity;
import ac.grim.grimac.platform.fabric.mc1194.player.Fabric1193PlatformInventory;
import ac.grim.grimac.platform.fabric.mc1161.player.Fabric1161PlatformInventory;
import ac.grim.grimac.platform.fabric.mc1161.util.convert.Fabric1140ConversionUtil;
import ac.grim.grimac.platform.fabric.player.FabricPlatformPlayerFactory;
import ac.grim.grimac.platform.fabric.utils.convert.IFabricConversionUtil;
import ac.grim.grimac.platform.fabric.utils.message.IFabricMessageUtil;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
public class GrimACFabric1190LoaderPlugin extends GrimACFabric1170LoaderPlugin {
public GrimACFabric1190LoaderPlugin() {
this(
new FabricParserDescriptorFactory(
new FabricPlayerSelectorParser<>(Fabric1161PlayerSelectorAdapter::new)
),
new FabricPlatformPlayerFactory(
Fabric1170PlatformPlayer::new,
Fabric1194GrimEntity::new,
PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_19_2)
? Fabric1193PlatformInventory::new : Fabric1161PlatformInventory::new
),
new Fabric1190PlatformServer(),
new Fabric1190MessageUtil(),
new Fabric1140ConversionUtil()
);
}
protected GrimACFabric1190LoaderPlugin(
CommandAdapter parserDescriptorFactory,
FabricPlatformPlayerFactory platformPlayerFactory,
AbstractFabricPlatformServer platformServer,
IFabricMessageUtil fabricMessageUtil,
IFabricConversionUtil fabricConversionUtil) {
super(parserDescriptorFactory, platformPlayerFactory, platformServer, fabricMessageUtil, fabricConversionUtil);
}
@Override
public ServerVersion getNativeVersion() {
return ServerVersion.V_1_19_4;
}
}
@@ -1,11 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1194.convert;
import ac.grim.grimac.platform.fabric.mc1161.util.convert.Fabric1161MessageUtil;
import net.minecraft.network.chat.Component;
public class Fabric1190MessageUtil extends Fabric1161MessageUtil {
@Override
public Component textLiteral(String message) {
return Component.literal(message);
}
}
@@ -1,37 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1194.entity;
import ac.grim.grimac.platform.fabric.mc1171.entity.Fabric1170GrimEntity;
import ac.grim.grimac.platform.fabric.utils.thread.FabricFutureUtil;
import ac.grim.grimac.utils.math.Location;
import java.util.EnumSet;
import java.util.concurrent.CompletableFuture;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.RelativeMovement;
public class Fabric1194GrimEntity extends Fabric1170GrimEntity {
public Fabric1194GrimEntity(Entity entity) {
super(entity);
}
@Override
public CompletableFuture<Boolean> teleportAsync(Location location) {
return FabricFutureUtil.supplySync(() -> {
if (entity.getLevel() instanceof ServerLevel) {
entity.teleportTo(
(ServerLevel) location.getWorld(),
location.getX(),
location.getY(),
location.getZ(),
EnumSet.noneOf(RelativeMovement.class), // todo change to match paper? Do they do this?
location.getYaw(),
location.getPitch()
);
return true;
}
return false;
});
}
}
@@ -1,18 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1194.player;
import ac.grim.grimac.platform.fabric.mc1161.player.Fabric1161PlatformInventory;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.MenuType;
public class Fabric1193PlatformInventory extends Fabric1161PlatformInventory {
public Fabric1193PlatformInventory(ServerPlayer player) {
super(player);
}
@Override
protected ResourceLocation getScreenID(MenuType<?> type) {
return BuiltInRegistries.MENU.getKey(type);
}
}
@@ -1,22 +0,0 @@
{
"schemaVersion": 1,
"id": "grimac-mc1194",
"version": "${version}",
"name": "GrimAC for 1.19+ built against 1.19.4",
"description": "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0.",
"authors": [
"GrimAC"
],
"license": "GPLv3",
"environment": "server",
"entrypoints": {
"grimMainLoad": [
"ac.grim.grimac.platform.fabric.mc1194.GrimACFabric1190LoaderPlugin"
]
},
"accessWidener": "grimac.accesswidener",
"depends": {
"minecraft": ">=1.19",
"fabric-lifecycle-events-v1": "*"
}
}
@@ -1,3 +0,0 @@
accessWidener v2 named
accessible field net/minecraft/server/level/ServerLevel serverLevelData Lnet/minecraft/world/level/storage/ServerLevelData;
accessible field net/minecraft/commands/CommandSourceStack source Lnet/minecraft/commands/CommandSource;
-10
View File
@@ -1,10 +0,0 @@
dependencies {
minecraft("com.mojang:minecraft:1.20.5")
mappings(loom.officialMojangMappings())
compileOnly(project(":fabric:mc1161", configuration = "namedElements"))
compileOnly(project(":fabric:mc1171", configuration = "namedElements"))
compileOnly(project(":fabric:mc1194", configuration = "namedElements"))
modImplementation(fabricApi.module("fabric-lifecycle-events-v1", "0.97.8+1.20.5"))
modImplementation("me.lucko:fabric-permissions-api:0.3.1")
}
@@ -1,22 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1205;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.mc1194.Fabric1190PlatformServer;
import net.minecraft.commands.CommandSourceStack;
public class Fabric1203PlatformServer extends Fabric1190PlatformServer {
// TODO (Cross-platform) implement proper bukkit equivalent for getting TPS over time
@Override
public double getTPS() {
return Math.min(1000.0 / GrimACFabricLoaderPlugin.FABRIC_SERVER.getCurrentSmoothedTickTime(), GrimACFabricLoaderPlugin.FABRIC_SERVER.tickRateManager().tickrate());
}
// Return type changed from int -> void in 1.20.3
@Override
public void dispatchCommand(Sender sender, String command) {
CommandSourceStack commandSource = GrimACFabricLoaderPlugin.LOADER.getFabricSenderFactory().reverse(sender);
GrimACFabricLoaderPlugin.FABRIC_SERVER.getCommands().performPrefixedCommand(commandSource, command);
}
}
@@ -1,44 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1205;
import ac.grim.grimac.platform.fabric.command.FabricPlayerSelectorParser;
import ac.grim.grimac.platform.fabric.manager.FabricParserDescriptorFactory;
import ac.grim.grimac.platform.fabric.mc1171.player.Fabric1170PlatformPlayer;
import ac.grim.grimac.platform.fabric.mc1194.Fabric1190PlatformServer;
import ac.grim.grimac.platform.fabric.mc1194.GrimACFabric1190LoaderPlugin;
import ac.grim.grimac.platform.fabric.mc1194.player.Fabric1193PlatformInventory;
import ac.grim.grimac.platform.fabric.mc1205.convert.Fabric1200MessageUtil;
import ac.grim.grimac.platform.fabric.mc1205.convert.Fabric1205ConversionUtil;
import ac.grim.grimac.platform.fabric.mc1194.entity.Fabric1194GrimEntity;
import ac.grim.grimac.platform.fabric.mc1205.player.Fabric1202PlatformPlayer;
import ac.grim.grimac.platform.fabric.mc1161.command.Fabric1161PlayerSelectorAdapter;
import ac.grim.grimac.platform.fabric.mc1161.util.convert.Fabric1140ConversionUtil;
import ac.grim.grimac.platform.fabric.player.FabricPlatformPlayerFactory;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import io.github.retrooper.packetevents.factory.fabric.FabricPacketEventsAPI;
public class GrimACFabric1200LoaderPlugin extends GrimACFabric1190LoaderPlugin {
public GrimACFabric1200LoaderPlugin() {
super(
new FabricParserDescriptorFactory(
new FabricPlayerSelectorParser<>(Fabric1161PlayerSelectorAdapter::new)
),
new FabricPlatformPlayerFactory(
FabricPacketEventsAPI.getServerAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_20_1)
? Fabric1202PlatformPlayer::new : Fabric1170PlatformPlayer::new,
Fabric1194GrimEntity::new,
Fabric1193PlatformInventory::new
),
FabricPacketEventsAPI.getServerAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_20_2)
? new Fabric1203PlatformServer() : new Fabric1190PlatformServer(),
new Fabric1200MessageUtil(),
FabricPacketEventsAPI.getServerAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_20_4)
? new Fabric1205ConversionUtil() : new Fabric1140ConversionUtil()
);
}
@Override
public ServerVersion getNativeVersion() {
return ServerVersion.V_1_20_5;
}
}
@@ -1,12 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1205.convert;
import ac.grim.grimac.platform.fabric.mc1194.convert.Fabric1190MessageUtil;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.network.chat.Component;
public class Fabric1200MessageUtil extends Fabric1190MessageUtil {
@Override
public void sendMessage(CommandSourceStack target, Component message, boolean overlay) {
target.sendSuccess(() -> message, overlay);
}
}
@@ -1,51 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1205.convert;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.utils.convert.IFabricConversionUtil;
import ac.grim.grimac.utils.anticheat.LogUtil;
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import io.github.retrooper.packetevents.adventure.serializer.gson.GsonComponentSerializer;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import net.kyori.adventure.text.Component;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.RegistryFriendlyByteBuf;
public class Fabric1205ConversionUtil implements IFabricConversionUtil {
public ItemStack fromFabricItemStack(net.minecraft.world.item.ItemStack fabricStack) {
if (fabricStack.isEmpty()) {
return ItemStack.EMPTY;
}
// Allocate a ByteBuf
ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer();
try {
// Obtain the DynamicRegistryManager (you need to provide this from your context)
RegistryAccess registryManager = GrimACFabricLoaderPlugin.FABRIC_SERVER.registryAccess(); // Replace with actual method to get registry manager
// Create a RegistryByteBuf
RegistryFriendlyByteBuf registryByteBuf = new RegistryFriendlyByteBuf(buffer, registryManager);
// Encode the ItemStack using the appropriate PacketCodec
net.minecraft.world.item.ItemStack.STREAM_CODEC.encode(registryByteBuf, fabricStack);
// Create a PacketWrapper to read the ItemStack back (if needed)
PacketWrapper<?> wrapper = PacketWrapper.createUniversalPacketWrapper(buffer);
return wrapper.readItemStack();
} catch (Exception e) {
// Handle encoding errors
LogUtil.error("Failed to encode ItemStack: {}" + fabricStack, e);
return ItemStack.EMPTY;
} finally {
// Release the ByteBuf to prevent memory leaks
ByteBufHelper.release(buffer);
}
}
// TODO proper registry support?
public net.minecraft.network.chat.Component toNativeText(Component component) {
return net.minecraft.network.chat.Component.Serializer.fromJson(GsonComponentSerializer.gson().serializeToTree(component), RegistryAccess.EMPTY);
}
}
@@ -1,16 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1205.player;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.mc1171.player.Fabric1170PlatformPlayer;
import net.minecraft.server.level.ServerPlayer;
public class Fabric1202PlatformPlayer extends Fabric1170PlatformPlayer {
public Fabric1202PlatformPlayer(ServerPlayer player) {
super(player);
}
@Override
public void kickPlayer(String textReason) {
fabricPlayer.connection.disconnect(GrimACFabricLoaderPlugin.LOADER.getFabricMessageUtils().textLiteral(textReason));
}
}
@@ -1,22 +0,0 @@
{
"schemaVersion": 1,
"id": "grimac-mc1205",
"version": "${version}",
"name": "GrimAC for 1.20+ built against 1.20.5",
"description": "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0.",
"authors": [
"GrimAC"
],
"license": "GPLv3",
"environment": "server",
"entrypoints": {
"grimMainLoad": [
"ac.grim.grimac.platform.fabric.mc1205.GrimACFabric1200LoaderPlugin"
]
},
"accessWidener": "grimac.accesswidener",
"depends": {
"minecraft": ">=1.20",
"fabric-lifecycle-events-v1": "*"
}
}
@@ -1,3 +0,0 @@
accessWidener v2 named
accessible field net/minecraft/server/level/ServerLevel serverLevelData Lnet/minecraft/world/level/storage/ServerLevelData;
accessible field net/minecraft/commands/CommandSourceStack source Lnet/minecraft/commands/CommandSource;
-17
View File
@@ -1,17 +0,0 @@
dependencies {
minecraft("com.mojang:minecraft:1.21.6")
mappings(loom.officialMojangMappings())
compileOnly(project(":fabric:mc1161", configuration = "namedElements"))
compileOnly(project(":fabric:mc1171", configuration = "namedElements"))
compileOnly(project(":fabric:mc1194", configuration = "namedElements"))
compileOnly(project(":fabric:mc1205", configuration = "namedElements"))
modImplementation(fabricApi.module("fabric-lifecycle-events-v1", "0.128.1+1.21.6"))
modImplementation("me.lucko:fabric-permissions-api:0.4.0")
include("me.lucko:fabric-permissions-api:0.4.0")
}
tasks.compileJava {
options.release.set(21)
}
@@ -1,43 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1216;
import ac.grim.grimac.platform.fabric.mc1216.command.Fabric1212PlayerSelectorAdapter;
import ac.grim.grimac.platform.fabric.command.FabricPlayerSelectorParser;
import ac.grim.grimac.platform.fabric.manager.FabricParserDescriptorFactory;
import ac.grim.grimac.platform.fabric.mc1194.GrimACFabric1190LoaderPlugin;
import ac.grim.grimac.platform.fabric.mc1194.entity.Fabric1194GrimEntity;
import ac.grim.grimac.platform.fabric.mc1194.player.Fabric1193PlatformInventory;
import ac.grim.grimac.platform.fabric.mc1205.Fabric1203PlatformServer;
import ac.grim.grimac.platform.fabric.mc1205.convert.Fabric1200MessageUtil;
import ac.grim.grimac.platform.fabric.mc1205.convert.Fabric1205ConversionUtil;
import ac.grim.grimac.platform.fabric.mc1216.convert.Fabric1216ConversionUtil;
import ac.grim.grimac.platform.fabric.mc1216.player.Fabric1212PlatformPlayer;
import ac.grim.grimac.platform.fabric.mc1216.player.Fabric1215PlatformInventory;
import ac.grim.grimac.platform.fabric.player.FabricPlatformPlayerFactory;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
public class GrimACFabric1212LoaderPlugin extends GrimACFabric1190LoaderPlugin {
public GrimACFabric1212LoaderPlugin() {
super(
new FabricParserDescriptorFactory(
new FabricPlayerSelectorParser<>(Fabric1212PlayerSelectorAdapter::new)
),
new FabricPlatformPlayerFactory(
Fabric1212PlatformPlayer::new,
Fabric1194GrimEntity::new,
PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_21_4)
? Fabric1215PlatformInventory::new : Fabric1193PlatformInventory::new
),
new Fabric1203PlatformServer(),
new Fabric1200MessageUtil(),
PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_21_5)
? new Fabric1216ConversionUtil() : new Fabric1205ConversionUtil()
);
}
@Override
public ServerVersion getNativeVersion() {
return ServerVersion.V_1_21_6;
}
}
@@ -1,19 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1216.command;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.mc1161.command.Fabric1161PlayerSelectorAdapter;
import org.incendo.cloud.minecraft.modded.data.SinglePlayerSelector;
public class Fabric1212PlayerSelectorAdapter extends Fabric1161PlayerSelectorAdapter {
public Fabric1212PlayerSelectorAdapter(SinglePlayerSelector fabricSelector) {
super(fabricSelector);
}
// 1.21.2 .getCommandSource() moves from entity to player
@Override
public Sender getSinglePlayer() {
return GrimACFabricLoaderPlugin.LOADER.getFabricSenderFactory().map(fabricSelector.single().createCommandSourceStack());
}
}
@@ -1,18 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1216.convert;
import com.mojang.serialization.JsonOps;
import io.github.retrooper.packetevents.adventure.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.Component;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.chat.ComponentSerialization;
public class Fabric1216ConversionUtil extends ac.grim.grimac.platform.fabric.mc1205.convert.Fabric1205ConversionUtil {
@Override
public net.minecraft.network.chat.Component toNativeText(Component component) {
return ComponentSerialization.CODEC.decode(
RegistryAccess.EMPTY.createSerializationContext(JsonOps.INSTANCE),
GsonComponentSerializer.gson().serializeToTree(component)
).getOrThrow(IllegalArgumentException::new).getFirst();
}
}
@@ -1,40 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1216.player;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.mc1205.player.Fabric1202PlatformPlayer;
import ac.grim.grimac.platform.fabric.utils.thread.FabricFutureUtil;
import ac.grim.grimac.utils.math.Location;
import java.util.EnumSet;
import java.util.concurrent.CompletableFuture;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Relative;
public class Fabric1212PlatformPlayer extends Fabric1202PlatformPlayer {
public Fabric1212PlatformPlayer(ServerPlayer player) {
super(player);
}
@Override
public Sender getSender() {
return GrimACFabricLoaderPlugin.LOADER.getFabricSenderFactory().map(fabricPlayer.createCommandSourceStack());
}
@Override
public CompletableFuture<Boolean> teleportAsync(Location location) {
return FabricFutureUtil.supplySync(() -> {
fabricPlayer.teleportTo(
(ServerLevel) location.getWorld(),
location.getX(),
location.getY(),
location.getZ(),
EnumSet.noneOf(Relative.class), // todo change to match paper? Do they do this?
location.getYaw(),
location.getPitch(),
true
);
return true;
});
}
}
@@ -1,23 +0,0 @@
package ac.grim.grimac.platform.fabric.mc1216.player;
import ac.grim.grimac.platform.fabric.mc1194.player.Fabric1193PlatformInventory;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.MenuType;
public class Fabric1215PlatformInventory extends Fabric1193PlatformInventory {
public Fabric1215PlatformInventory(ServerPlayer player) {
super(player);
}
@Override
protected ResourceLocation getScreenID(MenuType<?> type) {
return BuiltInRegistries.MENU.getKey(type);
}
@Override
protected boolean isPlayerCreative() {
return fabricPlayer.isCreative();
}
}
@@ -1,22 +0,0 @@
{
"schemaVersion": 1,
"id": "grimac-mc1215",
"version": "${version}",
"name": "GrimAC for 1.21.2+ built against 1.21.5",
"description": "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0.",
"authors": [
"GrimAC"
],
"license": "GPLv3",
"environment": "server",
"entrypoints": {
"grimMainLoad": [
"ac.grim.grimac.platform.fabric.mc1216.GrimACFabric1212LoaderPlugin"
]
},
"accessWidener": "grimac.accesswidener",
"depends": {
"minecraft": ">=1.21.2",
"fabric-lifecycle-events-v1": "*"
}
}
@@ -1,3 +0,0 @@
accessWidener v2 named
accessible field net/minecraft/server/level/ServerLevel serverLevelData Lnet/minecraft/world/level/storage/ServerLevelData;
accessible field net/minecraft/commands/CommandSourceStack source Lnet/minecraft/commands/CommandSource;
@@ -1,33 +0,0 @@
package ac.grim.grimac.platform.fabric;
import ac.grim.grimac.platform.api.PlatformServer;
import ac.grim.grimac.platform.api.sender.Sender;
import com.mojang.authlib.GameProfile;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.commands.CommandSourceStack;
import org.jetbrains.annotations.Nullable;
public abstract class AbstractFabricPlatformServer implements PlatformServer {
@Override
public String getPlatformImplementationString() {
// Return the Fabric server version
return "Fabric " + FabricLoader.getInstance().getModContainer("fabricloader").orElseThrow().getMetadata().getVersion().getFriendlyString() + " (MC: " + GrimACFabricLoaderPlugin.FABRIC_SERVER.getServerVersion() + ")";
}
@Override
public Sender getConsoleSender() {
CommandSourceStack consoleSource = GrimACFabricLoaderPlugin.FABRIC_SERVER.createCommandSourceStack();
return GrimACFabricLoaderPlugin.LOADER.getFabricSenderFactory().map(consoleSource);
}
@Override
public void registerOutgoingPluginChannel(String name) {
throw new UnsupportedOperationException();
}
@Nullable
public GameProfile getProfileByName(String name) {
return GrimACFabricLoaderPlugin.FABRIC_SERVER.getProfileCache().get(name);
}
}
@@ -1,36 +0,0 @@
package ac.grim.grimac.platform.fabric;
import ac.grim.grimac.platform.api.PlatformPlugin;
import net.fabricmc.loader.api.ModContainer;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public class FabricPlatformPlugin implements PlatformPlugin {
private final @NotNull ModContainer modContainer;
@Contract(pure = true)
public FabricPlatformPlugin(@NotNull ModContainer modContainer) {
this.modContainer = Objects.requireNonNull(modContainer);
}
@Override
public boolean isEnabled() {
// Fabric mods are always "enabled" if loaded, as there's no explicit enable/disable state
// You can add custom logic if needed (e.g., check mod configuration)
return true;
}
@Override
public String getName() {
// Get the mod ID (unique identifier)
return modContainer.getMetadata().getId();
}
@Override
public String getVersion() {
// Get the mod version from metadata
return modContainer.getMetadata().getVersion().getFriendlyString();
}
}
@@ -1,51 +0,0 @@
package ac.grim.grimac.platform.fabric;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.manager.init.start.CommandRegister;
import ac.grim.grimac.platform.fabric.initables.FabricBStats;
import ac.grim.grimac.platform.fabric.initables.FabricTickEndEvent;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
import java.util.List;
public class GrimACFabricEntryPoint implements PreLaunchEntrypoint, ModInitializer {
@Override
public void onPreLaunch() {
}
@Override
public void onInitialize() {
FabricLoader loader = FabricLoader.getInstance();
String chainLoadEntryPointName = "grimMainLoad";
// Collect grimMainLoad entrypoints and sort by version
List<GrimACFabricLoaderPlugin> mainChainLoadEntryPoints = loader.getEntrypoints(chainLoadEntryPointName, GrimACFabricLoaderPlugin.class);
mainChainLoadEntryPoints.sort((a, b) -> b.getNativeVersion().getProtocolVersion() - a.getNativeVersion().getProtocolVersion());
// Get entrypoint for newest sub-version and execute it
GrimACFabricLoaderPlugin platformLoader = mainChainLoadEntryPoints.get(0);
GrimACFabricLoaderPlugin.LOADER = platformLoader;
// On Fabric we have to register commands earlier, and cannot register them when server is no longer null
GrimAPI.INSTANCE.load(
platformLoader,
new FabricBStats(),
new FabricTickEndEvent()
);
CommandRegister.registerCommands(platformLoader.getCommandManager());
ServerLifecycleEvents.SERVER_STARTING.register(server -> {
GrimACFabricLoaderPlugin.FABRIC_SERVER = server;
GrimAPI.INSTANCE.start();
});
ServerLifecycleEvents.SERVER_STOPPING.register((server) -> {
GrimAPI.INSTANCE.stop();
platformLoader.getScheduler().shutdown();
});
}
}
@@ -1,142 +0,0 @@
package ac.grim.grimac.platform.fabric;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.GrimAPIProvider;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.events.GrimExtensionManager;
import ac.grim.grimac.platform.api.PlatformLoader;
import ac.grim.grimac.platform.api.manager.*;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.api.sender.SenderFactory;
import ac.grim.grimac.platform.fabric.manager.*;
import ac.grim.grimac.platform.fabric.player.FabricPlatformPlayerFactory;
import ac.grim.grimac.platform.fabric.resolver.FabricResolverRegistrar;
import ac.grim.grimac.platform.fabric.scheduler.FabricPlatformScheduler;
import ac.grim.grimac.platform.fabric.sender.FabricSenderFactory;
import ac.grim.grimac.platform.fabric.utils.convert.IFabricConversionUtil;
import ac.grim.grimac.platform.fabric.utils.message.IFabricMessageUtil;
import ac.grim.grimac.utils.lazy.LazyHolder;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.PacketEventsAPI;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import lombok.Getter;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.execution.ExecutionCoordinator;
import org.incendo.cloud.fabric.FabricServerCommandManager;
public abstract class GrimACFabricLoaderPlugin implements PlatformLoader {
public static MinecraftServer FABRIC_SERVER;
public static GrimACFabricLoaderPlugin LOADER;
protected final LazyHolder<FabricPlatformScheduler> scheduler = LazyHolder.simple(FabricPlatformScheduler::new);
// Since we JiJ PacketEvents and depend on it on Fabric, we can always just get the API instance since it loads firsts
protected final PacketEventsAPI<?> packetEvents = PacketEvents.getAPI();
protected final LazyHolder<FabricSenderFactory> senderFactory = LazyHolder.simple(FabricSenderFactory::new);
protected final LazyHolder<CommandManager<Sender>> commandManager = LazyHolder.simple(this::createCommandManager);
protected final LazyHolder<ItemResetHandler> itemResetHandler = LazyHolder.simple(FabricItemResetHandler::new);
protected final GrimPlugin plugin;
@Getter
protected final PlatformPluginManager pluginManager = new FabricPlatformPluginManager();
@Getter
protected final MessagePlaceHolderManager messagePlaceHolderManager = new FabricMessagePlaceHolderManager();
protected final LazyHolder<FabricPermissionRegistrationManager> fabricPermissionRegistrationManager = LazyHolder.simple(FabricPermissionRegistrationManager::new);
protected final CommandAdapter parserFactory;
protected final FabricPlatformPlayerFactory playerFactory;
protected final AbstractFabricPlatformServer platformServer;
@Getter
protected final IFabricConversionUtil fabricConversionUtil;
protected final IFabricMessageUtil fabricMessageUtil;
public GrimACFabricLoaderPlugin(
CommandAdapter parserDescriptorFactory,
FabricPlatformPlayerFactory playerFactory,
AbstractFabricPlatformServer platformServer,
IFabricMessageUtil fabricMessageUtil,
IFabricConversionUtil fabricConversionUtil
) {
this.parserFactory = parserDescriptorFactory;
this.playerFactory = playerFactory;
this.platformServer = platformServer;
this.fabricMessageUtil = fabricMessageUtil;
this.fabricConversionUtil = fabricConversionUtil;
GrimExtensionManager extensionManager = GrimAPI.INSTANCE.getExtensionManager();
new FabricResolverRegistrar(extensionManager).registerAll();
plugin = extensionManager.getPlugin("GrimAC");
}
@Override
public FabricPlatformScheduler getScheduler() {
return scheduler.get();
}
@Override
public PacketEventsAPI<?> getPacketEvents() {
return packetEvents;
}
@Override
public CommandManager<Sender> getCommandManager() {
return commandManager.get();
}
@Override
public ItemResetHandler getItemResetHandler() {
return itemResetHandler.get();
}
@Override
public SenderFactory<CommandSourceStack> getSenderFactory() {
return senderFactory.get();
}
@Override
public GrimPlugin getPlugin() {
return plugin;
}
@Override
public void registerAPIService() {
GrimAPIProvider.init(GrimAPI.INSTANCE.getExternalAPI());
}
@Override
public PermissionRegistrationManager getPermissionManager() {
return fabricPermissionRegistrationManager.get();
}
private CommandManager<Sender> createCommandManager() {
return new FabricServerCommandManager<>(
ExecutionCoordinator.simpleCoordinator(),
senderFactory.get()
);
}
public FabricSenderFactory getFabricSenderFactory() {
return senderFactory.get();
}
@Override
public CommandAdapter getCommandAdapter() {
return parserFactory;
}
@Override
public FabricPlatformPlayerFactory getPlatformPlayerFactory() {
return playerFactory;
}
@Override
public AbstractFabricPlatformServer getPlatformServer() {
return platformServer;
}
public IFabricMessageUtil getFabricMessageUtils() {
return fabricMessageUtil;
}
public abstract ServerVersion getNativeVersion();
}
@@ -1,35 +0,0 @@
package ac.grim.grimac.platform.fabric.command;
import ac.grim.grimac.platform.api.command.AbstractPlayerSelectorParser;
import ac.grim.grimac.platform.api.command.PlayerSelector;
import lombok.RequiredArgsConstructor;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.minecraft.modded.data.SinglePlayerSelector;
import org.incendo.cloud.minecraft.modded.parser.VanillaArgumentParsers;
import org.incendo.cloud.parser.ParserDescriptor;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
@RequiredArgsConstructor
public class FabricPlayerSelectorParser<C> extends AbstractPlayerSelectorParser<C> {
private final Function<SinglePlayerSelector, PlayerSelector> selectorSupplier;
@Override
public ParserDescriptor<C, PlayerSelector> descriptor() {
return createDescriptor();
}
@Override
protected ParserDescriptor<C, ?> getPlatformSpecificDescriptor() {
return VanillaArgumentParsers.singlePlayerSelectorParser();
}
@Override
protected CompletableFuture<PlayerSelector> adaptToCommonSelector(CommandContext<C> context, Object platformSpecificSelector) {
return CompletableFuture.completedFuture(
selectorSupplier.apply((SinglePlayerSelector) platformSpecificSelector)
);
}
}
@@ -1,66 +0,0 @@
package ac.grim.grimac.platform.fabric.entity;
import ac.grim.grimac.platform.api.entity.GrimEntity;
import ac.grim.grimac.platform.api.world.PlatformWorld;
import ac.grim.grimac.utils.math.Location;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.UUID;
import net.minecraft.world.entity.Entity;
public abstract class AbstractFabricGrimEntity implements GrimEntity {
protected final Entity entity;
public AbstractFabricGrimEntity(Entity entity) {
this.entity = Objects.requireNonNull(entity);
}
@Override
public UUID getUniqueId() {
return entity.getUUID();
}
@Override
public boolean eject() {
if (entity.isVehicle()) {
entity.ejectPassengers();
return true;
}
return false;
}
@Override
public @NotNull Entity getNative() {
return this.entity;
}
@Override
public PlatformWorld getWorld() {
return (PlatformWorld) entity.level;
}
@Override
public Location getLocation() {
return new Location(
this.getWorld(),
this.entity.getX(),
this.entity.getY(),
this.entity.getZ(),
this.entity.getViewYRot(1.0F),
this.entity.getViewXRot(1.0F)
);
}
@Override
public double distanceSquared(double oX, double oY, double oZ) {
double x = this.entity.getX();
double y = this.entity.getY();
double z = this.entity.getZ();
double distX = (x - oX) * (x - oX);
double distY = (y - oY) * (y - oY);
double distZ = (z - oZ) * (z - oZ);
return distX + distY + distZ;
}
}
@@ -1,25 +0,0 @@
package ac.grim.grimac.platform.fabric.initables;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.manager.init.start.StartableInitable;
import ac.grim.grimac.manager.init.stop.StoppableInitable;
import ac.grim.grimac.platform.fabric.utils.metrics.MetricsFabric;
import ac.grim.grimac.utils.anticheat.Constants;
public class FabricBStats implements StartableInitable, StoppableInitable {
private MetricsFabric metricsFabric;
@Override
public void start() {
try {
metricsFabric = new MetricsFabric(GrimAPI.INSTANCE.getGrimPlugin(), Constants.BSTATS_PLUGIN_ID);
} catch (Exception ignored) {}
}
@Override
public void stop() {
if (metricsFabric != null)
metricsFabric.shutdown();
}
}
@@ -1,31 +0,0 @@
package ac.grim.grimac.platform.fabric.initables;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.manager.init.start.AbstractTickEndEvent;
import ac.grim.grimac.player.GrimPlayer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.server.MinecraftServer;
public class FabricTickEndEvent extends AbstractTickEndEvent {
@Override
public void start() {
if (!super.shouldInjectEndTick()) {
return;
}
// Register the end-of-tick callback
ServerTickEvents.END_SERVER_TICK.register(this::onEndServerTick);
}
private void onEndServerTick(MinecraftServer server) {
tickAllPlayers();
}
private void tickAllPlayers() {
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
if (player.disableGrim) continue;
super.onEndOfTick(player);
}
}
}
@@ -1,32 +0,0 @@
package ac.grim.grimac.platform.fabric.manager;
import ac.grim.grimac.platform.api.manager.ItemResetHandler;
import ac.grim.grimac.platform.api.player.PlatformPlayer;
import ac.grim.grimac.platform.fabric.utils.convert.FabricConversionUtil;
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
import net.minecraft.server.level.ServerPlayer;
import org.jetbrains.annotations.Nullable;
public class FabricItemResetHandler implements ItemResetHandler {
@Override
public void resetItemUsage(@Nullable PlatformPlayer player) {
if (player != null) {
((ServerPlayer) player.getNative()).stopUsingItem();
}
}
@Override
public @Nullable InteractionHand getItemUsageHand(@Nullable PlatformPlayer platformPlayer) {
if (platformPlayer == null) {
return null;
}
ServerPlayer player = (ServerPlayer) platformPlayer.getNative();
return player.isUsingItem() ? FabricConversionUtil.fromFabricHand(player.getUsedItemHand()) : null;
}
@Override
public boolean isUsingItem(@Nullable PlatformPlayer player) {
return player != null && ((ServerPlayer) player.getNative()).isUsingItem();
}
}
@@ -1,15 +0,0 @@
package ac.grim.grimac.platform.fabric.manager;
import ac.grim.grimac.platform.api.manager.MessagePlaceHolderManager;
import ac.grim.grimac.platform.api.player.PlatformPlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class FabricMessagePlaceHolderManager implements MessagePlaceHolderManager {
// PlaceHolderAPI doesn't exist on Fabric and no chosen replacement for the platform yet
@Override
public @NotNull String replacePlaceholders(@Nullable PlatformPlayer player, @NotNull String string) {
return string;
}
}
@@ -1,42 +0,0 @@
package ac.grim.grimac.platform.fabric.manager;
import ac.grim.grimac.platform.api.command.PlayerSelector;
import ac.grim.grimac.platform.api.manager.CommandAdapter;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.command.FabricPlayerSelectorParser;
import lombok.RequiredArgsConstructor;
import net.minecraft.server.level.ServerPlayer;
import org.incendo.cloud.parser.ParserDescriptor;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.suggestion.SuggestionProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@RequiredArgsConstructor
public class FabricParserDescriptorFactory implements CommandAdapter {
private final FabricPlayerSelectorParser<Sender> fabricPlayerSelectorParser;
@Override
public ParserDescriptor<Sender, PlayerSelector> singlePlayerSelectorParser() {
return fabricPlayerSelectorParser.descriptor();
}
// TODO (Cross-platform) brigadier style & better suggestions
@Override
public SuggestionProvider<Sender> onlinePlayerSuggestions() {
return (context, input) -> {
List<Suggestion> suggestions = new ArrayList<>();
// TODO Support Vanish mods?
for (ServerPlayer player : GrimACFabricLoaderPlugin.FABRIC_SERVER.getPlayerList().getPlayers()) {
suggestions.add(Suggestion.suggestion(player.getName().getString()));
}
return CompletableFuture.completedFuture(suggestions);
};
}
}
@@ -1,31 +0,0 @@
package ac.grim.grimac.platform.fabric.manager;
import ac.grim.grimac.platform.api.manager.PermissionRegistrationManager;
import ac.grim.grimac.platform.api.permissions.PermissionDefaultValue;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.sender.FabricSenderFactory;
import me.lucko.fabric.api.permissions.v0.Permissions;
public class FabricPermissionRegistrationManager implements PermissionRegistrationManager {
private final FabricSenderFactory fabricSenderFactory = GrimACFabricLoaderPlugin.LOADER.getFabricSenderFactory();
public FabricPermissionRegistrationManager() {
registerPermission("grim.exempt", PermissionDefaultValue.FALSE);
registerPermission("grim.nosetback", PermissionDefaultValue.FALSE);
registerPermission("grim.nomodifypacket", PermissionDefaultValue.FALSE);
registerPermission("grim.nosetback", PermissionDefaultValue.FALSE);
registerPermission("grim.alerts.enable-on-join", PermissionDefaultValue.FALSE);
registerPermission("grim.verbose.enable-on-join", PermissionDefaultValue.FALSE);
registerPermission("grim.brand.enable-on-join", PermissionDefaultValue.FALSE);
registerPermission("grim.alerts.enable-on-join.silent", PermissionDefaultValue.FALSE);
registerPermission("grim.verbose.enable-on-join.silent", PermissionDefaultValue.FALSE);
registerPermission("grim.brand.enable-on-join.silent", PermissionDefaultValue.FALSE);
}
@Override
public void registerPermission(String name, PermissionDefaultValue defaultValue) {
fabricSenderFactory.registerPermissionDefault(name, defaultValue);
Permissions.check(GrimACFabricLoaderPlugin.FABRIC_SERVER.createCommandSourceStack(), name);
}
}
@@ -1,32 +0,0 @@
package ac.grim.grimac.platform.fabric.manager;
import ac.grim.grimac.platform.api.PlatformPlugin;
import ac.grim.grimac.platform.api.manager.PlatformPluginManager;
import ac.grim.grimac.platform.fabric.FabricPlatformPlugin;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import java.util.Collection;
import java.util.Optional;
public class FabricPlatformPluginManager implements PlatformPluginManager {
@Override
public PlatformPlugin[] getPlugins() {
// Get all loaded mods from Fabric Loader
Collection<ModContainer> mods = FabricLoader.getInstance().getAllMods();
PlatformPlugin[] plugins = new PlatformPlugin[mods.size()];
int i = 0;
for (ModContainer mod : mods) {
plugins[i++] = new FabricPlatformPlugin(mod);
}
return plugins;
}
@Override
public PlatformPlugin getPlugin(String pluginName) {
// Look up a mod by its ID
Optional<ModContainer> mod = FabricLoader.getInstance().getModContainer(pluginName);
return mod.map(FabricPlatformPlugin::new).orElse(null);
}
}
@@ -1,22 +0,0 @@
package ac.grim.grimac.platform.fabric.mixins;
import ac.grim.grimac.platform.api.world.PlatformChunk;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.chunk.LevelChunk;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(LevelChunk.class)
@Implements(@Interface(iface = PlatformChunk.class, prefix = "grimac$"))
abstract class LevelChunkMixin {
public int grimac$getBlockID(int x, int y, int z) {
LevelChunk chunk = (LevelChunk) (Object) this;
return Block.getId(chunk.getBlockState(new BlockPos(
chunk.getPos().getMinBlockX() + x,
y,
chunk.getPos().getMinBlockZ() + z
)));
}
}
@@ -1,47 +0,0 @@
package ac.grim.grimac.platform.fabric.mixins;
import ac.grim.grimac.platform.api.world.PlatformChunk;
import ac.grim.grimac.platform.api.world.PlatformWorld;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.*;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.storage.ServerLevelData;
@Mixin(ServerLevel.class)
@Implements(@Interface(iface = PlatformWorld.class, prefix = "grimac$"))
abstract class ServerLevelMixin implements LevelAccessor {
@Shadow public @Final ServerLevelData serverLevelData;
public boolean grimac$isChunkLoaded(int chunkX, int chunkZ) {
return hasChunk(chunkX, chunkZ);
}
public WrappedBlockState grimac$getBlockAt(int x, int y, int z) {
return WrappedBlockState.getByGlobalId(
Block.getId(getBlockState(new BlockPos(x, y, z)))
);
}
public String grimac$getName() {
return serverLevelData.getLevelName();
}
public @Nullable UUID grimac$getUID() {
throw new UnsupportedOperationException();
}
public PlatformChunk grimac$getChunkAt(int currChunkX, int currChunkZ) {
return (PlatformChunk) getChunk(currChunkX, currChunkZ);
}
public boolean grimac$isLoaded() {
return GrimACFabricLoaderPlugin.FABRIC_SERVER.getLevel(getLevel().dimension()) != null;
}
}
@@ -1,18 +0,0 @@
package ac.grim.grimac.platform.fabric.mixins;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.platform.fabric.player.FabricPlatformPlayerFactory;
import net.minecraft.server.level.ServerPlayer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
// Works from 1.14 - latest (1.21.5)
@Mixin(ServerPlayer.class)
abstract class ServerPlayerMixin {
@Inject(method = "restoreFrom", at = @At("TAIL"))
private void onRestoreFrom(ServerPlayer oldPlayer, boolean alive, CallbackInfo ci) {
((FabricPlatformPlayerFactory) GrimAPI.INSTANCE.getPlatformPlayerFactory()).replaceNativePlayer(oldPlayer.getUUID(), (ServerPlayer) (Object) this);
}
}
@@ -1,65 +0,0 @@
package ac.grim.grimac.platform.fabric.player;
import ac.grim.grimac.platform.api.player.PlatformInventory;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.utils.convert.IFabricConversionUtil;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Inventory;
public abstract class AbstractFabricPlatformInventory implements PlatformInventory {
private static final IFabricConversionUtil fabricConversionUtil = GrimACFabricLoaderPlugin.LOADER.getFabricConversionUtil();
protected ServerPlayer fabricPlayer;
protected Inventory inventory;
public AbstractFabricPlatformInventory(ServerPlayer player) {
this.fabricPlayer = player;
this.inventory = player.inventory;
}
@Override
public ItemStack getItemInHand() {
return fabricConversionUtil.fromFabricItemStack(inventory.getSelected());
}
@Override
public ItemStack getItemInOffHand() {
return fabricConversionUtil.fromFabricItemStack(inventory.getItem(40));
}
@Override
public ItemStack getStack(int bukkitSlot, int vanillaSlot) {
return fabricConversionUtil.fromFabricItemStack(inventory.getItem(bukkitSlot));
}
@Override
public ItemStack getHelmet() {
return fabricConversionUtil.fromFabricItemStack(inventory.getItem(39));
}
@Override
public ItemStack getChestplate() {
return fabricConversionUtil.fromFabricItemStack(inventory.getItem(38));
}
@Override
public ItemStack getLeggings() {
return fabricConversionUtil.fromFabricItemStack(inventory.getItem(37));
}
@Override
public ItemStack getBoots() {
return fabricConversionUtil.fromFabricItemStack(inventory.getItem(36));
}
@Override
public ItemStack[] getContents() {
ItemStack[] items = new ItemStack[inventory.getContainerSize()];
for (int i = 0; i < inventory.getContainerSize(); i++) {
items[i] = fabricConversionUtil.fromFabricItemStack(inventory.getItem(i));
}
return items;
}
}
@@ -1,160 +0,0 @@
package ac.grim.grimac.platform.fabric.player;
import ac.grim.grimac.platform.api.entity.GrimEntity;
import ac.grim.grimac.platform.api.player.PlatformInventory;
import ac.grim.grimac.platform.api.player.PlatformPlayer;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.entity.AbstractFabricGrimEntity;
import ac.grim.grimac.platform.fabric.utils.convert.FabricConversionUtil;
import ac.grim.grimac.utils.common.arguments.CommonGrimArguments;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.util.Vector3d;
import net.kyori.adventure.text.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public abstract class AbstractFabricPlatformPlayer extends AbstractFabricGrimEntity implements PlatformPlayer {
protected ServerPlayer fabricPlayer;
protected final AbstractFabricPlatformInventory inventory;
private final @Nullable User user;
public AbstractFabricPlatformPlayer(ServerPlayer player) {
super(player);
this.fabricPlayer = player;
this.inventory = GrimACFabricLoaderPlugin.LOADER.getPlatformPlayerFactory().getPlatformInventory(player);
if (CommonGrimArguments.USE_CHAT_FAST_BYPASS.value()) {
Object channel = PacketEvents.getAPI().getProtocolManager().getChannel(fabricPlayer.getUUID());
this.user = PacketEvents.getAPI().getProtocolManager().getUser(channel);
} else {
this.user = null;
}
}
@Override
public void kickPlayer(String textReason) {
fabricPlayer.connection.disconnect(GrimACFabricLoaderPlugin.LOADER.getFabricMessageUtils().textLiteral(textReason));
}
@Override
public boolean isSneaking() {
return fabricPlayer.isShiftKeyDown();
}
@Override
public void setSneaking(boolean isSneaking) {
fabricPlayer.setShiftKeyDown(isSneaking);
}
@Override
public boolean hasPermission(String permission) {
return getSender().hasPermission(permission);
}
@Override
public boolean hasPermission(String permission, boolean defaultIfUnset) {
return getSender().hasPermission(permission, defaultIfUnset);
}
@Override
public void sendMessage(String message) {
if (CommonGrimArguments.USE_CHAT_FAST_BYPASS.value() && user != null) {
user.sendMessage(message);
} else {
fabricPlayer.displayClientMessage(GrimACFabricLoaderPlugin.LOADER.getFabricMessageUtils().textLiteral(message), false);
}
}
@Override
public void sendMessage(Component message) {
if (CommonGrimArguments.USE_CHAT_FAST_BYPASS.value() && user != null) {
user.sendMessage(message);
} else {
fabricPlayer.displayClientMessage(GrimACFabricLoaderPlugin.LOADER.getFabricConversionUtil().toNativeText(message), false);
}
}
@Override
public boolean isOnline() {
return !fabricPlayer.hasDisconnected();
}
@Override
public String getName() {
return fabricPlayer.getName().getString();
}
@Override
public void updateInventory() {
fabricPlayer.containerMenu.broadcastChanges();
}
@Override
public Vector3d getPosition() {
return new Vector3d(fabricPlayer.getX(), fabricPlayer.getY(), fabricPlayer.getZ());
}
@Override
public PlatformInventory getInventory() {
return inventory;
}
@Override
public GrimEntity getVehicle() {
Entity vehicle = fabricPlayer.getVehicle();
return vehicle != null ? GrimACFabricLoaderPlugin.LOADER.getPlatformPlayerFactory().getPlatformEntity(vehicle) : null;
}
@Override
public GameMode getGameMode() {
return FabricConversionUtil.fromFabricGameMode(fabricPlayer.gameMode.getGameModeForPlayer());
}
@Override
public void setGameMode(GameMode gameMode) {
fabricPlayer.setGameMode(FabricConversionUtil.toFabricGameMode(gameMode));
}
@Override
public UUID getUniqueId() {
return fabricPlayer.getUUID();
}
@Override
public boolean isExternalPlayer() {
return false;
}
@Override
public void sendPluginMessage(String channelName, byte[] byteArray) {
// You might want to use Fabric's networking system here
// CustomPayloadS2CPacket packet = new CustomPayloadS2CPacket(
// Identifier.of(channelName),
// new PacketByteBuf(Unpooled.wrappedBuffer(byteArray))
// );
// fabricPlayer.networkHandler.sendPacket(packet);
throw new UnsupportedOperationException();
}
@Override
public void replaceNativePlayer(Object nativePlayerObject) {
this.inventory.fabricPlayer = (ServerPlayer) nativePlayerObject;
this.inventory.inventory = ((ServerPlayer) nativePlayerObject).inventory;
this.fabricPlayer = (ServerPlayer) nativePlayerObject;
}
@Override
public @NotNull ServerPlayer getNative() {
return this.fabricPlayer;
}
@Override
public boolean isDead() {
return fabricPlayer.isDeadOrDying();
}
}
@@ -1,26 +0,0 @@
package ac.grim.grimac.platform.fabric.player;
import ac.grim.grimac.platform.api.player.OfflinePlatformPlayer;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
@RequiredArgsConstructor
@Getter
public class FabricOfflinePlatformPlayer implements OfflinePlatformPlayer {
private final @NotNull UUID uniqueId;
private final @NotNull String name;
@Override
public boolean isOnline() {
return GrimACFabricLoaderPlugin.FABRIC_SERVER.getPlayerList().getPlayer(uniqueId) != null;
}
@Override
public boolean equals(Object o) {
return o instanceof OfflinePlatformPlayer player && this.getUniqueId().equals(player.getUniqueId());
}
}
@@ -1,99 +0,0 @@
package ac.grim.grimac.platform.fabric.player;
import ac.grim.grimac.platform.api.entity.GrimEntity;
import ac.grim.grimac.platform.api.player.AbstractPlatformPlayerFactory;
import ac.grim.grimac.platform.api.player.OfflinePlatformPlayer;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import com.mojang.authlib.GameProfile;
import lombok.RequiredArgsConstructor;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import org.jetbrains.annotations.NotNull;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Function;
@RequiredArgsConstructor
public class FabricPlatformPlayerFactory extends AbstractPlatformPlayerFactory<ServerPlayer> {
private final Map<UUID, OfflinePlatformPlayer> offlinePlatformPlayerCache = new HashMap<>();
private final Function<ServerPlayer, AbstractFabricPlatformPlayer> getPlayerFunction;
private final Function<Entity, GrimEntity> getEntityFunction;
private final Function<ServerPlayer, AbstractFabricPlatformInventory> getPlayerInventoryFunction;
@Override
protected ServerPlayer getNativePlayer(@NotNull UUID uuid) {
return GrimACFabricLoaderPlugin.FABRIC_SERVER.getPlayerList().getPlayer(uuid);
}
@Override
protected ServerPlayer getNativePlayer(@NotNull String name) {
return GrimACFabricLoaderPlugin.FABRIC_SERVER.getPlayerList().getPlayerByName(name);
}
@Override
protected AbstractFabricPlatformPlayer createPlatformPlayer(@NotNull ServerPlayer nativePlayer) {
return getPlayerFunction.apply(nativePlayer);
}
@Override
protected UUID getPlayerUUID(@NotNull ServerPlayer nativePlayer) {
return nativePlayer.getUUID();
}
@Override
protected Collection<ServerPlayer> getNativeOnlinePlayers() {
// Get the list of online players from the server
return GrimACFabricLoaderPlugin.FABRIC_SERVER.getPlayerList().getPlayers();
}
@Override
public OfflinePlatformPlayer getOfflineFromUUID(@NotNull UUID uuid) {
return null;
}
@Override
public OfflinePlatformPlayer getOfflineFromName(@NotNull String name) {
OfflinePlatformPlayer result = this.getFromName(name);
if (result == null) {
GameProfile profile = null;
// Only fetch an online UUID in online mode
// TODO (cross-platform) add a config option for "offline-mode" servers with online-mode behind a proxy
if (GrimACFabricLoaderPlugin.FABRIC_SERVER.usesAuthentication()) {
// THIS CAN BLOCK THE CALLING THREAD!
profile = GrimACFabricLoaderPlugin.LOADER.getPlatformServer().getProfileByName(name);
}
result = this.getOfflinePlayer(profile != null
// Use the GameProfile even when we get a UUID so we ensure we still have a name
? profile
// Make an OfflinePlayer using an offline mode UUID since the name has no profile
: new GameProfile(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)), name)
);
} else {
this.offlinePlatformPlayerCache.remove(result.getUniqueId());
}
return result;
}
public OfflinePlatformPlayer getOfflinePlayer(GameProfile profile) {
OfflinePlatformPlayer player = new FabricOfflinePlatformPlayer(profile.getId(), profile.getName());
this.offlinePlatformPlayerCache.put(profile.getId(), player);
return player;
}
@Override
public void replaceNativePlayer(@NotNull UUID uuid, @NotNull ServerPlayer serverPlayerEntity) {
super.cache.getPlayer(uuid).replaceNativePlayer(serverPlayerEntity);
}
public AbstractFabricPlatformInventory getPlatformInventory(ServerPlayer serverPlayerEntity) {
return getPlayerInventoryFunction.apply(serverPlayerEntity);
}
public GrimEntity getPlatformEntity(Entity entity) {
return getEntityFunction.apply(entity);
}
}
@@ -1,185 +0,0 @@
package ac.grim.grimac.platform.fabric.resolver;
import ac.grim.grimac.api.plugin.BasicGrimPlugin;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.events.GrimExtensionManager;
import ac.grim.grimac.platform.fabric.utils.message.JULoggerFactory;
import lombok.RequiredArgsConstructor;
import net.fabricmc.api.*;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.entrypoint.EntrypointContainer;
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
import net.fabricmc.loader.api.metadata.Person;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* Manages the registration of Fabric-specific resolvers with the GrimExtensionManager.
* This class is designed to be instantiated once during plugin startup.
*/
@RequiredArgsConstructor
public final class FabricResolverRegistrar {
private final GrimExtensionManager extensionManager;
// Cache to ensure we only create one GrimPlugin wrapper per Fabric ModContainer.
private final Map<ModContainer, GrimPlugin> modContainerCache = new ConcurrentHashMap<>();
private final Map<Class<?>, GrimPlugin> classCache = new ConcurrentHashMap<>();
private final Map<Object, GrimPlugin> entrypointCache = new ConcurrentHashMap<>();
/**
* Registers all the Fabric-specific resolvers in order of performance (fastest to slowest).
*/
public void registerAll() {
extensionManager.setFailureHandler(this::createFailureException);
extensionManager.registerResolver(this::resolveModContainer);
extensionManager.registerResolver(this::resolveStringId);
extensionManager.registerResolver(this::resolveEntrypointInstance);
extensionManager.registerResolver(this::resolveClass);
}
/**
* Create a shared, reusable function to handle the core logic of
* converting a Fabric ModContainer to a GrimPlugin wrapper.
*/
private GrimPlugin resolveMod(ModContainer modContainer) {
return modContainerCache.computeIfAbsent(modContainer, container -> {
net.fabricmc.loader.api.metadata.ModMetadata metadata = container.getMetadata();
String folderName = metadata.getId().equals("grimac") ? metadata.getName() : metadata.getId();
return new BasicGrimPlugin(
JULoggerFactory.createLogger(metadata.getName()),
new File(FabricLoader.getInstance().getConfigDir().toFile(), folderName),
metadata.getVersion().getFriendlyString(),
metadata.getDescription(),
metadata.getAuthors().stream().map(Person::getName).collect(Collectors.toList())
);
});
}
/**
* Resolver #0: Direct ModContainer (fastest)
*/
private GrimPlugin resolveModContainer(Object context) {
return (context instanceof ModContainer mc) ? resolveMod(mc) : null;
}
/**
* Resolver #1: String Mod ID (very fast)
*/
private GrimPlugin resolveStringId(Object context) {
if (context instanceof String modId) {
// Mod IDs are enforced to always be fully lowercase
return FabricLoader.getInstance().getModContainer(modId.toLowerCase(Locale.ROOT))
.map(this::resolveMod)
.orElse(null);
}
return null;
}
/**
* Resolver #2: Mod Entrypoint Instance (slower, but cached)
*/
private GrimPlugin resolveEntrypointInstance(Object context) {
// We only care about potential entrypoint instances
if (context instanceof ModInitializer || context instanceof PreLaunchEntrypoint || context instanceof ClientModInitializer || context instanceof DedicatedServerModInitializer) {
return entrypointCache.computeIfAbsent(context, this::findEntrypoint);
}
return null;
}
private GrimPlugin findEntrypoint(Object key) {
GrimPlugin result;
if ((result = findEntrypoint(key, ModInitializer.class, "main")) != null) return result;
if ((result = findEntrypoint(key, PreLaunchEntrypoint.class, "preLaunch")) != null) return result;
if ((result = findEntrypoint(key, ClientModInitializer.class, "client")) != null) return result;
if ((result = findEntrypoint(key, DedicatedServerModInitializer.class, "server")) != null) return result;
return null;
}
private <T> GrimPlugin findEntrypoint(Object context, Class<T> entrypointClass, String entrypointKey) {
if (entrypointClass.isInstance(context)) {
for (EntrypointContainer<T> container : FabricLoader.getInstance().getEntrypointContainers(entrypointKey, entrypointClass)) {
if (container.getEntrypoint() == context) {
return resolveMod(container.getProvider());
}
}
}
return null;
}
/**
* Resolver #3: Class object (slowest - involves I/O, but cached)
*/
private GrimPlugin resolveClass(Object context) {
if (context instanceof Class<?> clazz) {
return classCache.computeIfAbsent(clazz, this::findClassProvider);
}
return null;
}
private GrimPlugin findClassProvider(Class<?> c) {
try {
// 1. Get the path to the physical JAR/directory the class was loaded from.
// This is our ground truth.
java.security.CodeSource codeSource = c.getProtectionDomain().getCodeSource();
if (codeSource == null) return null;
java.net.URL sourceUrl = codeSource.getLocation();
if (sourceUrl == null) return null;
Path sourcePath = Paths.get(sourceUrl.toURI());
// 2. Iterate through all mods and check if the class's source path
// matches the physical path of the mod's container.
for (ModContainer modContainer : FabricLoader.getInstance().getAllMods()) {
for (Path modRootPath : modContainer.getRootPaths()) {
URI modUri = modRootPath.toUri();
Path modPhysicalPath = null;
// 3. Determine the mod's physical path based on its URI scheme.
if ("file".equals(modUri.getScheme())) {
modPhysicalPath = modRootPath;
} else if ("jar".equals(modUri.getScheme())) {
String schemeSpecificPart = modUri.getSchemeSpecificPart();
int separatorIndex = schemeSpecificPart.indexOf("!/");
if (separatorIndex != -1) {
String jarUriString = schemeSpecificPart.substring(0, separatorIndex);
modPhysicalPath = Paths.get(new URI(jarUriString));
}
}
// 4. Perform the reliable file comparison.
if (modPhysicalPath != null && Files.isSameFile(modPhysicalPath, sourcePath)) {
return resolveMod(modContainer);
}
}
}
} catch (URISyntaxException | IOException | NullPointerException e) {
// Fail gracefully.
return null;
}
return null;
}
private RuntimeException createFailureException(Object failedContext) {
String message = """
Failed to resolve GrimPlugin context from the provided object of type '%s'.
Please ensure you are passing one of the following:
- The main instance of your mod (e.g., 'this' from your ModInitializer class).
- The mod ID as a String (e.g., "my-mod-id").
- Any Class from your mod's JAR file (e.g., MyListener.class).
- A pre-existing GrimPlugin instance.
""".formatted(failedContext.getClass().getName());
return new IllegalArgumentException(message);
}
}
@@ -1,119 +0,0 @@
package ac.grim.grimac.platform.fabric.scheduler;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.scheduler.AsyncScheduler;
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class FabricAsyncScheduler implements AsyncScheduler {
private final Map<Thread, InternalAsyncTask> asyncTasks = new HashMap<>();
private final GrimPlugin plugin;
record InternalAsyncTask(GrimPlugin plugin, Runnable runnable) {}
public FabricAsyncScheduler(GrimPlugin plugin) {
this.plugin = plugin;
}
@Override
public TaskHandle runNow(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
Thread thread = new Thread(task);
Runnable cancellationTask = () -> {
thread.interrupt();
asyncTasks.remove(thread);
};
asyncTasks.put(thread, new InternalAsyncTask(plugin, cancellationTask));
thread.start();
return new FabricTaskHandle(cancellationTask, false);
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, @NotNull TimeUnit timeUnit) {
long delayMillis = timeUnit.toMillis(delay);
Thread thread = new Thread(() -> {
try {
Thread.sleep(delayMillis);
task.run();
} catch (InterruptedException e) {
// Handle interruption
}
});
Runnable cancellationTask = () -> {
thread.interrupt();
asyncTasks.remove(thread);
};
asyncTasks.put(thread, new InternalAsyncTask(plugin, cancellationTask));
thread.start();
return new FabricTaskHandle(cancellationTask, false); // false for async
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, long period, @NotNull TimeUnit timeUnit) {
long delayMillis = timeUnit.toMillis(delay);
long periodMillis = timeUnit.toMillis(period);
Thread thread = new Thread(() -> {
try {
Thread.sleep(delayMillis);
while (!Thread.currentThread().isInterrupted()) {
task.run();
Thread.sleep(periodMillis);
}
} catch (InterruptedException e) {
// Handle interruption
}
});
Runnable cancellationTask = () -> {
thread.interrupt();
asyncTasks.remove(thread);
};
asyncTasks.put(thread, new InternalAsyncTask(plugin, cancellationTask));
thread.start();
return new FabricTaskHandle(cancellationTask, false); // false for async
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
return runAtFixedRate(plugin, task,
PlatformScheduler.convertTicksToTime(initialDelayTicks, TimeUnit.MILLISECONDS),
PlatformScheduler.convertTicksToTime(periodTicks, TimeUnit.MILLISECONDS),
TimeUnit.MILLISECONDS); // Convert ticks to milliseconds
}
@Override
public void cancel(@NotNull GrimPlugin plugin) {
// Cancel tasks only for the specified plugin
Iterator<Map.Entry<Thread, InternalAsyncTask>> iterator = asyncTasks.entrySet().iterator();
List<Runnable> cancellationTasks = new ArrayList<>();
while (iterator.hasNext()) {
Map.Entry<Thread, InternalAsyncTask> entry = iterator.next();
if (entry.getValue().plugin().equals(plugin)) {
cancellationTasks.add(entry.getValue().runnable());
iterator.remove();
}
}
for (Runnable cancellationTask : cancellationTasks) {
cancellationTask.run();
}
}
public void cancelAll() {
List<Runnable> cancellationTasks = asyncTasks.values().stream()
.map(InternalAsyncTask::runnable)
.toList();
asyncTasks.clear();
for (Runnable cancellationTask : cancellationTasks) {
cancellationTask.run();
}
}
}
@@ -1,85 +0,0 @@
package ac.grim.grimac.platform.fabric.scheduler;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.entity.GrimEntity;
import ac.grim.grimac.platform.api.scheduler.EntityScheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.server.MinecraftServer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class FabricEntityScheduler implements EntityScheduler {
// TODO (Cross-platform) (Threading) try to make this not Concurrent
private final Map<FabricPlatformScheduler.ScheduledTask, Runnable> taskMap = new ConcurrentHashMap<>();
private final GrimPlugin plugin;
public FabricEntityScheduler(GrimPlugin plugin) {
this.plugin = plugin;
ServerTickEvents.END_SERVER_TICK.register(this::handleTasks);
}
private void handleTasks(MinecraftServer server) {
FabricPlatformScheduler.handleSyncTasks(taskMap, server, plugin);
}
@Override
public void execute(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable run, @Nullable Runnable retired, long delay) {
runDelayed(entity, plugin, run, retired, delay);
}
@Override
public TaskHandle run(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired) {
return runDelayed(entity, plugin, task, retired, 0);
}
@Override
public TaskHandle runDelayed(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long delayTicks) {
FabricPlatformScheduler.ScheduledTask scheduledTask = new FabricPlatformScheduler.ScheduledTask(
() -> {
task.run();
if (retired != null && entity.isDead()) {
retired.run();
}
},
GrimACFabricLoaderPlugin.FABRIC_SERVER.getTickCount() + delayTicks,
0,
false,
plugin
);
Runnable cancellationTask = () -> taskMap.remove(scheduledTask);
taskMap.put(scheduledTask, cancellationTask);
return new FabricTaskHandle(cancellationTask, true); // true for sync
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long initialDelayTicks, long periodTicks) {
FabricPlatformScheduler.ScheduledTask scheduledTask = new FabricPlatformScheduler.ScheduledTask(
() -> {
task.run();
if (retired != null && entity.isDead()) {
retired.run();
}
},
GrimACFabricLoaderPlugin.FABRIC_SERVER.getTickCount() + initialDelayTicks,
periodTicks,
true,
plugin
);
Runnable cancellationTask = () -> taskMap.remove(scheduledTask);
taskMap.put(scheduledTask, cancellationTask);
return new FabricTaskHandle(cancellationTask, true); // true for sync
}
public void cancel(@NotNull GrimPlugin plugin) {
FabricPlatformScheduler.cancelPluginTasks(taskMap, plugin);
}
public void cancelAll() {
FabricPlatformScheduler.cancelAllTasks(taskMap);
}
}
@@ -1,76 +0,0 @@
package ac.grim.grimac.platform.fabric.scheduler;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.scheduler.GlobalRegionScheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.server.MinecraftServer;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class FabricGlobalRegionScheduler implements GlobalRegionScheduler {
// TODO (Cross-platform) (Threading) try to make this not Concurrent
private final Map<FabricPlatformScheduler.ScheduledTask, Runnable> taskMap = new ConcurrentHashMap<>();
private final GrimPlugin plugin;
public FabricGlobalRegionScheduler(GrimPlugin plugin) {
this.plugin = plugin;
// Register the task handler to run on server tick
ServerTickEvents.END_SERVER_TICK.register(this::handleTasks);
}
private void handleTasks(MinecraftServer server) {
FabricPlatformScheduler.handleSyncTasks(taskMap, server, plugin);
}
@Override
public void execute(@NotNull GrimPlugin plugin, @NotNull Runnable run) {
run(plugin, run);
}
@Override
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
return runDelayed(plugin, task, 0);
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay) {
FabricPlatformScheduler.ScheduledTask scheduledTask = new FabricPlatformScheduler.ScheduledTask(
task,
GrimACFabricLoaderPlugin.FABRIC_SERVER.getTickCount() + delay,
0,
false,
plugin
);
Runnable cancellationTask = () -> taskMap.remove(scheduledTask);
taskMap.put(scheduledTask, cancellationTask);
return new FabricTaskHandle(cancellationTask, true); // true for sync
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
FabricPlatformScheduler.ScheduledTask scheduledTask = new FabricPlatformScheduler.ScheduledTask(
task,
GrimACFabricLoaderPlugin.FABRIC_SERVER.getTickCount() + initialDelayTicks,
periodTicks,
true,
plugin
);
Runnable cancellationTask = () -> taskMap.remove(scheduledTask);
taskMap.put(scheduledTask, cancellationTask);
return new FabricTaskHandle(cancellationTask, true); // true for sync
}
@Override
public void cancel(@NotNull GrimPlugin plugin) {
FabricPlatformScheduler.cancelPluginTasks(taskMap, plugin);
}
// New method to cancel all tasks
public void cancelAll() {
FabricPlatformScheduler.cancelAllTasks(taskMap);
}
}
@@ -1,133 +0,0 @@
package ac.grim.grimac.platform.fabric.scheduler;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.scheduler.*;
import ac.grim.grimac.utils.anticheat.LogUtil;
import net.minecraft.server.MinecraftServer;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class FabricPlatformScheduler implements PlatformScheduler {
private final FabricAsyncScheduler asyncScheduler;
private final FabricGlobalRegionScheduler globalRegionScheduler;
private final FabricEntityScheduler entityScheduler;
private final FabricRegionScheduler regionScheduler;
public FabricPlatformScheduler() {
GrimPlugin plugin = GrimAPI.INSTANCE.getGrimPlugin();
this.asyncScheduler = new FabricAsyncScheduler(plugin);
this.globalRegionScheduler = new FabricGlobalRegionScheduler(plugin);
this.entityScheduler = new FabricEntityScheduler(plugin);
this.regionScheduler = new FabricRegionScheduler(plugin);
}
// Shared method to handle synchronous tasks
// Add this to FabricPlatformScheduler.java
public static final ThreadLocal<Boolean> EXECUTING_TASK = ThreadLocal.withInitial(() -> false);
protected static void handleSyncTasks(Map<ScheduledTask, Runnable> taskMap, MinecraftServer server, GrimPlugin plugin) {
Iterator<ScheduledTask> iterator = taskMap.keySet().iterator();
while (iterator.hasNext()) {
ScheduledTask task = iterator.next();
if (server.getTickCount() >= task.nextRunTick) {
try {
EXECUTING_TASK.set(true);
task.task.run();
} catch (Exception e) {
LogUtil.error("Error executing scheduled task ", e);
} finally {
EXECUTING_TASK.set(false);
}
if (task.isPeriodic) {
task.nextRunTick = server.getTickCount() + task.period;
} else {
iterator.remove();
}
}
}
}
// Cancel tasks for a specific plugin
protected static void cancelPluginTasks(Map<ScheduledTask, Runnable> taskMap, GrimPlugin plugin) {
Iterator<Map.Entry<ScheduledTask, Runnable>> iterator = taskMap.entrySet().iterator();
List<Runnable> cancellationTasks = new ArrayList<>();
while (iterator.hasNext()) {
Map.Entry<ScheduledTask, Runnable> entry = iterator.next();
if (entry.getKey().plugin.equals(plugin)) {
cancellationTasks.add(entry.getValue());
iterator.remove();
}
}
for (Runnable cancellationTask : cancellationTasks) {
cancellationTask.run();
}
}
// Cancel all tasks (renamed from cancelAllTasks)
protected static void cancelAllTasks(Map<?, Runnable> taskMap) {
List<Runnable> cancellationTasks = new ArrayList<>(taskMap.values());
taskMap.clear();
for (Runnable cancellationTask : cancellationTasks) {
cancellationTask.run();
}
}
protected static void scheduleTask(Map<ScheduledTask, Runnable> taskMap, GrimPlugin plugin, Runnable task, long initialDelayTicks, long periodTicks, boolean isPeriodic) {
}
@Override
public @NotNull AsyncScheduler getAsyncScheduler() {
return asyncScheduler;
}
@Override
public @NotNull GlobalRegionScheduler getGlobalRegionScheduler() {
return globalRegionScheduler;
}
@Override
public @NotNull EntityScheduler getEntityScheduler() {
return entityScheduler;
}
@Override
public @NotNull RegionScheduler getRegionScheduler() {
return regionScheduler;
}
/**
* Shuts down all schedulers and cancels all pending tasks.
* This method should be called when the server is shutting down.
*/
public void shutdown() {
asyncScheduler.cancelAll();
globalRegionScheduler.cancelAll();
entityScheduler.cancelAll();
regionScheduler.cancelAll();
}
protected static class ScheduledTask {
final Runnable task;
final long period;
final boolean isPeriodic;
final GrimPlugin plugin; // Add plugin reference
long nextRunTick;
ScheduledTask(Runnable task, long nextRunTick, long period, boolean isPeriodic, GrimPlugin plugin) {
this.task = task;
this.nextRunTick = nextRunTick;
this.period = period;
this.isPeriodic = isPeriodic;
this.plugin = plugin;
}
}
}
@@ -1,94 +0,0 @@
package ac.grim.grimac.platform.fabric.scheduler;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.scheduler.RegionScheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import ac.grim.grimac.platform.api.world.PlatformWorld;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.utils.math.Location;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.server.MinecraftServer;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class FabricRegionScheduler implements RegionScheduler {
// TODO (Cross-platform) (Threading) try to make this not Concurrent
private final Map<FabricPlatformScheduler.ScheduledTask, Runnable> taskMap = new ConcurrentHashMap<>();
private final GrimPlugin plugin;
public FabricRegionScheduler(GrimPlugin plugin) {
this.plugin = plugin;
ServerTickEvents.END_SERVER_TICK.register(this::handleTasks);
}
private void handleTasks(MinecraftServer server) {
FabricPlatformScheduler.handleSyncTasks(taskMap, server, plugin);
}
@Override
public void execute(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable run) {
run(plugin, world, chunkX, chunkZ, run);
}
@Override
public void execute(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable run) {
execute(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, run);
}
@Override
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task) {
return runDelayed(plugin, world, chunkX, chunkZ, task, 0);
}
@Override
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task) {
return run(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task);
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long delayTicks) {
FabricPlatformScheduler.ScheduledTask scheduledTask = new FabricPlatformScheduler.ScheduledTask(
task,
GrimACFabricLoaderPlugin.FABRIC_SERVER.getTickCount() + delayTicks,
0,
false,
plugin
);
Runnable cancellationTask = () -> taskMap.remove(scheduledTask);
taskMap.put(scheduledTask, cancellationTask);
return new FabricTaskHandle(cancellationTask, true);
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long delayTicks) {
return runDelayed(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, delayTicks);
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
FabricPlatformScheduler.ScheduledTask scheduledTask = new FabricPlatformScheduler.ScheduledTask(
task,
GrimACFabricLoaderPlugin.FABRIC_SERVER.getTickCount() + initialDelayTicks,
periodTicks,
true,
plugin
);
Runnable cancellationTask = () -> taskMap.remove(scheduledTask);
taskMap.put(scheduledTask, cancellationTask);
return new FabricTaskHandle(cancellationTask, true);
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
return runAtFixedRate(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, initialDelayTicks, periodTicks);
}
public void cancel(@NotNull GrimPlugin plugin) {
FabricPlatformScheduler.cancelPluginTasks(taskMap, plugin);
}
public void cancelAll() {
FabricPlatformScheduler.cancelAllTasks(taskMap);
}
}
@@ -1,28 +0,0 @@
package ac.grim.grimac.platform.fabric.scheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import lombok.Getter;
public class FabricTaskHandle implements TaskHandle {
private final Runnable cancellationTask;
@Getter
private boolean cancelled;
@Getter
private final boolean sync;
public FabricTaskHandle(Runnable cancellationTask) {
this.cancellationTask = cancellationTask;
this.sync = false;
}
public FabricTaskHandle(Runnable cancellationTask, boolean sync) {
this.cancellationTask = cancellationTask;
this.sync = sync;
}
@Override
public void cancel() {
this.cancellationTask.run();
this.cancelled = true;
}
}
@@ -1,111 +0,0 @@
package ac.grim.grimac.platform.fabric.sender;
import ac.grim.grimac.platform.api.permissions.PermissionDefaultValue;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.api.sender.SenderFactory;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import ac.grim.grimac.platform.fabric.utils.message.IFabricMessageUtil;
import me.lucko.fabric.api.permissions.v0.Permissions;
import net.fabricmc.fabric.api.util.TriState;
import net.kyori.adventure.text.Component;
import net.minecraft.commands.CommandSource;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.rcon.RconConsoleSource;
import org.incendo.cloud.SenderMapper;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class FabricSenderFactory extends SenderFactory<CommandSourceStack> implements SenderMapper<CommandSourceStack, Sender> {
private final Map<String, PermissionDefaultValue> permissionDefaults = new HashMap<>();
private static final IFabricMessageUtil fabricMessageUtils = GrimACFabricLoaderPlugin.LOADER.getFabricMessageUtils();
@Override
protected UUID getUniqueId(CommandSourceStack commandSource) {
if (commandSource.getEntity() != null) {
return commandSource.getEntity().getUUID();
}
return Sender.CONSOLE_UUID;
}
@Override
protected String getName(CommandSourceStack commandSource) {
String name = commandSource.getTextName();
if (commandSource.getEntity() != null && name.equals("Server")) {
return Sender.CONSOLE_NAME;
}
return name;
}
@Override
protected void sendMessage(CommandSourceStack sender, String message) {
fabricMessageUtils.sendMessage(sender, fabricMessageUtils.textLiteral(message), false);
}
@Override
protected void sendMessage(CommandSourceStack sender, Component message) {
fabricMessageUtils.sendMessage(sender, GrimACFabricLoaderPlugin.LOADER.getFabricConversionUtil().toNativeText(message), false);
}
@Override
protected boolean hasPermission(CommandSourceStack commandSource, String node) {
TriState permissionValue = Permissions.getPermissionValue(commandSource, node);
if (permissionValue != TriState.DEFAULT) {
return permissionValue.get();
}
// Check registered default value
PermissionDefaultValue defaultValue = permissionDefaults.get(node);
if (defaultValue == null) {
return permissionValue.get(); // Fallback to provided default if unset
}
return switch (defaultValue) {
case TRUE -> true;
case FALSE -> false;
case OP -> commandSource.hasPermission(GrimACFabricLoaderPlugin.FABRIC_SERVER.getOperatorUserPermissionLevel());
case NOT_OP -> !commandSource.hasPermission(GrimACFabricLoaderPlugin.FABRIC_SERVER.getOperatorUserPermissionLevel());
};
}
@Override
protected boolean hasPermission(CommandSourceStack commandSource, String node, boolean defaultIfUnset) {
return Permissions.check(commandSource, node, defaultIfUnset);
}
@Override
protected void performCommand(CommandSourceStack sender, String command) {
throw new UnsupportedOperationException();
}
@Override
protected boolean isConsole(CommandSourceStack sender) {
CommandSource output = sender.source;
return output == sender.getServer() || // Console
output.getClass() == RconConsoleSource.class || // Rcon
(output == CommandSource.NULL && sender.getTextName().isEmpty()); // Functions
}
@Override
protected boolean isPlayer(CommandSourceStack sender) {
return sender.getEntity() instanceof ServerPlayer;
}
@Override
public @NotNull Sender map(@NotNull CommandSourceStack base) {
return this.wrap(base);
}
@Override
public @NotNull CommandSourceStack reverse(@NotNull Sender mapped) {
return this.unwrap(mapped);
}
public void registerPermissionDefault(String permission, PermissionDefaultValue defaultValue) {
permissionDefaults.put(permission, defaultValue);
}
}
@@ -1,89 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.convert;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
import net.kyori.adventure.text.Component;
import net.minecraft.world.level.GameType;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
public abstract class FabricConversionUtil implements IFabricConversionUtil {
private IFabricConversionUtil fabricConversionUtilSupplier;
private final Function<net.minecraft.world.item.ItemStack, ItemStack> itemStackMapperFunction = (fabricStack) -> {
// if (fabricStack.isEmpty()) {
// return ItemStack.EMPTY;
// }
//
// // Allocate a ByteBuf
// ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer();
// try {
// // Obtain the DynamicRegistryManager (you need to provide this from your context)
// DynamicRegistryManager registryManager = GrimACFabricLoaderPlugin.FABRIC_SERVER.getRegistryManager(); // Replace with actual method to get registry manager
//
// // Create a RegistryByteBuf
// RegistryByteBuf registryByteBuf = new RegistryByteBuf(buffer, registryManager);
//
// // Encode the ItemStack using the appropriate PacketCodec
// net.minecraft.item.ItemStack.PACKET_CODEC.encode(registryByteBuf, fabricStack);
//
// // Create a PacketWrapper to read the ItemStack back (if needed)
// PacketWrapper<?> wrapper = PacketWrapper.createUniversalPacketWrapper(buffer);
// return wrapper.readItemStack();
// } catch (Exception e) {
// // Handle encoding errors
// LogUtil.error("Failed to encode ItemStack: {}" + fabricStack, e);
// return ItemStack.EMPTY;
// } finally {
// // Release the ByteBuf to prevent memory leaks
// ByteBufHelper.release(buffer);
// }
throw new UnsupportedOperationException();
};
private final Function<Component, net.minecraft.network.chat.Component> nativeTextMapperFunction = (component) -> {
throw new UnsupportedOperationException();
// Text.Serialization.fromJsonTree(GsonComponentSerializer.gson().serializeToTree(component), DynamicRegistryManager.EMPTY);
};
//
public ItemStack fromFabricItemStack(net.minecraft.world.item.ItemStack fabricStack) {
// return itemStackMapperFunction.apply(fabricStack);
return fabricConversionUtilSupplier.fromFabricItemStack(fabricStack);
}
public net.minecraft.network.chat.Component toNativeText(Component component) {
// return nativeTextMapperFunction.apply(component);
return fabricConversionUtilSupplier.toNativeText(component);
}
public static GameType toFabricGameMode(GameMode gameMode) {
return switch (gameMode) {
case CREATIVE -> GameType.CREATIVE;
case SURVIVAL -> GameType.SURVIVAL;
case ADVENTURE -> GameType.ADVENTURE;
case SPECTATOR -> GameType.SPECTATOR;
};
}
public static GameMode fromFabricGameMode(GameType fabricGameMode) {
return switch (fabricGameMode) {
case CREATIVE -> GameMode.CREATIVE;
case SURVIVAL -> GameMode.SURVIVAL;
case ADVENTURE -> GameMode.ADVENTURE;
case SPECTATOR -> GameMode.SPECTATOR;
default -> throw new IllegalArgumentException("Unknown Fabric GameMode: " + fabricGameMode);
};
}
@Contract(value = "null -> null; !null -> !null", pure = true)
public static @Nullable InteractionHand fromFabricHand(@Nullable net.minecraft.world.InteractionHand hand) {
return hand == null ? null : switch (hand) {
case OFF_HAND -> InteractionHand.OFF_HAND;
case MAIN_HAND -> InteractionHand.MAIN_HAND;
};
}
}
@@ -1,9 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.convert;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import net.kyori.adventure.text.Component;
public interface IFabricConversionUtil {
ItemStack fromFabricItemStack(net.minecraft.world.item.ItemStack fabricStack);
net.minecraft.network.chat.Component toNativeText(Component component);
}
@@ -1,9 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.message;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.network.chat.Component;
public interface IFabricMessageUtil {
Component textLiteral(String message);
void sendMessage(CommandSourceStack target, Component message, boolean overlay);
}
@@ -1,18 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.message;
import java.util.logging.Logger;
public class JULoggerFactory {
public static Logger createLogger(String name) {
try {
return new Slf4jBackedJULogger(name);
} catch (NoClassDefFoundError | Exception ignored) {
}
try {
return new Log4jBackedJULogger(name);
} catch (NoClassDefFoundError | Exception ignored) {
}
return Logger.getLogger(name);
}
}
@@ -1,47 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.message;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Log4jBackedJULogger extends Logger {
private final org.apache.logging.log4j.Logger log4jLogger;
protected Log4jBackedJULogger(String name) {
super(name, null);
this.log4jLogger = org.apache.logging.log4j.LogManager.getLogger(name);
}
@Override
public void log(Level level, String msg) {
if (level == Level.SEVERE) {
log4jLogger.error(msg);
} else if (level == Level.WARNING) {
log4jLogger.warn(msg);
} else if (level == Level.INFO) {
log4jLogger.info(msg);
} else if (level == Level.CONFIG || level == Level.FINE) {
log4jLogger.debug(msg);
} else if (level == Level.FINER || level == Level.FINEST) {
log4jLogger.trace(msg);
} else {
log4jLogger.info(msg);
}
}
@Override
public void log(Level level, String msg, Throwable thrown) {
if (level == Level.SEVERE) {
log4jLogger.error(msg, thrown);
} else if (level == Level.WARNING) {
log4jLogger.warn(msg, thrown);
} else if (level == Level.INFO) {
log4jLogger.info(msg, thrown);
} else if (level == Level.CONFIG || level == Level.FINE) {
log4jLogger.debug(msg, thrown);
} else if (level == Level.FINER || level == Level.FINEST) {
log4jLogger.trace(msg, thrown);
} else {
log4jLogger.info(msg, thrown);
}
}
}
@@ -1,51 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.message;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
public class Slf4jBackedJULogger extends Logger {
private final org.slf4j.Logger slf4jLogger;
private static final Marker MARKER = MarkerFactory.getMarker("JUL");
public Slf4jBackedJULogger(String name) {
super(name, null);
this.slf4jLogger = LoggerFactory.getLogger(name);
}
@Override
public void log(Level level, String msg) {
if (level == Level.SEVERE) {
slf4jLogger.error(MARKER, msg);
} else if (level == Level.WARNING) {
slf4jLogger.warn(MARKER, msg);
} else if (level == Level.INFO) {
slf4jLogger.info(MARKER, msg);
} else if (level == Level.CONFIG || level == Level.FINE) {
slf4jLogger.debug(MARKER, msg);
} else if (level == Level.FINER || level == Level.FINEST) {
slf4jLogger.trace(MARKER, msg);
} else {
slf4jLogger.info(MARKER, msg);
}
}
@Override
public void log(Level level, String msg, Throwable thrown) {
if (level.equals(Level.SEVERE)) {
slf4jLogger.error(MARKER, msg, thrown);
} else if (level.equals(Level.WARNING)) {
slf4jLogger.warn(MARKER, msg, thrown);
} else if (level.equals(Level.INFO)) {
slf4jLogger.info(MARKER, msg, thrown);
} else if (level.equals(Level.CONFIG) || level.equals(Level.FINE)) {
slf4jLogger.debug(MARKER, msg, thrown);
} else if (level.equals(Level.FINER) || level.equals(Level.FINEST)) {
slf4jLogger.trace(MARKER, msg, thrown);
} else {
slf4jLogger.info(MARKER, msg, thrown);
}
}
}
@@ -1,98 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.metrics;
import ac.grim.grimac.utils.anticheat.LogUtil;
import net.fabricmc.loader.api.FabricLoader;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
public class BStatsConfig {
private static final String HEADER = """
# bStats (https://bStats.org) collects some basic information for plugin authors, like how
# many people use their plugin and their total player count. It's recommended to keep bStats
# enabled, but if you're not comfortable with this, you can turn this setting off. There is no
# performance penalty associated with having metrics enabled, and data sent to bStats is fully
# anonymous.
""";
public static Config loadConfig() {
File bStatsFolder = new File(FabricLoader.getInstance().getConfigDir().toString(), "bStats");
File configFile = new File(bStatsFolder, "config.yml");
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
options.setPrettyFlow(true);
Yaml yaml = new Yaml(options);
Map<String, Object> data;
Config config = new Config();
try {
if (!configFile.exists()) {
bStatsFolder.mkdirs();
// Create default config
data = new LinkedHashMap<>();
data.put("enabled", true);
data.put("serverUuid", UUID.randomUUID().toString());
data.put("logFailedRequests", false);
data.put("logSentData", false);
data.put("logResponseStatusText", false);
// Write config with header
try (Writer writer = new OutputStreamWriter(new FileOutputStream(configFile), StandardCharsets.UTF_8)) {
writer.write(HEADER);
yaml.dump(data, writer);
}
} else {
// Load existing config
data = yaml.load(new FileInputStream(configFile));
if (data == null) {
data = new LinkedHashMap<>();
}
}
// Map the data to Config object
config.enabled = getBoolean(data, "enabled", true);
config.serverUuid = getString(data, "serverUuid", UUID.randomUUID().toString());
config.logFailedRequests = getBoolean(data, "logFailedRequests", false);
config.logSentData = getBoolean(data, "logSentData", false);
config.logResponseStatusText = getBoolean(data, "logResponseStatusText", false);
} catch (IOException e) {
LogUtil.error("Failed to load bStats config. Using default values.", e);
// Fallback to default values
config.enabled = true;
config.serverUuid = UUID.randomUUID().toString();
config.logFailedRequests = false;
config.logSentData = false;
config.logResponseStatusText = false;
}
return config;
}
private static boolean getBoolean(Map<String, Object> map, String key, boolean defaultValue) {
Object value = map.get(key);
return value instanceof Boolean ? (Boolean) value : defaultValue;
}
private static String getString(Map<String, Object> map, String key, String defaultValue) {
Object value = map.get(key);
return value instanceof String ? (String) value : defaultValue;
}
// Your existing Config class
public static class Config {
public boolean enabled = true;
public String serverUuid;
public boolean logFailedRequests = false;
public boolean logSentData = false;
public boolean logResponseStatusText = false;
}
}
@@ -1,37 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.metrics;
import java.util.function.BiConsumer;
public abstract class CustomChart {
private final String chartId;
protected CustomChart(String chartId) {
if (chartId == null) {
throw new IllegalArgumentException("chartId must not be null");
}
this.chartId = chartId;
}
public JsonObjectBuilder.JsonObject getRequestJsonObject(
BiConsumer<String, Throwable> errorLogger, boolean logErrors) {
JsonObjectBuilder builder = new JsonObjectBuilder();
builder.appendField("chartId", chartId);
try {
JsonObjectBuilder.JsonObject data = getChartData();
if (data == null) {
// If the data is null we don't send the chart.
return null;
}
builder.appendField("data", data);
} catch (Throwable t) {
if (logErrors) {
errorLogger.accept("Failed to get data for custom chart with id " + chartId, t);
}
return null;
}
return builder.build();
}
protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception;
}
@@ -1,210 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.metrics;
import java.util.Arrays;
import java.util.stream.Collectors;
/**
* An extremely simple JSON builder.
*
* <p>While this class is neither feature-rich nor the most performant one, it's sufficient enough
* for its use-case.
*/
public class JsonObjectBuilder {
private StringBuilder builder = new StringBuilder();
private boolean hasAtLeastOneField = false;
public JsonObjectBuilder() {
builder.append("{");
}
/**
* Escapes the given string like stated in <a href="https://www.ietf.org/rfc/rfc4627.txt">https://www.ietf.org/rfc/rfc4627.txt</a>.
*
* <p>This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'.
* Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n").
*
* @param value The value to escape.
* @return The escaped value.
*/
private static String escape(String value) {
final StringBuilder builder = new StringBuilder();
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
if (c == '"') {
builder.append("\\\"");
} else if (c == '\\') {
builder.append("\\\\");
} else if (c <= '\u000F') {
builder.append("\\u000").append(Integer.toHexString(c));
} else if (c <= '\u001F') {
builder.append("\\u00").append(Integer.toHexString(c));
} else {
builder.append(c);
}
}
return builder.toString();
}
/**
* Appends a null field to the JSON.
*
* @param key The key of the field.
* @return A reference to this object.
*/
public JsonObjectBuilder appendNull(String key) {
appendFieldUnescaped(key, "null");
return this;
}
/**
* Appends a string field to the JSON.
*
* @param key The key of the field.
* @param value The value of the field.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, String value) {
if (value == null) {
throw new IllegalArgumentException("JSON value must not be null");
}
appendFieldUnescaped(key, "\"" + escape(value) + "\"");
return this;
}
/**
* Appends an integer field to the JSON.
*
* @param key The key of the field.
* @param value The value of the field.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, int value) {
appendFieldUnescaped(key, String.valueOf(value));
return this;
}
/**
* Appends an object to the JSON.
*
* @param key The key of the field.
* @param object The object.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, JsonObject object) {
if (object == null) {
throw new IllegalArgumentException("JSON object must not be null");
}
appendFieldUnescaped(key, object.toString());
return this;
}
/**
* Appends a string array to the JSON.
*
* @param key The key of the field.
* @param values The string array.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, String[] values) {
if (values == null) {
throw new IllegalArgumentException("JSON values must not be null");
}
String escapedValues =
Arrays.stream(values)
.map(value -> "\"" + escape(value) + "\"")
.collect(Collectors.joining(","));
appendFieldUnescaped(key, "[" + escapedValues + "]");
return this;
}
/**
* Appends an integer array to the JSON.
*
* @param key The key of the field.
* @param values The integer array.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, int[] values) {
if (values == null) {
throw new IllegalArgumentException("JSON values must not be null");
}
String escapedValues =
Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(","));
appendFieldUnescaped(key, "[" + escapedValues + "]");
return this;
}
/**
* Appends an object array to the JSON.
*
* @param key The key of the field.
* @param values The integer array.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, JsonObject[] values) {
if (values == null) {
throw new IllegalArgumentException("JSON values must not be null");
}
String escapedValues =
Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(","));
appendFieldUnescaped(key, "[" + escapedValues + "]");
return this;
}
/**
* Appends a field to the object.
*
* @param key The key of the field.
* @param escapedValue The escaped value of the field.
*/
private void appendFieldUnescaped(String key, String escapedValue) {
if (builder == null) {
throw new IllegalStateException("JSON has already been built");
}
if (key == null) {
throw new IllegalArgumentException("JSON key must not be null");
}
if (hasAtLeastOneField) {
builder.append(",");
}
builder.append("\"").append(escape(key)).append("\":").append(escapedValue);
hasAtLeastOneField = true;
}
/**
* Builds the JSON string and invalidates this builder.
*
* @return The built JSON string.
*/
public JsonObject build() {
if (builder == null) {
throw new IllegalStateException("JSON has already been built");
}
JsonObject object = new JsonObject(builder.append("}").toString());
builder = null;
return object;
}
/**
* A super simple representation of a JSON object.
*
* <p>This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not
* allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String,
* JsonObject)}.
*/
public static class JsonObject {
private final String value;
private JsonObject(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
}
@@ -1,6 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.metrics;
public interface Metrics {
void shutdown();
}
@@ -1,278 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.metrics;
import org.jetbrains.annotations.NotNull;
import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.zip.GZIPOutputStream;
public class MetricsBase {
/**
* The version of the Metrics class.
*/
public static final String METRICS_VERSION = "3.1.0";
private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s";
private final ScheduledExecutorService scheduler;
private final String platform;
private final String serverUuid;
private final int serviceId;
private final Consumer<JsonObjectBuilder> appendPlatformDataConsumer;
private final Consumer<JsonObjectBuilder> appendServiceDataConsumer;
private final Consumer<Runnable> submitTaskConsumer;
private final Supplier<Boolean> checkServiceEnabledSupplier;
private final BiConsumer<String, Throwable> errorLogger;
private final Consumer<String> infoLogger;
private final boolean logErrors;
private final boolean logSentData;
private final boolean logResponseStatusText;
private final Set<CustomChart> customCharts = new HashSet<>();
private final boolean enabled;
/**
* Creates a new MetricsBase class instance.
*
* @param platform The platform of the service.
* @param serviceId The id of the service.
* @param serverUuid The server uuid.
* @param enabled Whether or not data sending is enabled.
* @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
* appends all platform-specific data.
* @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
* appends all service-specific data.
* @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be
* used to delegate the data collection to a another thread to prevent errors caused by
* concurrency. Can be {@code null}.
* @param checkServiceEnabledSupplier A supplier to check if the service is still enabled.
* @param errorLogger A consumer that accepts log message and an error.
* @param infoLogger A consumer that accepts info log messages.
* @param logErrors Whether or not errors should be logged.
* @param logSentData Whether or not the sent data should be logged.
* @param logResponseStatusText Whether or not the response status text should be logged.
* @param skipRelocateCheck Whether or not the relocate check should be skipped.
*/
public MetricsBase(
String platform,
String serverUuid,
int serviceId,
boolean enabled,
Consumer<JsonObjectBuilder> appendPlatformDataConsumer,
Consumer<JsonObjectBuilder> appendServiceDataConsumer,
Consumer<Runnable> submitTaskConsumer,
Supplier<Boolean> checkServiceEnabledSupplier,
BiConsumer<String, Throwable> errorLogger,
Consumer<String> infoLogger,
boolean logErrors,
boolean logSentData,
boolean logResponseStatusText,
boolean skipRelocateCheck) {
this.scheduler = getScheduledThreadPoolExecutor();
this.platform = platform;
this.serverUuid = serverUuid;
this.serviceId = serviceId;
this.enabled = enabled;
this.appendPlatformDataConsumer = appendPlatformDataConsumer;
this.appendServiceDataConsumer = appendServiceDataConsumer;
this.submitTaskConsumer = submitTaskConsumer;
this.checkServiceEnabledSupplier = checkServiceEnabledSupplier;
this.errorLogger = errorLogger;
this.infoLogger = infoLogger;
this.logErrors = logErrors;
this.logSentData = logSentData;
this.logResponseStatusText = logResponseStatusText;
if (!skipRelocateCheck) {
checkRelocation();
}
if (enabled) {
// WARNING: Removing the option to opt-out will get your plugin banned from
// bStats
startSubmitting();
}
}
private static @NotNull ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor() {
ScheduledThreadPoolExecutor scheduler =
new ScheduledThreadPoolExecutor(
1,
task -> {
Thread thread = new Thread(task, "bStats-Metrics");
thread.setDaemon(true);
return thread;
});
// We want delayed tasks (non-periodic) that will execute in the future to be
// cancelled when the scheduler is shutdown.
// Otherwise, we risk preventing the server from shutting down even when
// MetricsBase#shutdown() is called
scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
return scheduler;
}
/**
* Gzips the given string.
*
* @param str The string to gzip.
* @return The gzipped string.
*/
private static byte[] compress(final String str) throws IOException {
if (str == null) {
return null;
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
gzip.write(str.getBytes(StandardCharsets.UTF_8));
}
return outputStream.toByteArray();
}
public void addCustomChart(CustomChart chart) {
this.customCharts.add(chart);
}
public void shutdown() {
scheduler.shutdown();
}
private void startSubmitting() {
final Runnable submitTask =
() -> {
if (!enabled || !checkServiceEnabledSupplier.get()) {
// Submitting data or service is disabled
scheduler.shutdown();
return;
}
if (submitTaskConsumer != null) {
submitTaskConsumer.accept(this::submitData);
} else {
this.submitData();
}
};
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven
// distribution of requests on the
// bStats backend. To circumvent this problem, we introduce some randomness into
// the initial and second delay.
// WARNING: You must not modify and part of this Metrics class, including the
// submit delay or frequency!
// WARNING: Modifying this code will get your plugin banned on bStats. Just
// don't do it!
long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3));
long secondDelay = (long) (1000 * 60 * (Math.random() * 30));
scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS);
scheduler.scheduleAtFixedRate(
submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS);
}
private void submitData() {
final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder();
appendPlatformDataConsumer.accept(baseJsonBuilder);
final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder();
appendServiceDataConsumer.accept(serviceJsonBuilder);
JsonObjectBuilder.JsonObject[] chartData =
customCharts.stream()
.map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors))
.filter(Objects::nonNull)
.toArray(JsonObjectBuilder.JsonObject[]::new);
serviceJsonBuilder.appendField("id", serviceId);
serviceJsonBuilder.appendField("customCharts", chartData);
baseJsonBuilder.appendField("service", serviceJsonBuilder.build());
baseJsonBuilder.appendField("serverUUID", serverUuid);
baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION);
JsonObjectBuilder.JsonObject data = baseJsonBuilder.build();
scheduler.execute(
() -> {
try {
// Send the data
sendData(data);
} catch (Exception e) {
// Something went wrong! :(
if (logErrors) {
errorLogger.accept("Could not submit bStats metrics data", e);
}
}
});
}
private void sendData(JsonObjectBuilder.JsonObject data) throws Exception {
if (logSentData) {
infoLogger.accept("Sent bStats metrics data: " + data.toString());
}
String url = String.format(REPORT_URL, platform);
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
// Compress the data to save bandwidth
byte[] compressedData = compress(data.toString());
connection.setRequestMethod("POST");
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("User-Agent", "Metrics-Service/1");
connection.setDoOutput(true);
try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
outputStream.write(compressedData);
}
StringBuilder builder = new StringBuilder();
try (BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
}
}
if (logResponseStatusText) {
infoLogger.accept("Sent data to bStats and received response: " + builder);
}
}
/**
* Checks that the class was properly relocated.
*/
private void checkRelocation() {
// You can use the property to disable the check in your test environment
if (System.getProperty("bstats.relocatecheck") == null
|| !System.getProperty("bstats.relocatecheck").equals("false")) {
// Maven's Relocate is clever and changes strings, too. So we have to use this
// little "trick" ... :D
final String defaultPackage =
new String(new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'});
final String examplePackage =
new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
// We want to make sure no one just copy & pastes the example and uses the wrong
// package names
if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage)
|| MetricsBase.class.getPackage().getName().startsWith(examplePackage)) {
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
}
}
}
}
@@ -1,110 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.metrics;
/*
* This Metrics class was auto-generated and can be copied into your project if you are
* not using a build tool like Gradle or Maven for dependency management.
*
* IMPORTANT: You are not allowed to modify this class, except changing the package.
*
* Disallowed modifications include but are not limited to:
* - Remove the option for users to opt-out
* - Change the frequency for data submission
* - Obfuscate the code (every obfuscator should allow you to make an exception for specific files)
* - Reformat the code (if you use a linter, add an exception)
*
* Violations will result in a ban of your plugin and account from bStats.
*/
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.fabric.GrimACFabricLoaderPlugin;
import net.fabricmc.loader.api.FabricLoader;
import java.util.logging.Level;
public class MetricsFabric implements Metrics {
private final MetricsBase metricsBase;
/**
* Creates a new Metrics instance.
*
* @param serviceId The id of the service. It can be found at <a
* href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a>
*/
public MetricsFabric(GrimPlugin plugin, int serviceId) {
// Get the config file
BStatsConfig.Config config = BStatsConfig.loadConfig();
// Load the data
boolean enabled = config.enabled;
String serverUUID = config.serverUuid;
boolean logErrors = config.logFailedRequests;
boolean logSentData = config.logSentData;
boolean logResponseStatusText = config.logResponseStatusText;
metricsBase =
new // See https://github.com/Bastian/bstats-metrics/pull/126
// See https://github.com/Bastian/bstats-metrics/pull/126
// See https://github.com/Bastian/bstats-metrics/pull/126
// See https://github.com/Bastian/bstats-metrics/pull/126
// See https://github.com/Bastian/bstats-metrics/pull/126
// See https://github.com/Bastian/bstats-metrics/pull/126
// See https://github.com/Bastian/bstats-metrics/pull/126
MetricsBase(
"fabric",
serverUUID,
serviceId,
enabled,
this::appendPlatformData,
this::appendServiceData,
submitDataTask -> GrimAPI.INSTANCE.getScheduler().getAsyncScheduler().runNow(plugin, submitDataTask),
() -> true,
(message, error) -> plugin.getLogger().log(Level.WARNING, message, error),
(message) -> plugin.getLogger().log(Level.INFO, message),
logErrors,
logSentData,
logResponseStatusText,
false);
}
/**
* Shuts down the underlying scheduler service.
*/
public void shutdown() {
metricsBase.shutdown();
}
/**
* Adds a custom chart.
*
* @param chart The chart to add.
*/
public void addCustomChart(CustomChart chart) {
metricsBase.addCustomChart(chart);
}
private void appendPlatformData(JsonObjectBuilder builder) {
builder.appendField("playerAmount", getPlayerAmount());
builder.appendField("onlineMode", GrimACFabricLoaderPlugin.FABRIC_SERVER.usesAuthentication() ? 0 : 1);
builder.appendField("bukkitVersion", GrimAPI.INSTANCE.getPlatformServer().getPlatformImplementationString());
builder.appendField("bukkitName", "Fabric");
builder.appendField("javaVersion", System.getProperty("java.version"));
builder.appendField("osName", System.getProperty("os.name"));
builder.appendField("osArch", System.getProperty("os.arch"));
builder.appendField("osVersion", System.getProperty("os.version"));
builder.appendField("coreCount", Runtime.getRuntime().availableProcessors());
}
private void appendServiceData(JsonObjectBuilder builder) {
builder.appendField("pluginVersion", FabricLoader.getInstance().getModContainer("grimac").get().getMetadata().getVersion().getFriendlyString());
}
private int getPlayerAmount() {
if (GrimACFabricLoaderPlugin.FABRIC_SERVER.isRunning()) {
return GrimACFabricLoaderPlugin.FABRIC_SERVER.getPlayerCount();
} else {
return 0;
}
}
}
@@ -1,15 +0,0 @@
package ac.grim.grimac.platform.fabric.utils.thread;
import ac.grim.grimac.GrimAPI;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
public class FabricFutureUtil {
public static <U> CompletableFuture<U> supplySync(Supplier<U> entityTeleportSupplier) {
CompletableFuture<U> ret = new CompletableFuture<>();
GrimAPI.INSTANCE.getScheduler().getGlobalRegionScheduler().run(GrimAPI.INSTANCE.getGrimPlugin(),
() -> ret.complete(entityTeleportSupplier.get()));
return ret;
}
}
-30
View File
@@ -1,30 +0,0 @@
{
"schemaVersion": 1,
"id": "grimac",
"version": "${version}",
"name": "GrimAC",
"description": "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0.",
"authors": [
"GrimAC"
],
"license": "GPLv3",
"environment": "server",
"entrypoints": {
"main": [
"ac.grim.grimac.platform.fabric.GrimACFabricEntryPoint"
],
"preLaunch": [
"ac.grim.grimac.platform.fabric.GrimACFabricEntryPoint"
]
},
"mixins": [
"grimac.mixins.json"
],
"accessWidener": "grimac.accesswidener",
"depends": {
"fabricloader": "\u003e\u003d0.16",
"fabric-lifecycle-events-v1": "*",
"cloud": "*",
"packetevents": "*"
}
}
@@ -1,5 +0,0 @@
accessWidener v2 named
accessible field net/minecraft/server/level/ServerLevel serverLevelData Lnet/minecraft/world/level/storage/ServerLevelData;
accessible field net/minecraft/commands/CommandSourceStack source Lnet/minecraft/commands/CommandSource;
accessible field net/minecraft/world/entity/player/Player inventory Lnet/minecraft/world/entity/player/Inventory;
accessible field net/minecraft/world/entity/Entity level Lnet/minecraft/world/level/Level; # Required in newer versions, even though public in older ones
@@ -1,14 +0,0 @@
{
"required": true,
"minVersion": "0.8",
"package": "ac.grim.grimac.platform.fabric.mixins",
"compatibilityLevel": "JAVA_17",
"mixins": [
"LevelChunkMixin",
"ServerLevelMixin",
"ServerPlayerMixin"
],
"injectors": {
"defaultRequire": 1
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+93 -93
View File
@@ -1,93 +1,93 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
+1 -21
View File
@@ -12,20 +12,6 @@ dependencyResolutionManagement {
pluginManagement {
repositories {
// For the Fabric Loom plugin
exclusiveContent {
forRepository {
maven {
name = "FabricMC"
url = uri("https://maven.fabricmc.net/")
}
}
filter {
includeModule("fabric-loom", "fabric-loom.gradle.plugin")
includeGroupByRegex("net.fabricmc.*")
}
}
gradlePluginPortal()
}
}
@@ -60,12 +46,6 @@ if (gradle.startParameter.isBuildScan) {
}
}
rootProject.name = "grimac"
rootProject.name = "LightningGrim"
include("common")
include("bukkit")
include("fabric")
include(":fabric:mc1161")
include(":fabric:mc1171")
include(":fabric:mc1194")
include(":fabric:mc1205")
include(":fabric:mc1216")