Initial Commit
This commit is contained in:
parent
8749a28cdc
commit
1f2c68181e
119
.gitignore
vendored
Normal file
119
.gitignore
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
# User-specific stuff
|
||||
.idea/
|
||||
remappedSrc/
|
||||
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
Thumbs.db:encryptable
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
.gradle
|
||||
build/
|
||||
|
||||
# Ignore Gradle GUI config
|
||||
gradle-app.setting
|
||||
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
**/build/
|
||||
|
||||
# Common working directory
|
||||
run/
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2022 CameronReed
|
||||
|
||||
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.
|
86
build.gradle
Normal file
86
build.gradle
Normal file
@ -0,0 +1,86 @@
|
||||
plugins {
|
||||
id 'fabric-loom' version '1.0-SNAPSHOT'
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
version = project.mod_version
|
||||
group = project.maven_group
|
||||
|
||||
repositories {
|
||||
// Add repositories to retrieve artifacts from in here.
|
||||
// You should only use this when depending on other mods because
|
||||
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
||||
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
||||
// for more information about repositories.
|
||||
maven {
|
||||
name = 'TerraformersMC'
|
||||
url = 'https://maven.terraformersmc.com/releases'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// To change the versions see the gradle.properties file
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
|
||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
modCompileOnly "com.terraformersmc:modmenu:4.1.1"
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
filteringCharset "UTF-8"
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand "version": project.version
|
||||
}
|
||||
}
|
||||
|
||||
def targetJavaVersion = 17
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||
// this fixes some edge cases with special characters not displaying correctly
|
||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||
// If Javadoc is generated, this must be specified in that task too.
|
||||
it.options.encoding = "UTF-8"
|
||||
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
|
||||
it.options.release = targetJavaVersion
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
||||
if (JavaVersion.current() < javaVersion) {
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
|
||||
}
|
||||
archivesBaseName = project.archives_base_name
|
||||
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
|
||||
// if it is present.
|
||||
// If you remove this line, sources will not be generated.
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
jar {
|
||||
from("LICENSE") {
|
||||
rename { "${it}_${project.archivesBaseName}" }
|
||||
}
|
||||
}
|
||||
|
||||
// configure the maven publication
|
||||
publishing {
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||
repositories {
|
||||
// Add repositories to publish to here.
|
||||
// Notice: This block does NOT have the same function as the block in the top level.
|
||||
// The repositories here will be used for publishing your artifact, not for
|
||||
// retrieving dependencies.
|
||||
}
|
||||
}
|
14
gradle.properties
Normal file
14
gradle.properties
Normal file
@ -0,0 +1,14 @@
|
||||
# Done to increase the memory available to gradle.
|
||||
org.gradle.jvmargs=-Xmx2G
|
||||
# Fabric Properties
|
||||
# check these on https://modmuss50.me/fabric.html
|
||||
minecraft_version=1.19.2
|
||||
yarn_mappings=1.19.2+build.28
|
||||
loader_version=0.14.10
|
||||
# Mod Properties
|
||||
mod_version=1.0.0
|
||||
maven_group=cmods
|
||||
archives_base_name=haxxor
|
||||
# Dependencies
|
||||
# check this on https://modmuss50.me/fabric.html
|
||||
fabric_version=0.67.1+1.19.2
|
1
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
1
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1 @@
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
9
settings.gradle
Normal file
9
settings.gradle
Normal file
@ -0,0 +1,9 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
name = 'Fabric'
|
||||
url = 'https://maven.fabricmc.net/'
|
||||
}
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
322
src/main/java/cmods/haxxor/client/AutoFarmer.java
Normal file
322
src/main/java/cmods/haxxor/client/AutoFarmer.java
Normal file
@ -0,0 +1,322 @@
|
||||
package cmods.haxxor.client;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket;
|
||||
import net.minecraft.screen.slot.SlotActionType;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
public class AutoFarmer { // Really just a namespace and needed to separate things into their own files
|
||||
public static final AutoFarmerCropType[] crops = {
|
||||
new AutoFarmerCropType(Blocks.WHEAT, Items.WHEAT_SEEDS, GROWTH_PATTERN.BASIC, Blocks.FARMLAND),
|
||||
new AutoFarmerCropType(Blocks.BEETROOTS, Items.BEETROOT_SEEDS, GROWTH_PATTERN.BASIC, Blocks.FARMLAND),
|
||||
new AutoFarmerCropType(Blocks.POTATOES, Items.POTATO, GROWTH_PATTERN.BASIC, Blocks.FARMLAND),
|
||||
new AutoFarmerCropType(Blocks.CARROTS, Items.CARROT, GROWTH_PATTERN.BASIC, Blocks.FARMLAND),
|
||||
new AutoFarmerCropType(Blocks.NETHER_WART, Items.NETHER_WART, GROWTH_PATTERN.BASIC, Blocks.SOUL_SAND),
|
||||
new AutoFarmerCropType(Blocks.SUGAR_CANE, null, GROWTH_PATTERN.LEAVE_BASE, null)
|
||||
};
|
||||
|
||||
|
||||
private enum ACTION_TYPE {
|
||||
NONE,
|
||||
BREAK,
|
||||
PLACE,
|
||||
PLACE_MAIN_HAND,
|
||||
PLACE_OFF_HAND
|
||||
}
|
||||
|
||||
private enum GROWTH_PATTERN {
|
||||
BASIC,
|
||||
LEAVE_BASE
|
||||
}
|
||||
|
||||
private static final ArrayList<FarmerAction> potentialActions = new ArrayList<>();
|
||||
private static final ArrayList<FarmerAction> queuedActions = new ArrayList<>();
|
||||
private static final ArrayList<BlockPos> queuedStopPackets = new ArrayList<>();
|
||||
private static HaxxorOptions.AutoFarmerOptions options;
|
||||
|
||||
private static final int offHandSlot = 45;
|
||||
|
||||
|
||||
public static void init() {
|
||||
options = HaxxorOptions.getInstance().autoFarmer;
|
||||
}
|
||||
|
||||
public static boolean canFarm() {
|
||||
return queuedActions.size() > 0;
|
||||
}
|
||||
|
||||
public static void tick(MinecraftClient client) {
|
||||
if (client.player == null)
|
||||
return;
|
||||
|
||||
if (queuedStopPackets.size() > 0)
|
||||
sendStopPackets(client);
|
||||
|
||||
scanBlocks(client);
|
||||
if (options.move_seeds && options.enabled)
|
||||
adjustInventory(client);
|
||||
findActions(client);
|
||||
|
||||
if (options.enabled)
|
||||
run(client);
|
||||
}
|
||||
|
||||
|
||||
private static void run(MinecraftClient client) {
|
||||
if (client.world == null || client.player == null)
|
||||
return;
|
||||
|
||||
for (FarmerAction action : queuedActions) {
|
||||
switch (action.type) {
|
||||
case BREAK -> breakCrop(client, action.pos);
|
||||
case PLACE_MAIN_HAND -> plantSeeds(client, action.pos, Hand.MAIN_HAND);
|
||||
case PLACE_OFF_HAND -> plantSeeds(client, action.pos, Hand.OFF_HAND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void adjustInventory(MinecraftClient client) {
|
||||
if (client.player == null || client.world == null)
|
||||
return;
|
||||
|
||||
boolean item_in_main = false;
|
||||
boolean item_in_off = false;
|
||||
|
||||
PlayerInventory inventory = client.player.getInventory();
|
||||
|
||||
for (FarmerAction action: potentialActions) {
|
||||
if (action.type != ACTION_TYPE.PLACE)
|
||||
continue;
|
||||
|
||||
BlockState block = client.world.getBlockState(action.pos);
|
||||
for (int i = 0; i < crops.length; i++) {
|
||||
int slot = inventory.getSlotWithStack(new ItemStack(crops[i].seed_type));
|
||||
if (crops[i].seed_type != null && crops[i].planted_on != null && block.isOf(crops[i].planted_on) &&
|
||||
options.crops_enabled[i] && slot != -1) {
|
||||
if (!item_in_main) {
|
||||
if (PlayerInventory.isValidHotbarIndex(slot)) {
|
||||
selectSlot(client, slot);
|
||||
} else if (slot < 36) {
|
||||
moveToHotBar(client, inventory, inventory.getSwappableHotbarSlot(), slot);
|
||||
}
|
||||
item_in_main = true;
|
||||
} else if (!item_in_off && slot < 36 && slot > 8) {
|
||||
moveToOffHand(client, inventory, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void moveToOffHand(MinecraftClient client, PlayerInventory inventory, int slot) {
|
||||
if (client.player == null)
|
||||
return;
|
||||
|
||||
int[] slots = {slot, offHandSlot};
|
||||
ItemStack[] stacks = {inventory.getStack(offHandSlot), inventory.getStack(slot)};
|
||||
Int2ObjectMap<ItemStack> modifiedItems = new Int2ObjectArrayMap<>(slots, stacks);
|
||||
|
||||
Objects.requireNonNull(client.getNetworkHandler()).sendPacket(
|
||||
new ClickSlotC2SPacket(0, client.player.playerScreenHandler.getRevision(), slot, 40,
|
||||
SlotActionType.SWAP, ItemStack.EMPTY, modifiedItems));
|
||||
}
|
||||
|
||||
private static void moveToHotBar(MinecraftClient client, PlayerInventory inventory, int hotBarSlot, int slot) {
|
||||
if (client.player == null)
|
||||
return;
|
||||
|
||||
int[] slots = {slot, offHandSlot};
|
||||
ItemStack[] stacks = {inventory.getStack(offHandSlot), inventory.getStack(slot)};
|
||||
Int2ObjectMap<ItemStack> modifiedItems = new Int2ObjectArrayMap<>(slots, stacks);
|
||||
|
||||
Objects.requireNonNull(client.getNetworkHandler()).sendPacket(
|
||||
new ClickSlotC2SPacket(0, client.player.playerScreenHandler.getRevision(), slot, hotBarSlot,
|
||||
SlotActionType.SWAP, ItemStack.EMPTY, modifiedItems));
|
||||
|
||||
selectSlot(client, hotBarSlot);
|
||||
}
|
||||
|
||||
private static void selectSlot(MinecraftClient client, int slot) {
|
||||
if (PlayerInventory.isValidHotbarIndex(slot) && client.player != null) {
|
||||
client.player.getInventory().selectedSlot = slot;
|
||||
Objects.requireNonNull(client.getNetworkHandler()).sendPacket(new UpdateSelectedSlotC2SPacket(slot));
|
||||
}
|
||||
}
|
||||
|
||||
private static void scanBlocks(MinecraftClient client) {
|
||||
if (client.world == null || client.player == null)
|
||||
return;
|
||||
|
||||
potentialActions.clear();
|
||||
BlockPos playerPos = client.player.getBlockPos();
|
||||
|
||||
for (int y = options.min_y; y <= options.max_y; y++) {
|
||||
for (int x = -options.horizontal_reach; x <= options.horizontal_reach; x++) {
|
||||
for (int z = -options.horizontal_reach; z <= options.horizontal_reach; z++) {
|
||||
BlockPos pos = playerPos.add(x, y, z);
|
||||
|
||||
ACTION_TYPE action = checkBlock(client, pos);
|
||||
if (action != ACTION_TYPE.NONE) {
|
||||
potentialActions.add(new FarmerAction(pos, action));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ACTION_TYPE checkBlock(MinecraftClient client, BlockPos pos) {
|
||||
if (client.world == null || client.player == null)
|
||||
return ACTION_TYPE.NONE;
|
||||
|
||||
BlockState block = client.world.getBlockState(pos);
|
||||
|
||||
for (int i = 0; i < crops.length; i++) {
|
||||
AutoFarmerCropType cropType = crops[i];
|
||||
|
||||
if (cropType.growth_pattern == GROWTH_PATTERN.BASIC && block.isOf(cropType.crop_type) &&
|
||||
options.crops_enabled[i]) {
|
||||
return isMature(block, cropType.crop_type.getClass()) ? ACTION_TYPE.BREAK : ACTION_TYPE.NONE;
|
||||
}
|
||||
|
||||
if (cropType.growth_pattern == GROWTH_PATTERN.LEAVE_BASE && block.isOf(cropType.crop_type) &&
|
||||
options.crops_enabled[i]) {
|
||||
return isSecondBlock(client.world, pos, cropType.crop_type) ? ACTION_TYPE.BREAK : ACTION_TYPE.NONE;
|
||||
}
|
||||
|
||||
if (cropType.seed_type != null && cropType.planted_on != null && block.isOf(cropType.planted_on) &&
|
||||
client.world.getBlockState(pos.up()).isAir() && options.seeds_enabled[i]) {
|
||||
return ACTION_TYPE.PLACE;
|
||||
}
|
||||
}
|
||||
|
||||
return ACTION_TYPE.NONE;
|
||||
}
|
||||
|
||||
private static void findActions(MinecraftClient client) {
|
||||
if (client.world == null || client.player == null)
|
||||
return;
|
||||
|
||||
queuedActions.clear();
|
||||
|
||||
for (FarmerAction action: potentialActions) {
|
||||
if (action.type != ACTION_TYPE.PLACE) {
|
||||
queuedActions.add(action);
|
||||
} else {
|
||||
ACTION_TYPE action_type = holingSeeds(client, action.pos);
|
||||
if (action_type != ACTION_TYPE.NONE) {
|
||||
queuedActions.add(new FarmerAction(action.pos, action_type));
|
||||
}
|
||||
}
|
||||
|
||||
if (queuedActions.size() >= options.max_actions_per_tick)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static ACTION_TYPE holingSeeds(MinecraftClient client, BlockPos pos) {
|
||||
if (client.world == null || client.player == null)
|
||||
return ACTION_TYPE.NONE;
|
||||
|
||||
ItemStack mainHandItem = client.player.getStackInHand(Hand.MAIN_HAND);
|
||||
ItemStack offHandItem = client.player.getStackInHand(Hand.OFF_HAND);
|
||||
|
||||
BlockState block = client.world.getBlockState(pos);
|
||||
|
||||
for (int i = 0; i < crops.length; i++) {
|
||||
AutoFarmerCropType cropType = crops[i];
|
||||
|
||||
if (cropType.seed_type != null && cropType.planted_on != null && block.isOf(cropType.planted_on) &&
|
||||
client.world.getBlockState(pos.up()).isAir() && options.seeds_enabled[i]) {
|
||||
if (mainHandItem.isOf(cropType.seed_type)) {
|
||||
return ACTION_TYPE.PLACE_MAIN_HAND;
|
||||
} else if (offHandItem.isOf(cropType.seed_type)) {
|
||||
return ACTION_TYPE.PLACE_OFF_HAND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ACTION_TYPE.NONE;
|
||||
}
|
||||
|
||||
private static boolean isMature(BlockState block, Class<?> blockType) {
|
||||
if (block.getBlock() instanceof CropBlock)
|
||||
return ((CropBlock) block.getBlock()).isMature(block);
|
||||
if (blockType == NetherWartBlock.class)
|
||||
return block.get(NetherWartBlock.AGE) >= NetherWartBlock.field_31199;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isSecondBlock(ClientWorld world, BlockPos pos, Block crop_type) {
|
||||
return world.getBlockState(pos).isOf(crop_type) && world.getBlockState(pos.down()).isOf(crop_type) &&
|
||||
!world.getBlockState(pos.down().down()).isOf(crop_type);
|
||||
}
|
||||
|
||||
private static void sendStopPackets(MinecraftClient client) {
|
||||
if (client.world == null || client.player == null)
|
||||
return;
|
||||
|
||||
for (BlockPos pos: queuedStopPackets) {
|
||||
PlayerActionC2SPacket packet =
|
||||
new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.STOP_DESTROY_BLOCK, pos, Direction.UP, 0);
|
||||
Objects.requireNonNull(client.getNetworkHandler()).sendPacket(packet);
|
||||
}
|
||||
|
||||
queuedStopPackets.clear();
|
||||
}
|
||||
|
||||
private static void breakCrop(MinecraftClient client, BlockPos pos) {
|
||||
if (client == null || client.player == null)
|
||||
return;
|
||||
|
||||
PlayerActionC2SPacket packet =
|
||||
new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, pos, Direction.UP, 0);
|
||||
Objects.requireNonNull(client.getNetworkHandler()).sendPacket(packet);
|
||||
|
||||
queuedStopPackets.add(pos);
|
||||
}
|
||||
|
||||
private static void plantSeeds(MinecraftClient client, BlockPos pos, Hand hand) {
|
||||
if (client == null || client.player == null)
|
||||
return;
|
||||
|
||||
PlayerInteractBlockC2SPacket packet = new PlayerInteractBlockC2SPacket(hand,
|
||||
new BlockHitResult(new Vec3d(pos.getX(), pos.getY(), pos.getZ()), Direction.UP, pos, false), 0);
|
||||
Objects.requireNonNull(client.getNetworkHandler()).sendPacket(packet);
|
||||
}
|
||||
|
||||
|
||||
public static class AutoFarmerCropType {
|
||||
public Block crop_type;
|
||||
public Item seed_type;
|
||||
public GROWTH_PATTERN growth_pattern;
|
||||
public Block planted_on;
|
||||
|
||||
public AutoFarmerCropType(Block crop_type, Item seed_type, GROWTH_PATTERN growth_pattern, Block planted_on) {
|
||||
this.crop_type = crop_type;
|
||||
this.seed_type = seed_type;
|
||||
this.growth_pattern = growth_pattern;
|
||||
this.planted_on = planted_on;
|
||||
}
|
||||
}
|
||||
|
||||
private record FarmerAction(BlockPos pos, ACTION_TYPE type) { }
|
||||
}
|
53
src/main/java/cmods/haxxor/client/HaxxorClient.java
Normal file
53
src/main/java/cmods/haxxor/client/HaxxorClient.java
Normal file
@ -0,0 +1,53 @@
|
||||
package cmods.haxxor.client;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.option.StickyKeyBinding;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class HaxxorClient implements ClientModInitializer {
|
||||
public static String MOD_ID = "haxxor";
|
||||
public static String version = "Unknown";
|
||||
|
||||
private static StickyKeyBinding auto_farm_key;
|
||||
private static final HaxxorOptions options = HaxxorOptions.getInstance();
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
Optional<ModContainer> modContainer = FabricLoader.getInstance().getModContainer(MOD_ID);
|
||||
modContainer.ifPresentOrElse(container -> version = container.getMetadata().getVersion().getFriendlyString(),
|
||||
() -> System.out.println("Haxxor: Could not get mod version"));
|
||||
|
||||
auto_farm_key = (StickyKeyBinding) KeyBindingHelper.registerKeyBinding(new StickyKeyBinding(
|
||||
"key.haxxor.auto_farm",
|
||||
GLFW.GLFW_KEY_Z,
|
||||
"category.haxxor.options",
|
||||
() -> true
|
||||
));
|
||||
|
||||
AutoFarmer.init();
|
||||
|
||||
ClientTickEvents.END_CLIENT_TICK.register(this::tick);
|
||||
}
|
||||
|
||||
public static boolean toggleAutoFarmer() {
|
||||
auto_farm_key.setPressed(true);
|
||||
|
||||
return options.autoFarmer.enabled = auto_farm_key.isPressed();
|
||||
}
|
||||
|
||||
private void tick(MinecraftClient client) {
|
||||
options.autoFarmer.enabled = auto_farm_key.isPressed();
|
||||
|
||||
AutoFarmer.tick(client);
|
||||
}
|
||||
}
|
90
src/main/java/cmods/haxxor/client/HaxxorOptions.java
Normal file
90
src/main/java/cmods/haxxor/client/HaxxorOptions.java
Normal file
@ -0,0 +1,90 @@
|
||||
package cmods.haxxor.client;
|
||||
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
public final class HaxxorOptions {
|
||||
private static HaxxorOptions instance = null;
|
||||
|
||||
public final AutoFarmerOptions autoFarmer;
|
||||
|
||||
|
||||
public static HaxxorOptions getInstance() {
|
||||
if (instance == null)
|
||||
instance = new HaxxorOptions();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private HaxxorOptions() {
|
||||
autoFarmer = new AutoFarmerOptions();
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
autoFarmer.load();
|
||||
}
|
||||
|
||||
public void save() {
|
||||
autoFarmer.save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class AutoFarmerOptions {
|
||||
private final Preferences prefs = Preferences.userNodeForPackage(AutoFarmerOptions.class);
|
||||
|
||||
public boolean enabled;
|
||||
public boolean move_seeds;
|
||||
|
||||
public int min_y = -2;
|
||||
public int max_y = 1;
|
||||
|
||||
public int horizontal_reach = 4;
|
||||
public int max_actions_per_tick = 30;
|
||||
|
||||
public final boolean[] seeds_enabled = new boolean[AutoFarmer.crops.length];
|
||||
public final boolean[] crops_enabled = new boolean[AutoFarmer.crops.length];
|
||||
|
||||
public AutoFarmerOptions() { }
|
||||
|
||||
|
||||
private void load() {
|
||||
move_seeds = prefs.getBoolean("move_seeds", move_seeds);
|
||||
min_y = prefs.getInt("min_y", min_y);
|
||||
max_y = prefs.getInt("max_y", max_y);
|
||||
horizontal_reach = prefs.getInt("horizontal_reach", horizontal_reach);
|
||||
max_actions_per_tick = prefs.getInt("max_actions_per_tick", max_actions_per_tick);
|
||||
|
||||
for (int i = 0; i < AutoFarmer.crops.length; i++) {
|
||||
if (AutoFarmer.crops[i].seed_type != null) {
|
||||
seeds_enabled[i] = prefs.getBoolean("seed_" + AutoFarmer.crops[i].seed_type.getName().getString(),
|
||||
seeds_enabled[i]);
|
||||
}
|
||||
|
||||
if (AutoFarmer.crops[i].crop_type != null) {
|
||||
crops_enabled[i] = prefs.getBoolean("crop_" + AutoFarmer.crops[i].crop_type.getName().getString(),
|
||||
crops_enabled[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void save() {
|
||||
prefs.putBoolean("move_seeds", move_seeds);
|
||||
prefs.putInt("min_y", min_y);
|
||||
prefs.putInt("max_y", max_y);
|
||||
prefs.putInt("horizontal_reach", horizontal_reach);
|
||||
prefs.putInt("max_actions_per_tick", max_actions_per_tick);
|
||||
|
||||
for (int i = 0; i < AutoFarmer.crops.length; i++) {
|
||||
if (AutoFarmer.crops[i].seed_type != null) {
|
||||
prefs.putBoolean("seed_" + AutoFarmer.crops[i].seed_type.getName().getString(), seeds_enabled[i]);
|
||||
}
|
||||
|
||||
if (AutoFarmer.crops[i].crop_type != null) {
|
||||
prefs.putBoolean("crop_" + AutoFarmer.crops[i].crop_type.getName().getString(), crops_enabled[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
13
src/main/java/cmods/haxxor/client/ModMenuConfig.java
Normal file
13
src/main/java/cmods/haxxor/client/ModMenuConfig.java
Normal file
@ -0,0 +1,13 @@
|
||||
package cmods.haxxor.client;
|
||||
|
||||
import cmods.haxxor.client.ui.HaxxorOptionsScreen;
|
||||
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
|
||||
public class ModMenuConfig implements ModMenuApi {
|
||||
@Override
|
||||
public ConfigScreenFactory<?> getModConfigScreenFactory() {
|
||||
return (ConfigScreenFactory<Screen>) HaxxorOptionsScreen::new;
|
||||
}
|
||||
}
|
14
src/main/java/cmods/haxxor/client/ui/Constants.java
Normal file
14
src/main/java/cmods/haxxor/client/ui/Constants.java
Normal file
@ -0,0 +1,14 @@
|
||||
package cmods.haxxor.client.ui;
|
||||
|
||||
public class Constants {
|
||||
public static final int buttonWidth = 150;
|
||||
public static final int buttonHeight = 20;
|
||||
public static final int column1_offset = -5 - buttonWidth;
|
||||
public static final int column2_offset = 5;
|
||||
public static final float startHeight_multiplier = 1.0f / 6.0f;
|
||||
public static final int rowIncrement = buttonHeight + 5;
|
||||
|
||||
public static final int doneButtonWidth = buttonWidth + buttonWidth / 3;
|
||||
public static final int doneButtonX_offset = -(doneButtonWidth / 2);
|
||||
public static final int doneButtonRowIncrement = rowIncrement + 4;
|
||||
}
|
80
src/main/java/cmods/haxxor/client/ui/CropSelectScreen.java
Normal file
80
src/main/java/cmods/haxxor/client/ui/CropSelectScreen.java
Normal file
@ -0,0 +1,80 @@
|
||||
package cmods.haxxor.client.ui;
|
||||
|
||||
import cmods.haxxor.client.AutoFarmer;
|
||||
import cmods.haxxor.client.HaxxorOptions;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.screen.ScreenTexts;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import static cmods.haxxor.client.ui.Constants.*;
|
||||
|
||||
public class CropSelectScreen extends Screen {
|
||||
private final HaxxorOptions options;
|
||||
private final Screen parent;
|
||||
private final int heightOffset = 10;
|
||||
|
||||
|
||||
protected CropSelectScreen(Screen parent) {
|
||||
super(Text.translatable("haxxor.options.farmer.crop_select.title"));
|
||||
this.parent = parent;
|
||||
options = HaxxorOptions.getInstance();
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
if (client == null)
|
||||
return;
|
||||
|
||||
final int column1 = this.width / 2 + column1_offset;
|
||||
final int column2 = this.width / 2 + column2_offset;
|
||||
final int startHeight = (int) Math.floor(this.height * startHeight_multiplier) + heightOffset;
|
||||
final int doneButtonX = this.width / 2 + doneButtonX_offset;
|
||||
|
||||
int y = startHeight;
|
||||
|
||||
for (int i = 0; i < AutoFarmer.crops.length; i++) {
|
||||
int finalI = i;
|
||||
|
||||
if (AutoFarmer.crops[i].seed_type != null) {
|
||||
addDrawableChild(new ToggleEnableButtonWidget(column1, y, buttonWidth, buttonHeight,
|
||||
AutoFarmer.crops[i].seed_type.getName(), options.autoFarmer.seeds_enabled[i],
|
||||
(button, enable) -> options.autoFarmer.seeds_enabled[finalI] = enable));
|
||||
}
|
||||
|
||||
if (AutoFarmer.crops[i].crop_type != null) {
|
||||
addDrawableChild(new ToggleEnableButtonWidget(column2, y, buttonWidth, buttonHeight,
|
||||
AutoFarmer.crops[i].crop_type.getName(), options.autoFarmer.crops_enabled[i],
|
||||
(button, enable) -> options.autoFarmer.crops_enabled[finalI] = enable));
|
||||
}
|
||||
|
||||
y += rowIncrement;
|
||||
}
|
||||
|
||||
addDrawableChild(new ButtonWidget(doneButtonX, y + doneButtonRowIncrement, doneButtonWidth, buttonHeight,
|
||||
ScreenTexts.DONE, button -> {
|
||||
options.save();
|
||||
client.setScreen(parent);
|
||||
}));
|
||||
}
|
||||
|
||||
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
|
||||
final int column1 = this.width / 2 + column1_offset;
|
||||
final int column2 = this.width / 2 + column2_offset;
|
||||
final int startHeight = (int) Math.floor(this.height * startHeight_multiplier) + heightOffset;
|
||||
|
||||
this.renderBackground(matrices);
|
||||
|
||||
drawCenteredText(matrices, this.textRenderer, Text.translatable("haxxor.options.farmer.crop_select.seeds"),
|
||||
column1 + buttonWidth / 2, startHeight - rowIncrement, 0xffffff);
|
||||
drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 15, 0xffffff);
|
||||
drawCenteredText(matrices, this.textRenderer, Text.translatable("haxxor.options.farmer.crop_select.blocks"),
|
||||
column2 + buttonWidth / 2, startHeight - rowIncrement, 0xffffff);
|
||||
|
||||
super.render(matrices, mouseX, mouseY, delta);
|
||||
}
|
||||
|
||||
public void removed() {
|
||||
options.save();
|
||||
}
|
||||
}
|
41
src/main/java/cmods/haxxor/client/ui/CycleButtonWidget.java
Normal file
41
src/main/java/cmods/haxxor/client/ui/CycleButtonWidget.java
Normal file
@ -0,0 +1,41 @@
|
||||
package cmods.haxxor.client.ui;
|
||||
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public class CycleButtonWidget extends ButtonWidget {
|
||||
private final Text[] options;
|
||||
private final CycleAction onCycle;
|
||||
private int selectedIndex;
|
||||
|
||||
|
||||
public CycleButtonWidget(int x, int y, int width, int height, Text[] options, int startIndex, CycleAction onCycle) {
|
||||
this(x, y, width, height, options, startIndex, onCycle, EMPTY);
|
||||
}
|
||||
|
||||
public CycleButtonWidget(int x, int y, int width, int height, Text[] options, int startIndex, CycleAction onCycle, TooltipSupplier tooltipSupplier) {
|
||||
super(x, y, width, height, options[startIndex], onCycle, tooltipSupplier);
|
||||
this.options = options;
|
||||
this.onCycle = onCycle;
|
||||
this.selectedIndex = startIndex;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onPress() {
|
||||
selectedIndex++;
|
||||
if (selectedIndex >= options.length) {
|
||||
selectedIndex = 0;
|
||||
}
|
||||
|
||||
this.setMessage(options[selectedIndex]);
|
||||
this.onCycle.onCycle(this, selectedIndex);
|
||||
}
|
||||
|
||||
public interface CycleAction extends PressAction {
|
||||
void onCycle(ButtonWidget button, int newIndex);
|
||||
|
||||
@Override
|
||||
default void onPress(ButtonWidget button) { }
|
||||
}
|
||||
}
|
115
src/main/java/cmods/haxxor/client/ui/FarmerOptionsScreen.java
Normal file
115
src/main/java/cmods/haxxor/client/ui/FarmerOptionsScreen.java
Normal file
@ -0,0 +1,115 @@
|
||||
package cmods.haxxor.client.ui;
|
||||
|
||||
import cmods.haxxor.client.HaxxorClient;
|
||||
import cmods.haxxor.client.HaxxorOptions;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.screen.ScreenTexts;
|
||||
import net.minecraft.text.Text;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static cmods.haxxor.client.ui.Constants.*;
|
||||
|
||||
public class FarmerOptionsScreen extends Screen {
|
||||
private final Screen parent;
|
||||
private final HaxxorOptions options = HaxxorOptions.getInstance();
|
||||
|
||||
protected FarmerOptionsScreen(Screen parent) {
|
||||
super(Text.translatable("haxxor.options.farmer.title"));
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
if (client == null)
|
||||
return;
|
||||
|
||||
final Text enabledText = Text.translatable("haxxor.state.enabled");
|
||||
final Text disabledText = Text.translatable("haxxor.state.disabled");
|
||||
|
||||
final int column1 = this.width / 2 + column1_offset;
|
||||
final int column2 = this.width / 2 + column2_offset;
|
||||
final int startHeight = (int) Math.floor(this.height * startHeight_multiplier);
|
||||
final int doneButtonX = this.width / 2 + doneButtonX_offset;
|
||||
|
||||
int row = 0;
|
||||
|
||||
addDrawableChild(new ButtonWidget(column1, startHeight, buttonWidth, buttonHeight,
|
||||
options.autoFarmer.enabled ? enabledText : disabledText,
|
||||
button -> button.setMessage(HaxxorClient.toggleAutoFarmer() ? enabledText : disabledText)));
|
||||
|
||||
addDrawableChild(new ButtonWidget(column2, startHeight, buttonWidth, buttonHeight,
|
||||
Text.translatable("haxxor.options.farmer.edit_actions"),
|
||||
button -> client.setScreen(new CropSelectScreen(this))));
|
||||
|
||||
row++;
|
||||
|
||||
addDrawableChild(new ToggleEnableButtonWidget(column1, startHeight + (rowIncrement * row), buttonWidth,
|
||||
buttonHeight, Text.literal("Move Seeds"), options.autoFarmer.move_seeds,
|
||||
(button, isEnabled) -> options.autoFarmer.move_seeds = isEnabled));
|
||||
|
||||
row++;
|
||||
|
||||
addVariableAdjust(column1, startHeight + (rowIncrement * row), buttonWidth, buttonHeight, options.autoFarmer.min_y,
|
||||
Text.translatable("haxxor.options.farmer.min_y"),
|
||||
() -> --options.autoFarmer.min_y,
|
||||
() -> ++options.autoFarmer.min_y);
|
||||
|
||||
addVariableAdjust(column2, startHeight + (rowIncrement * row), buttonWidth, buttonHeight, options.autoFarmer.max_y,
|
||||
Text.translatable("haxxor.options.farmer.max_y"),
|
||||
() -> --options.autoFarmer.max_y,
|
||||
() -> ++options.autoFarmer.max_y);
|
||||
|
||||
row++;
|
||||
|
||||
addVariableAdjust(column1, startHeight + (rowIncrement * row), buttonWidth, buttonHeight, options.autoFarmer.horizontal_reach,
|
||||
Text.translatable("haxxor.options.farmer.reach"),
|
||||
() -> --options.autoFarmer.horizontal_reach,
|
||||
() -> ++options.autoFarmer.horizontal_reach);
|
||||
|
||||
addVariableAdjust(column2, startHeight + (rowIncrement * row), buttonWidth, buttonHeight, options.autoFarmer.max_actions_per_tick,
|
||||
Text.translatable("haxxor.options.farmer.actions_per_tick"),
|
||||
() -> options.autoFarmer.max_actions_per_tick -= 5,
|
||||
() -> options.autoFarmer.max_actions_per_tick += 5);
|
||||
|
||||
row++;
|
||||
|
||||
this.addDrawableChild(new ButtonWidget(doneButtonX,
|
||||
startHeight + (rowIncrement * row) + doneButtonRowIncrement, doneButtonWidth, buttonHeight,
|
||||
ScreenTexts.DONE, button -> client.setScreen(parent)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private void addVariableAdjust(int x, int y, int width, int height, int initialValue, @NotNull Text label,
|
||||
UpdateTextAction minus, UpdateTextAction add) {
|
||||
final int button_width = height + height / 4;
|
||||
final String labelStr = label.getString() + ": ";
|
||||
|
||||
ButtonWidget middle = new ButtonWidget(x + button_width - 1, y, width - (button_width * 2) + 2, height,
|
||||
Text.literal(labelStr + initialValue), button -> {});
|
||||
this.addDrawableChild(middle);
|
||||
|
||||
this.addDrawableChild(new ButtonWidget(x, y, button_width, height, Text.literal("-"),
|
||||
button -> middle.setMessage(Text.literal(labelStr + minus.onUpdate()))));
|
||||
this.addDrawableChild(new ButtonWidget(x + width - button_width + 1, y, button_width, height, Text.literal("+"),
|
||||
button -> middle.setMessage(Text.literal(labelStr + add.onUpdate()))));
|
||||
}
|
||||
|
||||
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
|
||||
this.renderBackground(matrices);
|
||||
drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 15, 0xffffff);
|
||||
super.render(matrices, mouseX, mouseY, delta);
|
||||
}
|
||||
|
||||
public void removed() {
|
||||
options.save();
|
||||
}
|
||||
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
private interface UpdateTextAction {
|
||||
int onUpdate();
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package cmods.haxxor.client.ui;
|
||||
|
||||
import cmods.haxxor.client.HaxxorClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.screen.ScreenTexts;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import static cmods.haxxor.client.ui.Constants.*;
|
||||
|
||||
public class HaxxorOptionsScreen extends Screen {
|
||||
private final Screen parent;
|
||||
|
||||
public HaxxorOptionsScreen(Screen parent) {
|
||||
super(Text.translatable("haxxor.options.title"));
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
if (client == null)
|
||||
return;
|
||||
|
||||
final int column1 = this.width / 2 + column1_offset;
|
||||
final int startHeight = (int) Math.floor(this.height * startHeight_multiplier);
|
||||
final int doneButtonX = this.width / 2 + doneButtonX_offset;
|
||||
|
||||
this.addDrawableChild(new ButtonWidget(column1, startHeight, buttonWidth, buttonHeight,
|
||||
Text.translatable("haxxor.options.farmer"),
|
||||
button -> this.client.setScreen(new FarmerOptionsScreen(this))));
|
||||
|
||||
this.addDrawableChild(new ButtonWidget(doneButtonX, startHeight + rowIncrement + doneButtonRowIncrement,
|
||||
doneButtonWidth, buttonHeight, ScreenTexts.DONE, button -> this.client.setScreen(this.parent)));
|
||||
}
|
||||
|
||||
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
|
||||
renderBackground(matrices);
|
||||
Text versionText = Text.literal("v" + HaxxorClient.version);
|
||||
|
||||
|
||||
drawCenteredText(matrices, textRenderer, title, this.width / 2, 15, 0xffffff);
|
||||
drawTextWithShadow(matrices, textRenderer, versionText, this.width - textRenderer.getWidth(versionText) - 2,
|
||||
this.height - textRenderer.fontHeight - 2, 0xffffff);
|
||||
super.render(matrices, mouseX, mouseY, delta);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package cmods.haxxor.client.ui;
|
||||
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public class ToggleEnableButtonWidget extends ButtonWidget {
|
||||
private final String name;
|
||||
private boolean enabled;
|
||||
private final ToggleAction onToggle;
|
||||
|
||||
private final String enabledText = Text.translatable("haxxor.state.enabled").getString();
|
||||
private final String disabledText = Text.translatable("haxxor.state.disabled").getString();
|
||||
|
||||
|
||||
public ToggleEnableButtonWidget(int x, int y, int width, int height, Text name, boolean startEnabled,
|
||||
ToggleAction onToggle) {
|
||||
this(x, y, width, height, name, startEnabled, onToggle, EMPTY);
|
||||
}
|
||||
|
||||
public ToggleEnableButtonWidget(int x, int y, int width, int height, Text name, boolean startEnabled,
|
||||
ToggleAction onToggle, TooltipSupplier tooltipSupplier) {
|
||||
super(x, y, width, height, name, onToggle, tooltipSupplier);
|
||||
this.name = name.getString() + ": ";
|
||||
this.enabled = startEnabled;
|
||||
this.onToggle = onToggle;
|
||||
}
|
||||
|
||||
private void updateText() {
|
||||
setMessage(Text.literal(name + (enabled ? enabledText : disabledText)));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onPress() {
|
||||
onToggle.onToggle(this, enabled = !enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderButton(MatrixStack matrices, int mouseX, int mouseY, float delta) {
|
||||
updateText();
|
||||
super.renderButton(matrices, mouseX, mouseY, delta);
|
||||
}
|
||||
|
||||
public interface ToggleAction extends PressAction {
|
||||
void onToggle(ButtonWidget button, boolean isEnabled);
|
||||
|
||||
@Override
|
||||
default void onPress(ButtonWidget button) { }
|
||||
}
|
||||
}
|
60
src/main/java/cmods/haxxor/mixin/HudMixin.java
Normal file
60
src/main/java/cmods/haxxor/mixin/HudMixin.java
Normal file
@ -0,0 +1,60 @@
|
||||
package cmods.haxxor.mixin;
|
||||
|
||||
import cmods.haxxor.client.AutoFarmer;
|
||||
import cmods.haxxor.client.HaxxorOptions;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.client.gui.DrawableHelper;
|
||||
import net.minecraft.client.gui.hud.InGameHud;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Mixin(InGameHud.class)
|
||||
public abstract class HudMixin extends DrawableHelper {
|
||||
|
||||
@Shadow @Final private MinecraftClient client;
|
||||
@Shadow public abstract TextRenderer getTextRenderer();
|
||||
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "render")
|
||||
private void render(MatrixStack matrices, float tickDelta, CallbackInfo callback) {
|
||||
if (this.client.options.debugEnabled || client.player == null)
|
||||
return;
|
||||
|
||||
HaxxorOptions options = HaxxorOptions.getInstance();
|
||||
TextRenderer textRenderer = this.getTextRenderer();
|
||||
ArrayList<Pair<Text, Integer>> lines = new ArrayList<>();
|
||||
|
||||
int x = 5;
|
||||
int y = 5;
|
||||
|
||||
int red = 0xff0000;
|
||||
int green = 0x00ff00;
|
||||
|
||||
|
||||
if (options.autoFarmer.enabled) {
|
||||
lines.add(new Pair<>(Text.translatable("haxxor.state.on"), green));
|
||||
} else {
|
||||
lines.add(new Pair<>(Text.translatable("haxxor.state.off"), red));
|
||||
}
|
||||
|
||||
if (AutoFarmer.canFarm()) {
|
||||
lines.add(new Pair<>(Text.translatable("haxxor.actions.available"), green));
|
||||
}
|
||||
|
||||
|
||||
for (Pair<Text, Integer> line: lines) {
|
||||
DrawableHelper.drawTextWithShadow(matrices, textRenderer, line.getFirst(), x, y, line.getSecond());
|
||||
y += 10;
|
||||
}
|
||||
}
|
||||
}
|
29
src/main/java/cmods/haxxor/mixin/OptionsMixin.java
Normal file
29
src/main/java/cmods/haxxor/mixin/OptionsMixin.java
Normal file
@ -0,0 +1,29 @@
|
||||
package cmods.haxxor.mixin;
|
||||
|
||||
import cmods.haxxor.client.ui.HaxxorOptionsScreen;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.option.OptionsScreen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(OptionsScreen.class)
|
||||
public class OptionsMixin extends Screen {
|
||||
|
||||
protected OptionsMixin(Text title) {
|
||||
super(title);
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "init")
|
||||
private void init(CallbackInfo ci) {
|
||||
if (client == null)
|
||||
return;
|
||||
|
||||
this.addDrawableChild(new ButtonWidget(20, 20, 100, 20,
|
||||
Text.translatable("haxxor.options"), (button) ->
|
||||
client.setScreen(new HaxxorOptionsScreen(this))));
|
||||
}
|
||||
}
|
30
src/main/java/cmods/haxxor/mixin/PauseMixin.java
Normal file
30
src/main/java/cmods/haxxor/mixin/PauseMixin.java
Normal file
@ -0,0 +1,30 @@
|
||||
package cmods.haxxor.mixin;
|
||||
|
||||
|
||||
import cmods.haxxor.client.ui.HaxxorOptionsScreen;
|
||||
import net.minecraft.client.gui.screen.GameMenuScreen;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(GameMenuScreen.class)
|
||||
public class PauseMixin extends Screen {
|
||||
|
||||
protected PauseMixin(Text title) {
|
||||
super(title);
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "init")
|
||||
public void init(CallbackInfo ci) {
|
||||
if (client == null)
|
||||
return;
|
||||
|
||||
this.addDrawableChild(new ButtonWidget(20, 20, 100, 20,
|
||||
Text.translatable("haxxor.options"), (button) ->
|
||||
client.setScreen(new HaxxorOptionsScreen(this))));
|
||||
}
|
||||
}
|
BIN
src/main/resources/assets/haxxor/icon.png
Normal file
BIN
src/main/resources/assets/haxxor/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
26
src/main/resources/assets/haxxor/lang/en_us.json
Normal file
26
src/main/resources/assets/haxxor/lang/en_us.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"haxxor.state.on": "On",
|
||||
"haxxor.state.off": "Off",
|
||||
"haxxor.state.enabled": "Enabled",
|
||||
"haxxor.state.disabled": "Disabled",
|
||||
|
||||
"haxxor.actions.available": "Actions available",
|
||||
"haxxor.actions.unavailable": "Actions unavailable",
|
||||
|
||||
"haxxor.options": "Haxxor",
|
||||
"haxxor.options.title": "Haxxor Options",
|
||||
"haxxor.options.farmer": "Auto Farm",
|
||||
"haxxor.options.farmer.title": "Auto Farm Options",
|
||||
"haxxor.options.farmer.max_y": "Max Y Offset",
|
||||
"haxxor.options.farmer.min_y": "Min Y Offset",
|
||||
"haxxor.options.farmer.reach": "Reach",
|
||||
"haxxor.options.farmer.edit_actions": "Configure Actions",
|
||||
"haxxor.options.farmer.actions_per_tick": "Max Per Tick",
|
||||
"haxxor.options.farmer.crop_select.title": "Toggle Actions",
|
||||
"haxxor.options.farmer.crop_select.seeds": "Seeds to Plant",
|
||||
"haxxor.options.farmer.crop_select.blocks": "Crops to Break",
|
||||
|
||||
"category.haxxor.options": "Haxxor",
|
||||
"key.haxxor.auto_farm": "Auto Farm Toggle",
|
||||
"key.haxxor.swap_items": "Swap Items"
|
||||
}
|
30
src/main/resources/fabric.mod.json
Normal file
30
src/main/resources/fabric.mod.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "haxxor",
|
||||
"version": "${version}",
|
||||
"name": "Haxxor",
|
||||
"description": "A collection of hacks because yes",
|
||||
"authors": [
|
||||
"Cameron Reed"
|
||||
],
|
||||
"contact": {
|
||||
"sources": "https://gitea.cam123.dev/CameronReed/cmods-haxxor"
|
||||
},
|
||||
"license": "MIT",
|
||||
"icon": "assets/haxxor/icon.png",
|
||||
"environment": "client",
|
||||
"entrypoints": {
|
||||
"client": [
|
||||
"cmods.haxxor.client.HaxxorClient"
|
||||
],
|
||||
"modmenu": ["cmods.haxxor.client.ModMenuConfig"]
|
||||
},
|
||||
"mixins": [
|
||||
"haxxor.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.14.10",
|
||||
"fabric": "*",
|
||||
"minecraft": "1.19.2"
|
||||
}
|
||||
}
|
16
src/main/resources/haxxor.mixins.json
Normal file
16
src/main/resources/haxxor.mixins.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "cmods.haxxor.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
],
|
||||
"client": [
|
||||
"HudMixin",
|
||||
"OptionsMixin",
|
||||
"PauseMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user