Initial commit

This commit is contained in:
2026-04-24 14:54:59 +06:00
commit 28776fa5b6
26 changed files with 817 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
{
"permissions": {
"allow": [
"Bash(curl -L -o gradle/wrapper/gradle-wrapper.jar https://raw.githubusercontent.com/gradle/gradle/master/gradle/wrapper/gradle-wrapper.jar)",
"Bash(git init *)",
"Bash(git checkout *)",
"Bash(git add *)"
]
}
}

40
.drone.yml Normal file
View File

@@ -0,0 +1,40 @@
kind: pipeline
type: docker
name: build
steps:
- name: build
image: eclipse-temurin:21-jdk
commands:
- chmod +x gradlew
- ./gradlew build --no-daemon
- name: publish
image: eclipse-temurin:21-jdk
commands:
- mkdir -p artifacts
- cp build/libs/*.jar artifacts/
when:
branch:
- main
- name: upload-artifacts
image: plugins/s3
settings:
bucket: cheat-builds
access_key:
from_secret: s3_access_key
secret_key:
from_secret: s3_secret_key
source: artifacts/*.jar
target: /builds/${DRONE_BUILD_NUMBER}/
when:
branch:
- main
trigger:
branch:
- main
event:
- push
- pull_request

11
.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
.gradle/
build/
out/
*.iml
*.ipr
*.iws
.idea/
run/
logs/
*.log
.DS_Store

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Arkon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

29
README.md Normal file
View File

@@ -0,0 +1,29 @@
# Cheat Client
Advanced Minecraft 1.21.1 client mod built with Fabric.
## Features
- **Killaura** - Automatic attack with configurable range and crit-only mode
- **Triggerbot** - Auto-attack on crosshair target with crit-only mode
- **ESP** - See players through walls
- **Hitbox** - Expanded hitboxes for easier targeting
- **TargetHUD** - Display target information on screen
## Building
```bash
./gradlew build
```
The compiled mod will be in `build/libs/`.
## Installation
1. Install Fabric Loader for Minecraft 1.21.1
2. Install Fabric API
3. Place the mod jar in your `.minecraft/mods` folder
## CI/CD
This project uses Drone CI for automated builds. Every push to main triggers a build and artifact upload.

50
build.gradle Normal file
View File

@@ -0,0 +1,50 @@
plugins {
id 'fabric-loom' version '1.7-SNAPSHOT'
id 'maven-publish'
}
version = project.mod_version
group = project.maven_group
base {
archivesName = project.archives_base_name
}
repositories {
maven { url 'https://maven.fabricmc.net/' }
}
dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
}
processResources {
inputs.property "version", project.version
filteringCharset "UTF-8"
filesMatching("fabric.mod.json") {
expand "version": project.version
}
}
def targetJavaVersion = 21
tasks.withType(JavaCompile).configureEach {
it.options.encoding = "UTF-8"
it.options.release = targetJavaVersion
}
java {
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
sourceCompatibility = javaVersion
targetCompatibility = javaVersion
withSourcesJar()
}
jar {
from("LICENSE") {
rename { "${it}_${project.archivesBaseName}"}
}
}

6
git.txt Normal file
View File

@@ -0,0 +1,6 @@
git init
git checkout -b main
git add *
git commit -m "Initial commit"
git remote add origin https://git.nevetime.ru/Arkon/Cheat-1.21.11.git
git push -u origin main

12
gradle.properties Normal file
View File

@@ -0,0 +1,12 @@
org.gradle.jvmargs=-Xmx2G
org.gradle.parallel=true
minecraft_version=1.21.1
yarn_mappings=1.21.1+build.3
loader_version=0.16.5
mod_version=1.0.0
maven_group=ru.nevetime
archives_base_name=cheat
fabric_version=0.105.0+1.21.1

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

12
gradlew vendored Normal file
View File

@@ -0,0 +1,12 @@
#!/bin/sh
set -e
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
APP_NAME="Gradle"
APP_BASE_NAME=$(basename "$0")
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
exec "$JAVACMD" $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

34
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,34 @@
@rem Gradle startup script for Windows
@if "%DEBUG%"=="" @echo off
setlocal enabledelayedexpansion
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
exit /b 1
:execute
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
: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

9
settings.gradle Normal file
View File

@@ -0,0 +1,9 @@
pluginManagement {
repositories {
maven {
name = 'Fabric'
url = 'https://maven.fabricmc.net/'
}
gradlePluginPortal()
}
}

View File

@@ -0,0 +1,53 @@
package ru.nevetime.cheat;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.nevetime.cheat.module.ModuleManager;
import ru.nevetime.cheat.module.combat.Killaura;
import ru.nevetime.cheat.module.combat.Triggerbot;
import ru.nevetime.cheat.module.render.ESP;
import ru.nevetime.cheat.module.render.Hitbox;
import ru.nevetime.cheat.module.render.TargetHUD;
public class CheatClient implements ClientModInitializer {
public static final String MOD_ID = "cheat";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
private static CheatClient INSTANCE;
private ModuleManager moduleManager;
@Override
public void onInitializeClient() {
INSTANCE = this;
LOGGER.info("Initializing Cheat Client");
moduleManager = new ModuleManager();
moduleManager.register(new Killaura());
moduleManager.register(new Triggerbot());
moduleManager.register(new ESP());
moduleManager.register(new Hitbox());
moduleManager.register(new TargetHUD());
ClientTickEvents.END_CLIENT_TICK.register(client -> {
moduleManager.onTick();
});
WorldRenderEvents.AFTER_ENTITIES.register(context -> {
moduleManager.onRender(context);
});
LOGGER.info("Cheat Client initialized");
}
public static CheatClient getInstance() {
return INSTANCE;
}
public ModuleManager getModuleManager() {
return moduleManager;
}
}

View File

@@ -0,0 +1,23 @@
package ru.nevetime.cheat.mixin;
import net.minecraft.entity.Entity;
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.CallbackInfoReturnable;
import ru.nevetime.cheat.CheatClient;
import ru.nevetime.cheat.module.render.Hitbox;
@Mixin(Entity.class)
public class EntityMixin {
@Inject(method = "getTargetingMargin", at = @At("RETURN"), cancellable = true)
private void onGetTargetingMargin(CallbackInfoReturnable<Float> cir) {
Hitbox hitbox = (Hitbox) CheatClient.getInstance()
.getModuleManager()
.getModule("Hitbox");
if (hitbox != null && hitbox.isEnabled()) {
cir.setReturnValue(cir.getReturnValue() + hitbox.getExpandAmount());
}
}
}

View File

@@ -0,0 +1,29 @@
package ru.nevetime.cheat.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.render.RenderTickCounter;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import ru.nevetime.cheat.CheatClient;
import ru.nevetime.cheat.module.render.TargetHUD;
@Mixin(InGameHud.class)
public class InGameHudMixin {
@Inject(method = "render", at = @At("TAIL"))
private void onRender(DrawContext context, RenderTickCounter tickCounter, CallbackInfo ci) {
MinecraftClient mc = MinecraftClient.getInstance();
if (mc.player == null) return;
TargetHUD targetHUD = (TargetHUD) CheatClient.getInstance()
.getModuleManager()
.getModule("TargetHUD");
if (targetHUD != null) {
targetHUD.render(context, mc.getWindow().getScaledWidth(), mc.getWindow().getScaledHeight());
}
}
}

View File

@@ -0,0 +1,60 @@
package ru.nevetime.cheat.module;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.minecraft.client.MinecraftClient;
public abstract class Module {
protected final String name;
protected final Category category;
protected boolean enabled;
protected final MinecraftClient mc;
public Module(String name, Category category) {
this.name = name;
this.category = category;
this.enabled = false;
this.mc = MinecraftClient.getInstance();
}
public void toggle() {
enabled = !enabled;
if (enabled) {
onEnable();
} else {
onDisable();
}
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
if (enabled) {
onEnable();
} else {
onDisable();
}
}
public void onEnable() {}
public void onDisable() {}
public void onTick() {}
public void onRender(WorldRenderContext context) {}
public String getName() {
return name;
}
public Category getCategory() {
return category;
}
public boolean isEnabled() {
return enabled;
}
public enum Category {
COMBAT,
RENDER,
MOVEMENT,
MISC
}
}

View File

@@ -0,0 +1,41 @@
package ru.nevetime.cheat.module;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import java.util.ArrayList;
import java.util.List;
public class ModuleManager {
private final List<Module> modules = new ArrayList<>();
public void register(Module module) {
modules.add(module);
module.setEnabled(true);
}
public void onTick() {
for (Module module : modules) {
if (module.isEnabled()) {
module.onTick();
}
}
}
public void onRender(WorldRenderContext context) {
for (Module module : modules) {
if (module.isEnabled()) {
module.onRender(context);
}
}
}
public List<Module> getModules() {
return modules;
}
public Module getModule(String name) {
return modules.stream()
.filter(m -> m.getName().equalsIgnoreCase(name))
.findFirst()
.orElse(null);
}
}

View File

@@ -0,0 +1,81 @@
package ru.nevetime.cheat.module.combat;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Hand;
import ru.nevetime.cheat.module.Module;
public class Killaura extends Module {
private double range = 4.0;
private boolean critsOnly = true;
private int attackDelay = 0;
public Killaura() {
super("Killaura", Category.COMBAT);
}
@Override
public void onTick() {
if (mc.player == null || mc.world == null) return;
if (attackDelay > 0) {
attackDelay--;
return;
}
Entity target = findTarget();
if (target == null) return;
if (critsOnly && !canCrit()) return;
mc.interactionManager.attackEntity(mc.player, target);
mc.player.swingHand(Hand.MAIN_HAND);
attackDelay = 10;
}
private Entity findTarget() {
Entity closest = null;
double closestDistance = range;
for (Entity entity : mc.world.getEntities()) {
if (entity == mc.player) continue;
if (!(entity instanceof LivingEntity)) continue;
if (entity instanceof PlayerEntity && ((PlayerEntity) entity).isCreative()) continue;
if (!entity.isAlive()) continue;
double distance = mc.player.distanceTo(entity);
if (distance < closestDistance) {
closest = entity;
closestDistance = distance;
}
}
return closest;
}
private boolean canCrit() {
return mc.player.fallDistance > 0.0F
&& !mc.player.isOnGround()
&& !mc.player.isClimbing()
&& !mc.player.isTouchingWater()
&& !mc.player.hasVehicle()
&& mc.player.getVelocity().y < 0;
}
public void setRange(double range) {
this.range = range;
}
public double getRange() {
return range;
}
public void setCritsOnly(boolean critsOnly) {
this.critsOnly = critsOnly;
}
public boolean isCritsOnly() {
return critsOnly;
}
}

View File

@@ -0,0 +1,59 @@
package ru.nevetime.cheat.module.combat;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.hit.HitResult;
import ru.nevetime.cheat.module.Module;
public class Triggerbot extends Module {
private boolean critsOnly = true;
private int attackDelay = 0;
public Triggerbot() {
super("Triggerbot", Category.COMBAT);
}
@Override
public void onTick() {
if (mc.player == null || mc.world == null) return;
if (attackDelay > 0) {
attackDelay--;
return;
}
HitResult hitResult = mc.crosshairTarget;
if (hitResult == null || hitResult.getType() != HitResult.Type.ENTITY) return;
EntityHitResult entityHit = (EntityHitResult) hitResult;
Entity target = entityHit.getEntity();
if (!(target instanceof LivingEntity)) return;
if (!target.isAlive()) return;
if (critsOnly && !canCrit()) return;
mc.interactionManager.attackEntity(mc.player, target);
mc.player.swingHand(Hand.MAIN_HAND);
attackDelay = 10;
}
private boolean canCrit() {
return mc.player.fallDistance > 0.0F
&& !mc.player.isOnGround()
&& !mc.player.isClimbing()
&& !mc.player.isTouchingWater()
&& !mc.player.hasVehicle()
&& mc.player.getVelocity().y < 0;
}
public void setCritsOnly(boolean critsOnly) {
this.critsOnly = critsOnly;
}
public boolean isCritsOnly() {
return critsOnly;
}
}

View File

@@ -0,0 +1,100 @@
package ru.nevetime.cheat.module.render;
import com.mojang.blaze3d.systems.RenderSystem;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.minecraft.client.render.*;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;
import org.joml.Matrix4f;
import ru.nevetime.cheat.module.Module;
public class ESP extends Module {
public ESP() {
super("ESP", Category.RENDER);
}
@Override
public void onRender(WorldRenderContext context) {
if (mc.player == null || mc.world == null) return;
MatrixStack matrices = context.matrixStack();
matrices.push();
Vec3d camera = context.camera().getPos();
matrices.translate(-camera.x, -camera.y, -camera.z);
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.disableDepthTest();
RenderSystem.setShader(GameRenderer::getPositionColorProgram);
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.begin(VertexFormat.DrawMode.DEBUG_LINES, VertexFormats.POSITION_COLOR);
for (Entity entity : mc.world.getEntities()) {
if (entity == mc.player) continue;
if (!(entity instanceof PlayerEntity)) continue;
if (!entity.isAlive()) continue;
Box box = entity.getBoundingBox();
drawBox(matrices, buffer, box, 1.0f, 0.0f, 0.0f, 1.0f);
}
BufferRenderer.drawWithGlobalProgram(buffer.end());
RenderSystem.enableDepthTest();
RenderSystem.disableBlend();
matrices.pop();
}
private void drawBox(MatrixStack matrices, BufferBuilder buffer, Box box, float r, float g, float b, float a) {
Matrix4f matrix = matrices.peek().getPositionMatrix();
float minX = (float) box.minX;
float minY = (float) box.minY;
float minZ = (float) box.minZ;
float maxX = (float) box.maxX;
float maxY = (float) box.maxY;
float maxZ = (float) box.maxZ;
buffer.vertex(matrix, minX, minY, minZ).color(r, g, b, a);
buffer.vertex(matrix, maxX, minY, minZ).color(r, g, b, a);
buffer.vertex(matrix, maxX, minY, minZ).color(r, g, b, a);
buffer.vertex(matrix, maxX, minY, maxZ).color(r, g, b, a);
buffer.vertex(matrix, maxX, minY, maxZ).color(r, g, b, a);
buffer.vertex(matrix, minX, minY, maxZ).color(r, g, b, a);
buffer.vertex(matrix, minX, minY, maxZ).color(r, g, b, a);
buffer.vertex(matrix, minX, minY, minZ).color(r, g, b, a);
buffer.vertex(matrix, minX, maxY, minZ).color(r, g, b, a);
buffer.vertex(matrix, maxX, maxY, minZ).color(r, g, b, a);
buffer.vertex(matrix, maxX, maxY, minZ).color(r, g, b, a);
buffer.vertex(matrix, maxX, maxY, maxZ).color(r, g, b, a);
buffer.vertex(matrix, maxX, maxY, maxZ).color(r, g, b, a);
buffer.vertex(matrix, minX, maxY, maxZ).color(r, g, b, a);
buffer.vertex(matrix, minX, maxY, maxZ).color(r, g, b, a);
buffer.vertex(matrix, minX, maxY, minZ).color(r, g, b, a);
buffer.vertex(matrix, minX, minY, minZ).color(r, g, b, a);
buffer.vertex(matrix, minX, maxY, minZ).color(r, g, b, a);
buffer.vertex(matrix, maxX, minY, minZ).color(r, g, b, a);
buffer.vertex(matrix, maxX, maxY, minZ).color(r, g, b, a);
buffer.vertex(matrix, maxX, minY, maxZ).color(r, g, b, a);
buffer.vertex(matrix, maxX, maxY, maxZ).color(r, g, b, a);
buffer.vertex(matrix, minX, minY, maxZ).color(r, g, b, a);
buffer.vertex(matrix, minX, maxY, maxZ).color(r, g, b, a);
}
}

View File

@@ -0,0 +1,19 @@
package ru.nevetime.cheat.module.render;
import ru.nevetime.cheat.module.Module;
public class Hitbox extends Module {
private float expandAmount = 0.3f;
public Hitbox() {
super("Hitbox", Category.RENDER);
}
public float getExpandAmount() {
return expandAmount;
}
public void setExpandAmount(float expandAmount) {
this.expandAmount = expandAmount;
}
}

View File

@@ -0,0 +1,72 @@
package ru.nevetime.cheat.module.render;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import ru.nevetime.cheat.module.Module;
public class TargetHUD extends Module {
private Entity currentTarget;
public TargetHUD() {
super("TargetHUD", Category.RENDER);
}
@Override
public void onTick() {
if (mc.player == null || mc.world == null) {
currentTarget = null;
return;
}
currentTarget = findTarget();
}
private Entity findTarget() {
Entity closest = null;
double closestDistance = 20.0;
for (Entity entity : mc.world.getEntities()) {
if (entity == mc.player) continue;
if (!(entity instanceof LivingEntity)) continue;
if (!entity.isAlive()) continue;
double distance = mc.player.distanceTo(entity);
if (distance < closestDistance) {
closest = entity;
closestDistance = distance;
}
}
return closest;
}
public void render(DrawContext context, int screenWidth, int screenHeight) {
if (!isEnabled() || currentTarget == null) return;
if (!(currentTarget instanceof LivingEntity living)) return;
int x = 10;
int y = 10;
String name = currentTarget.getName().getString();
float health = living.getHealth();
float maxHealth = living.getMaxHealth();
float distance = mc.player.distanceTo(currentTarget);
context.fill(x, y, x + 150, y + 50, 0x80000000);
context.drawText(mc.textRenderer, name, x + 5, y + 5, 0xFFFFFF, true);
context.drawText(mc.textRenderer, String.format("HP: %.1f/%.1f", health, maxHealth), x + 5, y + 20, 0xFF0000, true);
context.drawText(mc.textRenderer, String.format("Distance: %.1f", distance), x + 5, y + 35, 0xFFFFFF, true);
int barWidth = 140;
int healthBarWidth = (int) ((health / maxHealth) * barWidth);
context.fill(x + 5, y + 48, x + 5 + barWidth, y + 52, 0xFF333333);
context.fill(x + 5, y + 48, x + 5 + healthBarWidth, y + 52, 0xFF00FF00);
}
public Entity getCurrentTarget() {
return currentTarget;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

View File

@@ -0,0 +1,13 @@
{
"required": true,
"minVersion": "0.8",
"package": "ru.nevetime.cheat.mixin",
"compatibilityLevel": "JAVA_21",
"client": [
"InGameHudMixin",
"EntityMixin"
],
"injectors": {
"defaultRequire": 1
}
}

View File

@@ -0,0 +1,26 @@
{
"schemaVersion": 1,
"id": "cheat",
"version": "${version}",
"name": "Cheat",
"description": "Advanced client mod",
"authors": ["Arkon"],
"contact": {},
"license": "MIT",
"icon": "assets/cheat/icon.png",
"environment": "client",
"entrypoints": {
"client": [
"ru.nevetime.cheat.CheatClient"
]
},
"mixins": [
"cheat.mixins.json"
],
"depends": {
"fabricloader": ">=0.16.0",
"minecraft": "~1.21.1",
"java": ">=21",
"fabric-api": "*"
}
}