Compare commits

..

35 commits

Author SHA1 Message Date
115c4f0470
fix: use gitversion properly 2024-05-08 23:26:10 +02:00
7640b4f6b8
Merge branch 'dev' of fantabos.co:ftbsc/bscv into dev 2024-02-14 20:31:52 +01:00
5adc5da6cd
feat: block and item id search 2024-02-14 20:30:53 +01:00
f1b2842357
fix: multiblock updates show correctly
the callback blockpos is always the same, clone it to store it and it
now works as intended
2024-01-17 01:46:47 +01:00
57dd48049d
fix: only hide effects when no gui is shown 2024-01-17 00:36:57 +01:00
2893438f64
feat: add distance option to autofish 2024-01-17 00:18:13 +01:00
85f8adb577 Merge branch 'dev' of https://git.fantabos.co/bscv into dev 2024-01-10 23:35:23 +01:00
a2df8fd999 spot player(s) when they enter render distance 2024-01-10 23:35:13 +01:00
63cfbaa56c
feat[containercleaner]: throw whole stacks 2023-11-26 00:07:22 +01:00
aebd63ac13
feat: /mods command lists all mods
badly tho: it doesn't fit on screen and must be read from minecraft logs
2023-11-13 05:02:17 +01:00
b2caa0f762
chore: gitignore factorypath, who creates it? 2023-11-13 04:42:11 +01:00
34b96b67d3
feat: added crude fastcraft 2023-11-13 04:41:06 +01:00
939a0f7a40
fix: typo 2023-11-13 04:40:59 +01:00
cf69868863
feat: use list of integers (ids) for containerclean 2023-11-13 04:27:23 +01:00
0045af0117
chore: better default reach for aura 2023-11-13 04:26:49 +01:00
c2874312d3
feat: added item search command
also renamed because it clashed with import
2023-11-13 04:26:27 +01:00
72333dfd33
chore: NoOverlay is not really a hud mod 2023-11-13 04:26:06 +01:00
399af0c12d
chore: better defaults for VanillaFlight 2023-11-13 04:25:49 +01:00
3638f7f9c1
chore: move regex filters from Highlighter to utils 2023-11-13 04:25:29 +01:00
bfc6d4fef6
feat: added Many setting for collections
still very raw and not super helpful but kind of usable?
2023-11-13 04:24:49 +01:00
add2ea7945
feat: add crude regex containercleaner
also works on self inventory btw
2023-11-12 06:03:18 +01:00
12f1ec92a0
feat: allow to select prefer-looting in autoweapon
yes i know that *technically* a sharp 5 axe has 3 DPS and a god sword
has only 2.9411763880904593 but if a mob dies in 3 attacks, faster
attacks means it will die faster, also looting is usually more
important, to say nothing about fire aspect which deals DoT and sweeping
edge which deals AoE damage. USE THE SWORD!!!!!
2023-11-11 15:29:52 +01:00
b71dcba7a2
feat: updated cursor commands, added block search 2023-11-02 16:52:31 +01:00
6201f66c85
feat: added ruler 2023-11-02 16:52:21 +01:00
78b9ffa352
feat: added initial bad impl of HandChanger 2023-11-02 16:51:55 +01:00
bf5405d64d
feat: allow disabling drift in vanillaflight 2023-06-21 00:15:07 +02:00
134d6fedaa
chore: removed unneeded imports and implements 2023-06-21 00:10:23 +02:00
434b0cc0cc
fix: aura attacks closest target 2023-06-21 00:03:03 +02:00
954a8c806f
Merge branch 'processor5' into dev 2023-06-20 23:54:17 +02:00
f4ec2cddb1
chore: processor version bump 2023-04-12 01:37:22 +02:00
5a86e4e2be
fix: packet log filename on windows 2023-04-10 17:39:42 +02:00
3d2966d986
fix: updated build.gradle 2023-04-06 15:00:42 +02:00
a5271a1d32
fix: reference inner class name in patch finder 2023-04-06 14:46:08 +02:00
9c8a192866
chore: updated to 0.5.1, direct hook targeting 2023-04-02 23:52:02 +02:00
d90f2ca4d9
chore: upgraded patches to lillero-processor 0.5 2023-03-28 14:26:36 +02:00
44 changed files with 902 additions and 355 deletions

3
.gitignore vendored
View file

@ -18,6 +18,9 @@ build
.gradle
gradle.properties
# ??? gradle again ???
.factorypath
# other
eclipse
run

View file

@ -6,12 +6,10 @@ plugins {
alias libs.plugins.checkerFramework
}
version = gitVersion()
version = versionDetails().lastTag
group = 'ftbsc'
archivesBaseName = 'bscv'
def shortVersion = version.split('-')[0].replaceAll(".dirty", "") // necessary when there are no extra commits on tags, and thus no dash
project.ext {
deployJarDo = getProjectProperty("deployJar.do", "false")
deployJarTargetDir = getProjectProperty("deployJar.targetDir", ".")
@ -66,11 +64,11 @@ dependencies {
}
compileJava { //mappings for lillero-processor
options.compilerArgs << '-AmappingsFile=https://data.fantabos.co/output.tsrg'
options.compilerArgs << '-AmappingsFile=https://data.fantabos.co/1.16.5.tsrg'
}
jar {
archiveFileName = "${jar.archiveBaseName.get()}-${shortVersion}.${jar.archiveExtension.get()}"
archiveFileName = "${jar.archiveBaseName.get()}-${archiveVersion.get()}.${jar.archiveExtension.get()}"
manifest {
attributes([
"Specification-Title": "bscv",

View file

@ -4,8 +4,8 @@ gitVersion = "0.13.0"
minecraft = "1.16.5"
forge = "1.16.5-36.2.34"
autoService = "1.0.1"
lillero = "0.3.4"
lilleroProcessor = "0.4.2"
lillero = "0.4.1"
lilleroProcessor = "0.5.2"
checkerFramework = "0.6.24"
[plugins]

View file

@ -8,6 +8,7 @@ import ftbsc.bscv.api.IModule;
import ftbsc.bscv.patches.CommandsPatch.CommandsBuiltEvent;
import ftbsc.bscv.system.Friends;
import ftbsc.bscv.system.ModManager;
import ftbsc.bscv.system.Ruler;
import net.minecraft.client.gui.screen.IngameMenuScreen;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.command.CommandSource;
@ -42,6 +43,9 @@ public class Boscovicino implements ICommons {
private static Friends friends;
public static Friends friends() { return Boscovicino.friends; }
@SuppressWarnings("unused") // it just needs to exist to be used by player
private static Ruler ruler;
public Boscovicino() {
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onSetupComplete);
@ -53,6 +57,8 @@ public class Boscovicino implements ICommons {
Boscovicino.modManager.finish();
Boscovicino.ruler = new Ruler();
Boscovicino.spec = cfg.build();
ForgeConfigSpec.Builder friendSpec = new ForgeConfigSpec.Builder();
@ -71,9 +77,13 @@ public class Boscovicino implements ICommons {
}
public static void log(String message) {
log(message, true);
}
public static void log(String message, boolean overlay) {
LOGGER.info(message);
if (MC.player != null) {
MC.player.displayClientMessage(new StringTextComponent(message), true);
MC.player.displayClientMessage(new StringTextComponent(message), overlay);
}
}

View file

@ -0,0 +1,72 @@
package ftbsc.bscv.commands;
import com.google.auto.service.AutoService;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import ftbsc.bscv.api.ILoadable;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.command.CommandSource;
import net.minecraft.command.Commands;
import net.minecraft.command.arguments.BlockStateArgument;
import net.minecraft.command.arguments.BlockStateInput;
import static ftbsc.bscv.Boscovicino.log;
@AutoService(ILoadable.class)
public class BlockSearch extends AbstractCommand {
@Override
public String getName() { return "block"; }
public LiteralArgumentBuilder<CommandSource> register(LiteralArgumentBuilder<CommandSource> builder) {
return builder
.then(
Commands.literal("search")
.then(
Commands.argument("id", IntegerArgumentType.integer(0))
.executes( ctx -> {
int block_id = ctx.getArgument("id", Integer.class);
int block_number = block_id >> 4;
int block_meta = block_id & 0b1111;
BlockState state = Block.stateById(block_id);
log("block #[%d:%d]::%d >> %s", block_number, block_meta, block_id, state.toString());
return 1;
})
)
.then(
Commands.argument("number", IntegerArgumentType.integer(0))
.then(
Commands.argument("meta", IntegerArgumentType.integer(0))
.executes( ctx -> {
int block_number = ctx.getArgument("number", Integer.class);
int block_meta = ctx.getArgument("meta", Integer.class);
int block_id = (block_number << 4) | block_meta;
BlockState state = Block.stateById(block_id);
log("block #[%d:%d]::%d >> %s", block_number, block_meta, block_id, state.toString());
return 1;
})
)
)
)
.then(
Commands.literal("id")
.then(
Commands.argument("name", BlockStateArgument.block())
.executes( ctx -> {
BlockStateInput arg = ctx.getArgument("name", BlockStateInput.class);
BlockState state = arg.getState();
int block_id = Block.getId(state);
log("block #[%d:%d] >> %s", block_id >> 4, block_id & 0xF, state.toString());
return 1;
})
)
)
.executes(ctx -> {
log("no block specified");
return 0;
});
}
}

View file

@ -4,6 +4,7 @@ import com.google.auto.service.AutoService;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import ftbsc.bscv.api.ILoadable;
import net.minecraft.block.BlockState;
import net.minecraft.command.CommandSource;
import net.minecraft.command.Commands;
import net.minecraft.util.Direction;
@ -18,17 +19,18 @@ public class Cursor extends AbstractCommand {
public LiteralArgumentBuilder<CommandSource> register(LiteralArgumentBuilder<CommandSource> builder) {
return builder
.then(
Commands.literal("pos")
Commands.literal("info")
.executes(ctx -> {
switch (MC.hitResult.getType()) {
case BLOCK:
BlockRayTraceResult result = (BlockRayTraceResult) MC.hitResult;
Direction dir = result.getDirection();
BlockPos pos =result.getBlockPos();
log("Block @ %s (%s)", pos.toString(), dir.toString());
BlockPos pos = result.getBlockPos();
BlockState state = MC.level.getBlockState(pos);
log("Block @ %s (%s): %s", pos.toString(), dir.toString(), state.toString());
return 1;
case ENTITY:
log("Entity @ %s", MC.hitResult.getLocation().toString());
log("Entity @ %s (TODO!)", MC.hitResult.getLocation().toString());
return 1;
default:
case MISS:

View file

@ -1,18 +1,25 @@
package ftbsc.bscv.commands;
import com.google.auto.service.AutoService;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.tools.Inventory;
import net.minecraft.command.CommandSource;
import net.minecraft.command.Commands;
import net.minecraft.command.arguments.ItemArgument;
import net.minecraft.command.arguments.ItemInput;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.Item;
import static ftbsc.bscv.Boscovicino.log;
@AutoService(ILoadable.class)
public class Item extends AbstractCommand {
public class ItemCommand extends AbstractCommand {
@Override
public String getName() { return "item"; }
public LiteralArgumentBuilder<CommandSource> register(LiteralArgumentBuilder<CommandSource> builder) {
return builder
@ -32,6 +39,29 @@ public class Item extends AbstractCommand {
return 1;
})
)
.then(
Commands.literal("search")
.then(
Commands.argument("id", IntegerArgumentType.integer(0))
.executes(ctx -> {
int item_id = ctx.getArgument("id", Integer.class);
log("item #[%d] >> %s", item_id, Item.byId(item_id).toString());
return 1;
})
)
)
.then(
Commands.literal("id")
.then(
Commands.argument("name", ItemArgument.item())
.executes( ctx -> {
ItemInput arg = ctx.getArgument("name", ItemInput.class);
Item item = arg.getItem();
log("item #[%d] >> %s", Item.getId(item), item.toString());
return 1;
})
)
)
.executes(ctx -> {
Slot slot = Inventory.hotbar(MC.player).get(MC.player.inventory.selected);
if (!slot.hasItem()) return 0;

View file

@ -9,7 +9,7 @@ import ftbsc.bscv.api.IModule;
import net.minecraft.command.CommandSource;
import net.minecraft.command.Commands;
import static ftbsc.bscv.Boscovicino.log;
import java.util.stream.Collectors;
@AutoService(ILoadable.class)
public class ModCommands extends AbstractCommand {
@ -43,8 +43,11 @@ public class ModCommands extends AbstractCommand {
})
)
.executes(ctx -> {
log("no args specified");
return 0;
String mods = Boscovicino.modManager.mods.stream()
.map(x -> x.getName())
.collect(Collectors.joining(","));
Boscovicino.log("[ %s ]", mods);
return 1;
});
}

View file

@ -1,6 +1,7 @@
package ftbsc.bscv.modules;
import ftbsc.bscv.Boscovicino;
import ftbsc.bscv.tools.Keybind;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.client.util.InputMappings;
import net.minecraftforge.client.event.InputEvent;
@ -51,7 +52,7 @@ public abstract class QuickModule extends AbstractModule {
public QuickModule() {
super();
this.keybind = new KeyBinding(key_name(this.getName()), this.getDefaultKey(), key_category());
this.keybind = new KeyBinding(Keybind.name(this.getName()), this.getDefaultKey(), Keybind.category());
ClientRegistry.registerKeyBinding(this.keybind);
// register a separate subclass on the hook, so that it's always listening
@ -76,12 +77,4 @@ public abstract class QuickModule extends AbstractModule {
// );
}
private static String key_name(String name) {
return String.format("key.%s.%s", Boscovicino.MOD_ID, name);
}
private static String key_category() {
return String.format("key.category.%s", Boscovicino.MOD_ID);
}
}

View file

@ -3,7 +3,6 @@ package ftbsc.bscv.modules.defense;
import com.google.auto.service.AutoService;
import ftbsc.bscv.Boscovicino;
import ftbsc.bscv.ICommons;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.QuickModule;
import ftbsc.bscv.modules.self.AutoTool;
@ -23,7 +22,7 @@ import net.minecraftforge.event.TickEvent.Phase;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class Aura extends QuickModule implements ICommons {
public class Aura extends QuickModule {
private enum LookType {
NONE,
@ -53,7 +52,7 @@ public class Aura extends QuickModule implements ICommons {
this.reach = Setting.Decimal.builder()
.min(0.)
.fallback(5.)
.fallback(4.)
.name("reach")
.comment("aura attack reach")
.build(this);
@ -129,6 +128,9 @@ public class Aura extends QuickModule implements ICommons {
if (MC.player.getAttackStrengthScale(0.f) < this.strenght.get()) return;
float distance = Float.MAX_VALUE;
Entity target = null;
for (Entity e : MC.level.entitiesForRendering()) {
if (e.equals(MC.player)) continue;
if (!(e instanceof LivingEntity)) continue;
@ -143,13 +145,21 @@ public class Aura extends QuickModule implements ICommons {
}
if (this.trace.get() && !MC.player.canSee(e)) continue;
float dist = MC.player.distanceTo(e);
if (dist < distance) {
distance = dist;
target = e;
}
}
if (target != null) {
switch (this.look.get()) {
case ONCE:
MC.player.lookAt(Type.EYES, e.getEyePosition(1.0F));
MC.player.lookAt(Type.EYES, target.getEyePosition(1.0F));
MC.player.connection.send(new CPlayerPacket.RotationPacket(MC.player.yRot, MC.player.xRot, MC.player.isOnGround()));
break;
case PACKET:
this.lookAtHidden(Type.EYES, e.getEyePosition(1.0F));
this.lookAtHidden(Type.EYES, target.getEyePosition(1.0F));
break;
case NONE: break;
}
@ -157,12 +167,10 @@ public class Aura extends QuickModule implements ICommons {
if (this.tool.get()) {
this.autotool.selectBestWeapon();
}
MC.gameMode.attack(MC.player, e);
MC.gameMode.attack(MC.player, target);
if (this.swing.get()) {
MC.player.swing(Hand.MAIN_HAND);
}
break; // TODO should find all valid targets and choose one rather than stopping here
}
}
}

View file

@ -4,6 +4,7 @@ import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import ftbsc.bscv.modules.AbstractModule;
import ftbsc.bscv.tools.Inventory;
import ftbsc.bscv.tools.Setting;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.inventory.container.Slot;
@ -48,38 +49,6 @@ public class Highlighter extends AbstractModule {
this.pattern = Pattern.compile(this.query.get());
}
private List<String> enchantments(ItemStack stack) {
final ListNBT tags;
if (Items.ENCHANTED_BOOK.equals(stack.getItem())) {
tags = EnchantedBookItem.getEnchantments(stack); // special case to also search book enchants
} else {
tags = stack.getEnchantmentTags();
}
List<String> out = new ArrayList<>();
for (int i = 0; i < tags.size(); i++) {
CompoundNBT tag = tags.getCompound(i);
out.add(String.format("%s %s", tag.getString("id"), tag.getInt("lvl")));
}
return out;
}
private boolean matches(ItemStack stack) {
if (stack.isEmpty()) return false;
String displayName = stack.getDisplayName().getString();
if (this.pattern.matcher(displayName).find()) return true;
if (Items.ENCHANTED_BOOK.equals(stack.getItem()) || stack.isEnchanted()) {
for (String ench : this.enchantments(stack)) {
if (this.pattern.matcher(ench).find()) return true;
}
}
return false;
}
@SubscribeEvent
public void onGuiContainerDraw(GuiContainerEvent.DrawBackground event) {
MatrixStack matrix = event.getMatrixStack();
@ -91,7 +60,7 @@ public class Highlighter extends AbstractModule {
for (Slot slot : screen.getMenu().slots) {
ItemStack stack = slot.getItem();
if (this.matches(stack)) {
if (Inventory.matchItem(this.pattern, stack)) {
GuiUtils.drawGradientRect(
matrix.last().pose(), 0,
slot.x, slot.y, slot.x + 16, slot.y + 16,

View file

@ -175,11 +175,14 @@ public class InfoDisplay extends HudModule {
@SubscribeEvent
public void onRenderOverlay(RenderGameOverlayEvent event) {
if (event.getType() == ElementType.POTION_ICONS) {
if (this.hide_effects.get() && event.isCancelable()) {
if (
event.getType() == ElementType.POTION_ICONS
&& MC.screen == null
&& this.hide_effects.get()
&& event.isCancelable()
) {
event.setCanceled(true);
}
}
if (event.getType() != ElementType.TEXT) return;
if (this.shouldHide()) return;

View file

@ -1,19 +1,38 @@
package ftbsc.bscv.modules.hud;
import com.google.auto.service.AutoService;
import ftbsc.bscv.ICommons;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.HudModule;
import ftbsc.bscv.tools.Setting;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import static ftbsc.bscv.tools.Text.TextBuilder;
import static ftbsc.bscv.Boscovicino.log;
@AutoService(ILoadable.class)
public class PlayerList extends HudModule implements ICommons {
public class PlayerList extends HudModule {
public final ForgeConfigSpec.ConfigValue<Boolean> notify;
public PlayerList() {
super();
this.notify = Setting.Bool.builder()
.fallback(false)
.name("notify")
.comment("notify when players enter render distance")
.build(this);
}
@SubscribeEvent
public void onRenderOverlay(RenderGameOverlayEvent event) {
@ -35,4 +54,14 @@ public class PlayerList extends HudModule implements ICommons {
offset += MC.font.lineHeight;
}
}
@SubscribeEvent
public void onEntityEntersRenderdistance(EntityJoinWorldEvent event) {
if (!notify.get()) return;
if (event.getEntity() instanceof PlayerEntity){
PlayerEntity player = (PlayerEntity) event.getEntity();
if (MC.player != null && player.getId() == MC.player.getId()) return;
log(String.format("%s spotted", player.getDisplayName().getString()), false);
}
}
}

View file

@ -1,21 +0,0 @@
package ftbsc.bscv.modules.hud;
import ftbsc.bscv.modules.AbstractModule;
import ftbsc.bscv.tools.Setting;
import net.minecraftforge.common.ForgeConfigSpec;
public class Terminal extends AbstractModule {
public final ForgeConfigSpec.ConfigValue<Integer> msg_count;
public Terminal() {
super();
this.msg_count = Setting.Number.builder()
.min(-1)
.fallback(100)
.name("msg-count")
.comment("How many messages to keep in chat, set to 0 for unlimited")
.build(this);
}
}

View file

@ -1,12 +1,11 @@
package ftbsc.bscv.modules.motion;
import com.google.auto.service.AutoService;
import ftbsc.bscv.ICommons;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.QuickModule;
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
import ftbsc.bscv.tools.Keyboard;
import ftbsc.bscv.tools.Setting;
import net.minecraft.client.entity.player.ClientPlayerEntity;
import net.minecraft.network.play.client.CPlayerPacket;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraftforge.common.ForgeConfigSpec;
@ -26,6 +25,7 @@ public class VanillaFlight extends QuickModule {
private static final int MS_PER_TICK = 50;
public final ForgeConfigSpec.ConfigValue<Boolean> force;
public final ForgeConfigSpec.ConfigValue<Boolean> drift;
public final ForgeConfigSpec.ConfigValue<Double> speed;
public final ForgeConfigSpec.ConfigValue<AntikickMode> antikick;
public final ForgeConfigSpec.ConfigValue<Double> antikick_magnitude;
@ -40,18 +40,24 @@ public class VanillaFlight extends QuickModule {
this.force = Setting.Bool.builder()
.name("force")
.comment("force enable flight on user")
.fallback(true)
.build(this);
this.drift = Setting.Bool.builder()
.name("drift")
.comment("gradually reduce momentum")
.fallback(false)
.build(this);
this.speed = Setting.Decimal.builder()
.min(0.)
.fallback(0.05)
.fallback(0.1)
.name("speed")
.comment("flight speed to set")
.build(this);
this.antikick = Setting.Switch.builder(AntikickMode.class)
.fallback(AntikickMode.NONE)
.fallback(AntikickMode.PACKET)
.name("antikick")
.comment("prevent vanilla flight kick by descending")
.build(this);
@ -103,6 +109,10 @@ public class VanillaFlight extends QuickModule {
MC.player.abilities.flying = true;
}
if (!this.drift.get() && !Keyboard.isMoving()) {
MC.player.setDeltaMovement(Vector3d.ZERO);
}
this.tick = ( this.tick + 1 ) % this.antikick_cycle.get();
Vector3d pos = MC.player.position();

View file

@ -34,7 +34,7 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class PacketLogger extends QuickModule {
public static final SimpleDateFormat CAPTURE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
public static final SimpleDateFormat CAPTURE_DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd@HH-mm-ss");
@Override
public void enable() {

View file

@ -1,7 +1,6 @@
package ftbsc.bscv.modules.self;
import com.google.auto.service.AutoService;
import ftbsc.bscv.ICommons;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.AbstractModule;
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
@ -13,7 +12,7 @@ import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class AntiHunger extends AbstractModule implements ICommons {
public class AntiHunger extends AbstractModule {
public final ForgeConfigSpec.ConfigValue<Boolean> sprint;
public final ForgeConfigSpec.ConfigValue<Boolean> hover;

View file

@ -1,7 +1,6 @@
package ftbsc.bscv.modules.self;
import com.google.auto.service.AutoService;
import ftbsc.bscv.ICommons;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.AbstractModule;
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
@ -13,7 +12,7 @@ import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class AutoDisconnect extends AbstractModule implements ICommons {
public class AutoDisconnect extends AbstractModule {
public final ForgeConfigSpec.ConfigValue<Double> threshold;

View file

@ -1,7 +1,6 @@
package ftbsc.bscv.modules.self;
import com.google.auto.service.AutoService;
import ftbsc.bscv.ICommons;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.AbstractModule;
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
@ -10,14 +9,16 @@ import net.minecraft.client.Minecraft;
import net.minecraft.network.play.server.SPlaySoundEffectPacket;
import net.minecraft.util.Hand;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class AutoFish extends AbstractModule implements ICommons {
public class AutoFish extends AbstractModule {
public final ForgeConfigSpec.ConfigValue<Boolean> recast;
public final ForgeConfigSpec.ConfigValue<Integer> delay;
public final ForgeConfigSpec.ConfigValue<Double> distance;
// public final ForgeConfigSpec.ConfigValue<Long> reaction;
public AutoFish() {
@ -34,13 +35,23 @@ public class AutoFish extends AbstractModule implements ICommons {
.name("delay")
.comment("how long in ms to wait before recasting hook")
.build(this);
this.distance = Setting.Decimal.builder()
.fallback(0.)
.name("distance")
.comment("ignore splashes further than X blocks, set to 0 to disable")
.build(this);
}
@SubscribeEvent
public void onPacket(PacketEvent.Incoming event) {
if (event.packet instanceof SPlaySoundEffectPacket) {
SPlaySoundEffectPacket packet = (SPlaySoundEffectPacket) event.packet;
if (packet.getSound().equals(SoundEvents.FISHING_BOBBER_SPLASH)) {
Vector3d location = new Vector3d(packet.getX(), packet.getY(), packet.getZ());
if (
packet.getSound().equals(SoundEvents.FISHING_BOBBER_SPLASH)
&& (this.distance.get() == 0 || MC.player.position().distanceTo(location) < this.distance.get())
) {
MC.gameMode.useItem(MC.player, MC.level, Hand.MAIN_HAND);
if (this.recast.get()) {
new RecastThread(MC, this.delay.get()).start();
@ -49,6 +60,7 @@ public class AutoFish extends AbstractModule implements ICommons {
}
}
// TODO don't spawn a thread, minecraft has a way to schedule actions for later
private class RecastThread extends Thread {
private long delay;
private Minecraft mc;

View file

@ -1,12 +1,14 @@
package ftbsc.bscv.modules.self;
import com.google.auto.service.AutoService;
import ftbsc.bscv.ICommons;
import ftbsc.bscv.Boscovicino;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.AbstractModule;
import ftbsc.bscv.tools.Inventory;
import ftbsc.bscv.tools.Setting;
import net.minecraft.block.BlockState;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockRayTraceResult;
@ -17,9 +19,10 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
import java.util.List;
@AutoService(ILoadable.class)
public class AutoTool extends AbstractModule implements ICommons {
public class AutoTool extends AbstractModule {
public final ForgeConfigSpec.ConfigValue<Integer> limit;
public final ForgeConfigSpec.ConfigValue<Boolean> prefer_looting;
public AutoTool() {
super();
@ -29,6 +32,12 @@ public class AutoTool extends AbstractModule implements ICommons {
.comment("durability limit for tools, set to 0 to destroy them")
.fallback(1)
.build(this);
this.prefer_looting = Setting.Bool.builder()
.name("prefer-looting")
.comment("when picking best weapon, prefer looting over slight more DPS")
.fallback(true)
.build(this);
}
private boolean itemIsTooDamaged(ItemStack item) {
@ -48,6 +57,12 @@ public class AutoTool extends AbstractModule implements ICommons {
}
double damage = Inventory.itemDPS(item);
int looting = Inventory.getEnchLevel(item, Enchantments.MOB_LOOTING);
if (this.prefer_looting.get() && looting > 0) {
damage += 0.1 * looting;
}
if (damage > current_damage) {
current_slot = i;
current_damage = damage;

View file

@ -0,0 +1,79 @@
package ftbsc.bscv.modules.self;
import java.util.ArrayList;
import java.util.List;
import com.google.auto.service.AutoService;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.AbstractModule;
import ftbsc.bscv.tools.Inventory;
import ftbsc.bscv.tools.Setting;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.command.arguments.ItemArgument;
import net.minecraft.command.arguments.ItemInput;
import net.minecraft.inventory.container.ClickType;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.Item;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.event.TickEvent.ClientTickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class ContainerCleaner extends AbstractModule {
public final ForgeConfigSpec.ConfigValue<Integer> cooldown;
public final ForgeConfigSpec.ConfigValue<Boolean> limit;
public final ForgeConfigSpec.ConfigValue<Boolean> all;
public final ForgeConfigSpec.ConfigValue<List<? extends Integer>> blacklist;
private int counter;
public ContainerCleaner() {
super();
this.counter = 0;
this.cooldown = Setting.Number.builder()
.fallback(0)
.name("cooldown")
.comment("ticks before throwing next item")
.build(this);
this.limit = Setting.Bool.builder()
.fallback(true)
.name("limit")
.comment("limit to one action per tick")
.build(this);
this.all = Setting.Bool.builder()
.fallback(true)
.name("all")
.comment("throw whole stacks instead of single items")
.build(this);
this.blacklist = new Setting.Many<ItemInput, Integer>(ItemArgument.item(), ItemInput.class)
.writer(x -> Item.getId(x.getItem()))
.fallback(new ArrayList<Integer>())
.name("blacklist")
.comment("items to throw away")
.build(this);
}
@SubscribeEvent
public void onTick(ClientTickEvent event) {
if (MC.screen == null) return;
if (!(MC.screen instanceof ContainerScreen)) return;
if (this.counter > 0) {
this.counter -= 1;
return;
}
ContainerScreen<?> screen = (ContainerScreen<?>) MC.screen;
for (Slot slot : screen.getMenu().slots) {
if (this.blacklist.get().contains(Item.getId(slot.getItem().getItem()))) {
int button = this.all.get() ? 1 : 0;
Inventory.clickSlot(screen.getMenu().containerId, slot.index, button, ClickType.THROW);
this.counter = this.cooldown.get();
if (this.limit.get()) return; // only throw one item per tick
}
}
}
}

View file

@ -0,0 +1,39 @@
package ftbsc.bscv.modules.self;
import com.google.auto.service.AutoService;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.AbstractModule;
import ftbsc.bscv.tools.Inventory;
import ftbsc.bscv.tools.Setting;
import net.minecraft.client.gui.screen.inventory.InventoryScreen;
import net.minecraft.inventory.container.ClickType;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.event.TickEvent.ClientTickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class FastCraft extends AbstractModule {
public final ForgeConfigSpec.ConfigValue<Boolean> drop;
public FastCraft() {
super();
this.drop = Setting.Bool.builder()
.fallback(false)
.name("drop")
.comment("throw cradted items away instead of moving them back in inventory")
.build(this);
}
@SubscribeEvent
public void onTick(ClientTickEvent event) {
if (MC.screen == null) return;
if (!(MC.screen instanceof InventoryScreen)) return;
InventoryScreen inventory = (InventoryScreen) MC.screen;
if (inventory.getMenu().slots.get(0).hasItem()) {
// TODO can we throw them all? like this it throws one by one
Inventory.clickSlot(0, this.drop.get() ? ClickType.THROW : ClickType.QUICK_MOVE);
}
}
}

View file

@ -1,18 +1,13 @@
package ftbsc.bscv.modules.self;
import com.google.auto.service.AutoService;
import ftbsc.bscv.ICommons;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.QuickModule;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import java.lang.reflect.Field;
import static ftbsc.bscv.Boscovicino.log;
@AutoService(ILoadable.class)
public class FastInteract extends QuickModule implements ICommons {
public class FastInteract extends QuickModule {
protected int getDefaultKey() { return UNBOUND; }

View file

@ -2,7 +2,6 @@ package ftbsc.bscv.modules.self;
import com.google.auto.service.AutoService;
import ftbsc.bscv.Boscovicino;
import ftbsc.bscv.ICommons;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.QuickModule;
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
@ -18,7 +17,7 @@ import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class Freecam extends QuickModule implements ICommons {
public class Freecam extends QuickModule {
public final ForgeConfigSpec.ConfigValue<Boolean> log;
public final ForgeConfigSpec.ConfigValue<Double> speed;

View file

@ -0,0 +1,72 @@
package ftbsc.bscv.modules.self;
import com.google.auto.service.AutoService;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.AbstractModule;
import ftbsc.bscv.tools.Setting;
import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class HandChanger extends AbstractModule {
public final ForgeConfigSpec.ConfigValue<Double> main;
public final ForgeConfigSpec.ConfigValue<Double> off;
public final ForgeConfigSpec.ConfigValue<Boolean> cancel_main;
public final ForgeConfigSpec.ConfigValue<Boolean> cancel_off;
public HandChanger() {
super();
this.main = Setting.Decimal.builder()
.min(0.)
.max(1.)
.name("main")
.comment("height of main hand")
.fallback(1.)
.build(this);
this.off = Setting.Decimal.builder()
.min(0.)
.max(1.)
.name("off")
.comment("height of off hand")
.fallback(1.)
.build(this);
this.cancel_main = Setting.Bool.builder()
.name("cancel-main")
.comment("completely prevent main hand rendering")
.fallback(false)
.build(this);
this.cancel_off = Setting.Bool.builder()
.name("cancel-off")
.comment("completely prevent off hand rendering")
.fallback(false)
.build(this);
}
@SubscribeEvent
public void onRenderHands(RenderHandEvent event) {
switch (event.getHand()) {
case MAIN_HAND:
if (this.cancel_main.get()) {
event.setCanceled(true);
} else if (this.main.get() != 1.0) {
MC.gameRenderer.itemInHandRenderer.mainHandHeight = this.main.get().floatValue(); // ACCESSTRANSFORMER public net.minecraft.client.renderer.FirstPersonRenderer field_187469_f
MC.gameRenderer.itemInHandRenderer.oMainHandHeight = this.main.get().floatValue(); // ACCESSTRANSFORMER public net.minecraft.client.renderer.FirstPersonRenderer field_187469_f
}
break;
case OFF_HAND:
if (this.cancel_off.get()) {
event.setCanceled(true);
} else if (this.off.get() != 1.0) {
MC.gameRenderer.itemInHandRenderer.offHandHeight = this.off.get().floatValue(); // ACCESSTRANSFORMER public net.minecraft.client.renderer.FirstPersonRenderer field_187470_g
MC.gameRenderer.itemInHandRenderer.oOffHandHeight = this.off.get().floatValue(); // ACCESSTRANSFORMER public net.minecraft.client.renderer.FirstPersonRenderer field_187470_g
}
break;
}
}
}

View file

@ -1,4 +1,4 @@
package ftbsc.bscv.modules.hud;
package ftbsc.bscv.modules.self;
import com.google.auto.service.AutoService;

View file

@ -5,14 +5,13 @@ import org.lwjgl.opengl.GL11;
import com.google.auto.service.AutoService;
import com.mojang.blaze3d.platform.GlStateManager;
import ftbsc.bscv.ICommons;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.QuickModule;
import net.minecraftforge.client.event.RenderLivingEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class Chams extends QuickModule implements ICommons {
public class Chams extends QuickModule {
protected int getDefaultKey() { return UNBOUND; }

View file

@ -1,7 +1,6 @@
package ftbsc.bscv.modules.vision;
import com.google.auto.service.AutoService;
import ftbsc.bscv.ICommons;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.QuickModule;
import net.minecraft.potion.Effect;
@ -12,7 +11,7 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
import java.awt.event.KeyEvent;
@AutoService(ILoadable.class)
public class Fullbright extends QuickModule implements ICommons {
public class Fullbright extends QuickModule {
private final static int NIGHT_VISION_ID = 16;
private final static int FOUR_MINUTES_TWENTY_SECONDS = 5204;

View file

@ -1,7 +1,5 @@
package ftbsc.bscv.modules.vision;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.lwjgl.opengl.GL11;
@ -11,7 +9,7 @@ import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.QuickModule;
import ftbsc.bscv.modules.AbstractModule;
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
import ftbsc.bscv.tools.Setting;
import net.minecraft.client.renderer.BufferBuilder;
@ -20,8 +18,10 @@ import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.WorldVertexBufferUploader;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.network.play.server.SChangeBlockPacket;
import net.minecraft.network.play.server.SChunkDataPacket;
import net.minecraft.network.play.server.SMultiBlockChangePacket;
import net.minecraft.util.Tuple;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3i;
import net.minecraftforge.client.event.RenderWorldLastEvent;
@ -31,7 +31,7 @@ import net.minecraftforge.event.TickEvent.Phase;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class UpdateESP extends QuickModule {
public class UpdateESP extends AbstractModule {
public final ForgeConfigSpec.ConfigValue<Integer> duration;
public final ForgeConfigSpec.ConfigValue<Double> alpha;
@ -144,7 +144,7 @@ public class UpdateESP extends QuickModule {
if (event.packet instanceof SMultiBlockChangePacket) {
SMultiBlockChangePacket packet = (SMultiBlockChangePacket) event.packet;
packet.runUpdates( (pos, state) -> this.updates.add(new Tuple<>(pos, System.currentTimeMillis())) );
packet.runUpdates( (pos, state) -> this.updates.add(new Tuple<>(new BlockPos(pos), System.currentTimeMillis())) );
}
}
}

View file

@ -5,7 +5,7 @@ import ftbsc.lll.processor.annotations.Find;
import ftbsc.lll.processor.annotations.Injector;
import ftbsc.lll.processor.annotations.Patch;
import ftbsc.lll.processor.annotations.Target;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.proxies.impl.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.PatternMatcher;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
@ -20,11 +20,6 @@ import org.objectweb.asm.tree.*;
import com.mojang.blaze3d.matrix.MatrixStack;
public class BackgroundPatch implements ICommons {
public static boolean shouldDrawBackground(Screen screen) {
return MinecraftForge.EVENT_BUS.post(new RenderBackgroundEvent(screen));
}
@Cancelable
public static class RenderBackgroundEvent extends Event {
public final Screen screen;
@ -34,15 +29,21 @@ public class BackgroundPatch implements ICommons {
}
}
@Patch(value = Screen.class, reason = "add hook to cancel background on some screens")
@Patch(Screen.class)
public abstract static class BackgroundOverride implements Opcodes {
@Find(parent = BackgroundPatch.class)
abstract MethodProxy shouldDrawBackground();
@Target
@Find(BackgroundOverride.class)
MethodProxy shouldDrawBackground;
@Target(of = "shouldDrawBackground")
public static boolean shouldDrawBackground(Screen screen) {
return MinecraftForge.EVENT_BUS.post(new RenderBackgroundEvent(screen));
}
@Target(of = "injectCancelBackgroundHook")
abstract void renderBackground(MatrixStack stack, int x);
@Injector
public void inject(ClassNode clazz, MethodNode main) {
@Injector(reason = "add hook to cancel background on some screens")
public void injectCancelBackgroundHook(ClassNode clazz, MethodNode main) {
AbstractInsnNode found = PatternMatcher.builder()
.opcodes(ALOAD, ALOAD, ICONST_0, ICONST_0)
.ignoreFrames()
@ -55,7 +56,7 @@ public class BackgroundPatch implements ICommons {
LabelNode skip = new LabelNode();
InsnSequence is = new InsnSequence();
is.add(new VarInsnNode(ALOAD, 0));
is.add(new MethodProxyInsnNode(INVOKESTATIC, shouldDrawBackground()));
is.add(new MethodProxyInsnNode(INVOKESTATIC, shouldDrawBackground));
is.add(new JumpInsnNode(IFEQ, skip));
is.add(new InsnNode(RETURN));
is.add(skip);

View file

@ -4,7 +4,7 @@ import ftbsc.lll.processor.annotations.Find;
import ftbsc.lll.processor.annotations.Injector;
import ftbsc.lll.processor.annotations.Patch;
import ftbsc.lll.processor.annotations.Target;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.proxies.impl.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
import net.minecraft.client.entity.player.ClientPlayerEntity;
@ -20,23 +20,24 @@ public class BlockPushPatch {
@Cancelable
public static class PlayerBlockPushEvent extends Event {}
@Patch(ClientPlayerEntity.class)
public abstract static class BlockCollisionsOverride implements Opcodes {
@Find(BlockCollisionsOverride.class)
MethodProxy shouldCancelBlockCollisions;
@Target(of = "shouldCancelBlockCollisions")
public static boolean shouldCancelBlockCollisions() {
return MinecraftForge.EVENT_BUS.post(new PlayerBlockPushEvent());
}
@Patch(value = ClientPlayerEntity.class, reason = "add hook to cancel block collisions")
public abstract static class BlockCollisionsOverride implements Opcodes {
@Find(parent = BlockPushPatch.class)
abstract MethodProxy shouldCancelBlockCollisions();
@Target
@Target(of = "injectCancelCollisionsHook")
abstract void moveTowardsClosestSpace(double x, double z);
@Injector
public void inject(ClassNode clazz, MethodNode main) {
@Injector(reason = "add hook to cancel block collisions")
public void injectCancelCollisionsHook(ClassNode clazz, MethodNode main) {
LabelNode skip = new LabelNode();
InsnSequence is = new InsnSequence();
is.add(new MethodProxyInsnNode(INVOKESTATIC, shouldCancelBlockCollisions()));
is.add(new MethodProxyInsnNode(INVOKESTATIC, shouldCancelBlockCollisions));
is.add(new JumpInsnNode(IFEQ, skip));
is.add(new InsnNode(RETURN));
is.add(skip);

View file

@ -5,7 +5,7 @@ import ftbsc.lll.processor.annotations.Find;
import ftbsc.lll.processor.annotations.Injector;
import ftbsc.lll.processor.annotations.Patch;
import ftbsc.lll.processor.annotations.Target;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.proxies.impl.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
import net.minecraft.entity.Entity;
@ -30,14 +30,66 @@ public class BoatPatch implements ICommons {
public static class Gravity extends Event { }
}
@Patch(BoatEntity.class)
public abstract static class BoatControlOverride implements Opcodes {
@Find(BoatControlOverride.class)
MethodProxy boatControl;
@Target(of = "boatControl")
public static boolean boatControl() {
return MinecraftForge.EVENT_BUS.post(new BoatEvent.Control());
}
@Target(of = "injectBoatControlHook")
public abstract void controlBoat();
@Injector(reason = "add hook to cancel vanilla boat controls")
public void injectBoatControlHook(ClassNode clazz, MethodNode main) {
// Hook at method start
LabelNode skip = new LabelNode();
InsnSequence is = new InsnSequence();
is.add(new MethodProxyInsnNode(INVOKESTATIC, boatControl));
is.add(new JumpInsnNode(IFEQ, skip));
is.add(new InsnNode(RETURN));
is.add(skip);
main.instructions.insert(is);
}
}
@Patch(BoatEntity.class)
public abstract static class BoatClampOverride implements Opcodes {
@Find(BoatClampOverride.class)
MethodProxy boatClampRotation;
@Target(of = "boatClampRotation")
public static boolean boatClampRotation() {
return MinecraftForge.EVENT_BUS.post(new BoatEvent.ClampRotation());
}
@Target(of = "injectRotationClampingHook")
public abstract void clampRotation(Entity e);
@Injector(reason = "add hook to cancel vanilla boat rotation clamping")
public void injectRotationClampingHook(ClassNode clazz, MethodNode main) {
// Hook at method start
LabelNode skip = new LabelNode();
InsnSequence is = new InsnSequence();
is.add(new MethodProxyInsnNode(INVOKESTATIC, boatClampRotation));
is.add(new JumpInsnNode(IFEQ, skip));
is.add(new InsnNode(RETURN));
is.add(skip);
main.instructions.insert(is);
}
}
@Patch(Entity.class)
public abstract static class BoatGravityOverride implements Opcodes {
@Find(BoatGravityOverride.class)
MethodProxy boatGravityCheck;
@Target(of = "boatGravityCheck")
public static boolean boatGravityCheck(Entity entity) {
if (MC.player == null) return false;
if (MC.player.getVehicle() == null) return false;
@ -45,65 +97,16 @@ public class BoatPatch implements ICommons {
return MinecraftForge.EVENT_BUS.post(new BoatEvent.Gravity());
}
@Patch(value = BoatEntity.class, reason = "add hook to cancel vanilla boat controls")
public abstract static class BoatControlOverride implements Opcodes {
@Find(parent = BoatPatch.class)
abstract MethodProxy boatControl();
@Target
public abstract void controlBoat();
@Injector
public void inject(ClassNode clazz, MethodNode main) {
// Hook at method start
LabelNode skip = new LabelNode();
InsnSequence is = new InsnSequence();
is.add(new MethodProxyInsnNode(INVOKESTATIC, boatControl()));
is.add(new JumpInsnNode(IFEQ, skip));
is.add(new InsnNode(RETURN));
is.add(skip);
main.instructions.insert(is);
}
}
@Patch(value = BoatEntity.class, reason = "add hook to cancel vanilla boat rotation clamping")
public abstract static class BoatClampOverride implements Opcodes {
@Find(parent = BoatPatch.class)
abstract MethodProxy boatClampRotation();
@Target
public abstract void clampRotation(Entity e);
@Injector
public void inject(ClassNode clazz, MethodNode main) {
// Hook at method start
LabelNode skip = new LabelNode();
InsnSequence is = new InsnSequence();
is.add(new MethodProxyInsnNode(INVOKESTATIC, boatClampRotation()));
is.add(new JumpInsnNode(IFEQ, skip));
is.add(new InsnNode(RETURN));
is.add(skip);
main.instructions.insert(is);
}
}
@Patch(value = Entity.class, reason = "add hook to alter vanilla boat gravity")
public abstract static class BoatGravityOverride implements Opcodes {
@Find(parent = BoatPatch.class)
abstract MethodProxy boatGravityCheck();
@Target
@Target(of = "injectGravityHook")
public abstract boolean isNoGravity();
@Injector
public void inject(ClassNode clazz, MethodNode main) {
@Injector(reason = "add hook to alter vanilla boat gravity")
public void injectGravityHook(ClassNode clazz, MethodNode main) {
// Hook at method start
LabelNode skip = new LabelNode();
InsnSequence is = new InsnSequence();
is.add(new VarInsnNode(ALOAD, 0));
is.add(new MethodProxyInsnNode(INVOKESTATIC, boatGravityCheck()));
is.add(new MethodProxyInsnNode(INVOKESTATIC, boatGravityCheck));
is.add(new JumpInsnNode(IFEQ, skip));
is.add(new InsnNode(ICONST_1));
is.add(new InsnNode(IRETURN));

View file

@ -1,21 +1,12 @@
package ftbsc.bscv.patches;
import ftbsc.bscv.modules.hud.Terminal;
import ftbsc.lll.processor.annotations.Find;
import ftbsc.lll.processor.annotations.Injector;
import ftbsc.lll.processor.annotations.Patch;
import ftbsc.lll.processor.annotations.Target;
import ftbsc.lll.proxies.FieldProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.PatternMatcher;
import ftbsc.lll.tools.debug.BytecodePrinter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.NewChatGui;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.eventbus.api.Cancelable;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
@ -23,55 +14,30 @@ import org.objectweb.asm.tree.*;
public class ChatPatch {
@Cancelable
public static class ClearChatEvent extends Event {}
public static boolean shouldPreventChatClearing() {
return MinecraftForge.EVENT_BUS.post(new ClearChatEvent());
}
@Patch(value = Minecraft.class, reason = "add hook to prevent chat from being cleared")
@Patch(Minecraft.class)
public abstract static class ChatClearInterceptor implements Opcodes {
// TODO this should be optional
@Target
@Target(of = "injectClearChatHook")
abstract void setScreen(Screen screen);
@Injector
public void inject(ClassNode clazz, MethodNode method) {
@Injector(reason = "skips chat clearing")
public void injectClearChatHook(ClassNode clazz, MethodNode main) {
InsnSequence match = PatternMatcher.builder()
.opcodes(ALOAD, GETFIELD, INVOKEVIRTUAL, ICONST_1, INVOKEVIRTUAL)
.ignoreLineNumbers()
.ignoreLabels()
.ignoreFrames()
.build()
.find(method);
.find(main);
LabelNode skip = new LabelNode();
JumpInsnNode jump = new JumpInsnNode(GOTO, skip);
method.instructions.insertBefore(match.getFirst(), jump);
method.instructions.insert(match.getLast(), skip);
main.instructions.insertBefore(match.getFirst(), jump);
main.instructions.insert(match.getLast(), skip);
}
}
@Patch(value = NewChatGui.class, reason = "make max number of messages in chat configurable (instead of just 100)")
public abstract static class ChatHistoryRemoveInterceptor implements Opcodes {
@Target
abstract void addMessage(ITextComponent txt, int idk1, int idk2, boolean idk3);
@Find(parent = Terminal.class)
abstract FieldProxy msg_count();
@Injector
public void inject(ClassNode clazz, MethodNode method) {
InsnSequence match = PatternMatcher.builder()
.opcodes(ALOAD, ICONST_2, INVOKESPECIAL, INVOKEINTERFACE, GOTO)
.build()
.find(method);
}
}
}

View file

@ -4,10 +4,9 @@ import ftbsc.lll.processor.annotations.Find;
import ftbsc.lll.processor.annotations.Injector;
import ftbsc.lll.processor.annotations.Patch;
import ftbsc.lll.processor.annotations.Target;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.proxies.impl.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.PatternMatcher;
import ftbsc.lll.tools.debug.BytecodePrinter;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
import net.minecraft.client.network.play.ClientPlayNetHandler;
import net.minecraft.command.CommandSource;
@ -30,21 +29,21 @@ public class CommandsPatch {
}
}
@Patch(ClientPlayNetHandler.class)
public abstract static class CommandsDispatcherCatcher implements Opcodes {
@Find(CommandsDispatcherCatcher.class)
MethodProxy cmdBuilt;
@Target(of = "cmdBuilt")
public static void cmdBuilt(CommandDispatcher<CommandSource> dispatcher) {
MinecraftForge.EVENT_BUS.post(new CommandsBuiltEvent(dispatcher));
}
@Patch(value = ClientPlayNetHandler.class, reason = "add hook to insert our command suggestions")
public abstract static class CommandsDispatcherCatcher implements Opcodes {
@Find(parent = CommandsPatch.class)
abstract MethodProxy cmdBuilt();
@Target
@Target(of = "injectCommandHandler")
abstract void handleCommands(SCommandListPacket pkt);
@Injector
public void inject(ClassNode clazz, MethodNode main) {
BytecodePrinter.logAsmMethod(main, "pre.log");
@Injector(reason = "add hook to insert our command suggestions")
public void injectCommandHandler(ClassNode clazz, MethodNode main) {
AbstractInsnNode found = PatternMatcher.builder()
.opcodes(ALOAD, INVOKEVIRTUAL, INVOKESPECIAL)
.ignoreFrames()
@ -56,10 +55,9 @@ public class CommandsPatch {
InsnSequence is = new InsnSequence();
is.add(new InsnNode(DUP));
is.add(new MethodProxyInsnNode(INVOKESTATIC, cmdBuilt()));
is.add(new MethodProxyInsnNode(INVOKESTATIC, cmdBuilt));
main.instructions.insert(found, is);
BytecodePrinter.logAsmMethod(main, "post.log");
}
}
}

View file

@ -5,7 +5,7 @@ import ftbsc.lll.processor.annotations.Find;
import ftbsc.lll.processor.annotations.Injector;
import ftbsc.lll.processor.annotations.Patch;
import ftbsc.lll.processor.annotations.Target;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.proxies.impl.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
import net.minecraft.entity.Entity;
@ -21,6 +21,12 @@ public class EntityPushPatch implements ICommons {
@Cancelable
public static class PlayerEntityPushEvent extends Event {}
@Patch(Entity.class)
public abstract static class EntityCollisionsOverride implements Opcodes {
@Find(EntityCollisionsOverride.class)
MethodProxy shouldCancelEntityCollisions;
@Target(of = "shouldCancelEntityCollisions")
public static boolean shouldCancelEntityCollisions(Entity e) {
if (e.equals(MC.player)) {
return MinecraftForge.EVENT_BUS.post(new PlayerEntityPushEvent());
@ -28,20 +34,15 @@ public class EntityPushPatch implements ICommons {
return false;
}
@Patch(value = Entity.class, reason = "add hook to cancel entity collisions")
public abstract static class EntityCollisionsOverride implements Opcodes {
@Find(parent = EntityPushPatch.class)
abstract MethodProxy shouldCancelEntityCollisions();
@Target
@Target(of = "injectEntityCollisionHook")
abstract void push(double x, double y, double z);
@Injector
public void inject(ClassNode clazz, MethodNode main) {
@Injector(reason = "add hook to cancel entity collisions")
public void injectEntityCollisionHook(ClassNode clazz, MethodNode main) {
LabelNode skip = new LabelNode();
InsnSequence is = new InsnSequence();
is.add(new VarInsnNode(ALOAD, 0));
is.add(new MethodProxyInsnNode(INVOKESTATIC, shouldCancelEntityCollisions()));
is.add(new MethodProxyInsnNode(INVOKESTATIC, shouldCancelEntityCollisions));
is.add(new JumpInsnNode(IFEQ, skip));
is.add(new InsnNode(RETURN));
is.add(skip);

View file

@ -5,7 +5,7 @@ import ftbsc.lll.processor.annotations.Find;
import ftbsc.lll.processor.annotations.Injector;
import ftbsc.lll.processor.annotations.Patch;
import ftbsc.lll.processor.annotations.Target;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.proxies.impl.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
import net.minecraft.entity.player.PlayerEntity;
@ -21,6 +21,12 @@ public class LiquidPushPatch implements ICommons {
@Cancelable
public static class PlayerLiquidPushEvent extends Event {}
@Patch(PlayerEntity.class)
public abstract static class LiquidCollisionsOverride implements Opcodes {
@Find(LiquidCollisionsOverride.class)
MethodProxy shouldCancelLiquidCollisions;
@Target(of = "shouldCancelLiquidCollisions")
public static boolean shouldCancelLiquidCollisions(PlayerEntity player) {
if (player.equals(MC.player)) {
return MinecraftForge.EVENT_BUS.post(new PlayerLiquidPushEvent());
@ -28,20 +34,15 @@ public class LiquidPushPatch implements ICommons {
return false;
}
@Patch(value = PlayerEntity.class, reason = "add hook to cancel liquid collisions")
public abstract static class LiquidCollisionsOverride implements Opcodes {
@Find(parent = LiquidPushPatch.class)
abstract MethodProxy shouldCancelLiquidCollisions();
@Target
@Target(of = "injectLiquidCollisionHook")
abstract boolean isPushedByFluid();
@Injector
public void inject(ClassNode clazz, MethodNode main) {
@Injector(reason = "add hook to cancel liquid collisions")
public void injectLiquidCollisionHook(ClassNode clazz, MethodNode main) {
LabelNode skip = new LabelNode();
InsnSequence is = new InsnSequence();
is.add(new VarInsnNode(ALOAD, 0));
is.add(new MethodProxyInsnNode(INVOKESTATIC, shouldCancelLiquidCollisions()));
is.add(new MethodProxyInsnNode(INVOKESTATIC, shouldCancelLiquidCollisions));
is.add(new JumpInsnNode(IFEQ, skip));
is.add(new InsnNode(ICONST_0));
is.add(new InsnNode(IRETURN));

View file

@ -4,7 +4,7 @@ import ftbsc.lll.processor.annotations.Find;
import ftbsc.lll.processor.annotations.Injector;
import ftbsc.lll.processor.annotations.Patch;
import ftbsc.lll.processor.annotations.Target;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.proxies.impl.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.PatternMatcher;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
@ -21,21 +21,22 @@ public class NoSlowPatch {
@Cancelable
public static class PlayerSlowDownEvent extends Event { }
@Patch(ClientPlayerEntity.class)
public abstract static class SlowDownOverride implements Opcodes {
@Find(SlowDownOverride.class)
MethodProxy shouldSlowPlayer;
@Target(of = "shouldSlowPlayer")
public static boolean shouldSlowPlayer() {
return MinecraftForge.EVENT_BUS.post(new PlayerSlowDownEvent());
}
@Patch(value = ClientPlayerEntity.class, reason = "add hook to cancel slowing down effect of using items")
public abstract static class SlowDownOverride implements Opcodes {
@Find(parent = NoSlowPatch.class)
abstract MethodProxy shouldSlowPlayer();
@Target
@Target(of = "injectNoSlowHook")
abstract void aiStep();
@Injector
public void inject(ClassNode clazz, MethodNode main) {
@Injector(reason = "add hook to cancel slowing down effect of using items")
public void injectNoSlowHook(ClassNode clazz, MethodNode main) {
AbstractInsnNode found = PatternMatcher.builder()
.opcodes(ALOAD, INVOKEVIRTUAL, IFEQ, ALOAD, INVOKEVIRTUAL, IFNE)
.ignoreFrames()
@ -56,7 +57,7 @@ public class NoSlowPatch {
LabelNode skip = new LabelNode(); // TODO can we get the label that the original IF is jumping to without adding one ourselves?
InsnSequence is = new InsnSequence();
is.add(new MethodProxyInsnNode(INVOKESTATIC, shouldSlowPlayer()));
is.add(new MethodProxyInsnNode(INVOKESTATIC, shouldSlowPlayer));
is.add(new JumpInsnNode(IFNE, skip));
main.instructions.insert(found, is);

View file

@ -4,10 +4,9 @@ import ftbsc.lll.processor.annotations.Find;
import ftbsc.lll.processor.annotations.Injector;
import ftbsc.lll.processor.annotations.Patch;
import ftbsc.lll.processor.annotations.Target;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.proxies.impl.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.PatternMatcher;
import ftbsc.lll.tools.debug.BytecodePrinter;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.concurrent.Future;
@ -43,24 +42,21 @@ public class PacketPatch {
}
}
@Patch(NetworkManager.class)
public abstract static class IncomingPacketInterceptor implements Opcodes {
@Find(IncomingPacketInterceptor.class)
MethodProxy pktIn;
@Target(of = "pktIn")
public static boolean pktIn(IPacket<?> pkt) {
return MinecraftForge.EVENT_BUS.post(new PacketEvent.Incoming(pkt));
}
public static boolean pktOut(IPacket<?> pkt) {
return MinecraftForge.EVENT_BUS.post(new PacketEvent.Outgoing(pkt));
}
@Target(of = "injectIncomingInterceptor")
abstract void channelRead0(ChannelHandlerContext ctx, IPacket<?> pak);
@Patch(value = NetworkManager.class, reason = "add hook to intercept and alter/cancel incoming packets")
public abstract static class IncomingPacketInterceptor implements Opcodes {
@Find(parent = PacketPatch.class)
abstract MethodProxy pktIn();
@Target
public abstract void channelRead0(ChannelHandlerContext ctx, IPacket<?> pak);
@Injector
public void inject(ClassNode clazz, MethodNode main) {
@Injector(reason = "add hook to intercept and alter/cancel incoming packets")
public void injectIncomingInterceptor(ClassNode clazz, MethodNode main) {
AbstractInsnNode found = PatternMatcher.builder()
.opcodes(ALOAD, GETFIELD, INVOKEINTERFACE, IFEQ)
.ignoreFrames()
@ -73,7 +69,7 @@ public class PacketPatch {
LabelNode skip = new LabelNode();
InsnSequence is = new InsnSequence();
is.add(new VarInsnNode(ALOAD, 2));
is.add(new MethodProxyInsnNode(INVOKESTATIC, pktIn()));
is.add(new MethodProxyInsnNode(INVOKESTATIC, pktIn));
is.add(new JumpInsnNode(IFEQ, skip));
is.add(new InsnNode(RETURN));
is.add(skip);
@ -82,21 +78,26 @@ public class PacketPatch {
}
}
@Patch(value = NetworkManager.class, reason = "add hook to intercept and alter/cancel outgoing packets")
@Patch(NetworkManager.class)
public abstract static class OutgoingPacketInterceptor implements Opcodes {
@Find(parent = PacketPatch.class)
abstract MethodProxy pktOut();
@Find(OutgoingPacketInterceptor.class)
MethodProxy pktOut;
@Target
@Target(of = "pktOut")
public static boolean pktOut(IPacket<?> pkt) {
return MinecraftForge.EVENT_BUS.post(new PacketEvent.Outgoing(pkt));
}
@Target(of = "injectOutgoingInterceptor")
public abstract void sendPacket(IPacket<?> pak, GenericFutureListener<? extends Future<? super Void>> gfl);
@Injector
public void inject(ClassNode clazz, MethodNode main) {
@Injector(reason = "add hook to intercept and alter/cancel outgoing packets")
public void injectOutgoingInterceptor(ClassNode clazz, MethodNode main) {
// hook at the top
LabelNode skip = new LabelNode();
InsnSequence is = new InsnSequence();
is.add(new VarInsnNode(ALOAD, 1));
is.add(new MethodProxyInsnNode(INVOKESTATIC, pktOut()));
is.add(new MethodProxyInsnNode(INVOKESTATIC, pktOut));
is.add(new JumpInsnNode(IFEQ, skip));
is.add(new InsnNode(RETURN));
is.add(skip);

View file

@ -13,12 +13,12 @@ import ftbsc.lll.processor.annotations.Target;
import ftbsc.lll.tools.PatternMatcher;
import net.minecraft.client.entity.player.ClientPlayerEntity;
@Patch(value = ClientPlayerEntity.class, reason = "prevent minecraft from force closing guis when entering portals")
@Patch(ClientPlayerEntity.class)
public abstract class PortalGuiPatch implements Opcodes {
@Target
@Target(of = "inject")
abstract void handleNetherPortalClient();
@Injector
@Injector(reason = "prevent minecraft from force closing guis when entering portals")
public void inject(ClassNode clazz, MethodNode main) {
LabelNode skip = new LabelNode();

View file

@ -0,0 +1,85 @@
package ftbsc.bscv.system;
import ftbsc.bscv.ICommons;
import ftbsc.bscv.tools.Keybind;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.client.util.InputMappings;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.RayTraceResult.Type;
import net.minecraftforge.client.event.InputEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import static ftbsc.bscv.Boscovicino.log;
public class Ruler implements ICommons {
public final KeyBinding keybind;
public Ruler() {
super();
this.keybind = new KeyBinding(Keybind.name("Ruler"), InputMappings.UNKNOWN.getValue(), Keybind.category());
ClientRegistry.registerKeyBinding(this.keybind);
// register a separate subclass on the hook, so that it's always listening
MinecraftForge.EVENT_BUS.register(new ToggleHook(this.keybind));
// dispatcher.register(
// Commands.literal(this.name.toLowerCase())
// .then(
// Commands.literal("bind")
// .then(
// Commands.argument("key", StringArgumentType.word())
// .executes( ctx -> {
// this.keybind.setKey(
// InputMappings.getKey( // TODO it's not this easy!
// StringArgumentType.getString(ctx, "key")
// )
// );
// return 1;
// })
// )
// )
// );
}
public static void measure() {
RayTraceResult aim = MC.player.pick(1024, 0, false); // will 1024 be enough?
double distance = Math.sqrt(aim.distanceTo(MC.player));
if (aim.getType() == Type.BLOCK) {
log("distance: %.1fm", distance);
}
}
// TODO can this be made an util or a global event listener?
private class ToggleHook {
private final KeyBinding key;
private boolean debounce;
// TODO all examples show isPressed() to get a debounced value
// but it seems to be missing? making my own debounce for now
protected ToggleHook(KeyBinding key) {
this.key = key;
this.debounce = false;
}
private void onInput() {
if (this.debounce) {
if (!this.key.isDown()) {
this.debounce = false;
}
} else {
if (this.key.isDown()) {
Ruler.measure();
this.debounce = true;
}
}
}
@SubscribeEvent
public void onKeyPress(InputEvent.KeyInputEvent event) { this.onInput(); }
@SubscribeEvent
public void onKeyPress(InputEvent.MouseInputEvent event) { this.onInput(); }
}
}

View file

@ -7,13 +7,19 @@ import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.inventory.container.ClickType;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.EnchantedBookItem;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.INBT;
import net.minecraft.nbt.ListNBT;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
public class Inventory implements ICommons {
@ -68,4 +74,44 @@ public class Inventory implements ICommons {
return damage / (1. + speed);
}
public static List<String> itemEnchantments(ItemStack stack) {
final ListNBT tags;
if (Items.ENCHANTED_BOOK.equals(stack.getItem())) {
tags = EnchantedBookItem.getEnchantments(stack); // special case to also search book enchants
} else {
tags = stack.getEnchantmentTags();
}
List<String> out = new ArrayList<>();
for (int i = 0; i < tags.size(); i++) {
CompoundNBT tag = tags.getCompound(i);
out.add(String.format("%s %s", tag.getString("id"), tag.getInt("lvl")));
}
return out;
}
public static void clickSlot(int slot_index, ClickType click) { clickSlot(0, slot_index, 0, click); }
public static void clickSlot(Slot slot, int button, ClickType click) { clickSlot(0, slot.index, button, click); }
public static void clickSlot(int container, int slot_index, ClickType click) { clickSlot(container, slot_index, 0, click); }
public static void clickSlot(int container, int slot_index, int button, ClickType click) {
MC.gameMode.handleInventoryMouseClick(container, slot_index, button, click, MC.player);
}
public static boolean matchItem(Pattern pattern, ItemStack stack) {
if (stack.isEmpty()) return false;
String displayName = stack.getDisplayName().getString();
if (pattern.matcher(displayName).find()) return true;
if (Items.ENCHANTED_BOOK.equals(stack.getItem()) || stack.isEnchanted()) {
for (String ench : itemEnchantments(stack)) {
if (pattern.matcher(ench).find()) return true;
}
}
return false;
}
}

View file

@ -0,0 +1,13 @@
package ftbsc.bscv.tools;
import ftbsc.bscv.Boscovicino;
public class Keybind {
public static String name(String name) {
return String.format("key.%s.%s", Boscovicino.MOD_ID, name);
}
public static String category() {
return String.format("key.category.%s", Boscovicino.MOD_ID);
}
}

View file

@ -1,23 +1,28 @@
package ftbsc.bscv.tools;
import com.google.common.collect.Lists;
import com.mojang.brigadier.arguments.*;
import ftbsc.bscv.api.IModule;
import net.minecraft.command.Commands;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.server.command.EnumArgument;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import static ftbsc.bscv.Boscovicino.log;
public abstract class Setting<T> {
public abstract class Setting<T, I> {
protected Optional<String> name;
protected Optional<String> comment;
protected Optional<T> fallback;
protected Optional<Consumer<T>> callback;
protected Optional<Consumer<I>> callback;
Setting() {
this.name = Optional.empty();
@ -26,29 +31,35 @@ public abstract class Setting<T> {
this.callback = Optional.empty();
}
public Setting<T> name(String name) {
public Setting<T, I> name(String name) {
this.name = Optional.of(name);
return this;
}
public Setting<T> comment(String comment) {
public Setting<T, I> comment(String comment) {
this.comment = Optional.of(comment);
return this;
}
public Setting<T> fallback(T fallback) {
public Setting<T, I> fallback(T fallback) {
this.fallback = Optional.of(fallback);
return this;
}
public Setting<T> callback(Consumer<T> callback) {
public Setting<T, I> callback(Consumer<I> callback) {
this.callback = Optional.of(callback);
return this;
}
abstract ForgeConfigSpec.ConfigValue<T> value(ForgeConfigSpec.Builder builder);
abstract ArgumentType<T> argument();
abstract ArgumentType<I> argument();
public abstract ForgeConfigSpec.ConfigValue<T> build(IModule module);
private static abstract class ValueSetting<T> extends Setting<T, T> {
abstract Class<T> clazz();
@ -84,10 +95,11 @@ public abstract class Setting<T> {
);
return conf;
}
}
public static class Bool extends Setting<Boolean> {
public static class Bool extends ValueSetting<Boolean> {
public static Bool builder() { return new Bool(); }
public Class<Boolean> clazz() { return Boolean.class; }
@ -101,7 +113,7 @@ public abstract class Setting<T> {
}
public static class Decimal extends Setting<Double> {
public static class Decimal extends ValueSetting<Double> {
protected Optional<Double> min;
protected Optional<Double> max;
@ -133,7 +145,7 @@ public abstract class Setting<T> {
}
public static class Number extends Setting<Integer> {
public static class Number extends ValueSetting<Integer> {
protected Optional<Integer> min;
protected Optional<Integer> max;
@ -165,7 +177,7 @@ public abstract class Setting<T> {
}
public static class Str extends Setting<String> {
public static class Str extends ValueSetting<String> {
public static Str builder() { return new Str(); }
protected boolean greedy = false;
@ -190,7 +202,7 @@ public abstract class Setting<T> {
}
public static class Switch<T extends Enum<T>> extends Setting<T> {
public static class Switch<T extends Enum<T>> extends ValueSetting<T> {
private final Class<T> enumClazz;
public static<T extends Enum<T>> Switch<T> builder(Class<T> type) { return new Switch<T>(type); }
@ -214,4 +226,102 @@ public abstract class Setting<T> {
}
}
public static class Many<T, S extends Serializable> extends Setting<List<? extends S>, T> {
private Predicate<Object> validator;
private Function<T, S> writer;
private final ArgumentType<T> argument_type;
private final Class<T> clazz;
// TODO can we infer clazz from the argument type without needing the second argument???
public Many(ArgumentType<T> argument, Class<T> clazz) {
super();
this.validator = x -> true;
this.writer = x -> (S) x; // TODO this works ootb if it's just the same type but crashes at runtime for everything else
this.argument_type = argument;
this.clazz = clazz;
}
public static<T, S extends Serializable> Many<T, S> builder(ArgumentType<T> argument, Class<T> clazz) { return new Many<T, S>(argument, clazz); }
public Many<T, S> validator(Predicate<Object> validator) {
this.validator = validator;
return this;
}
public Many<T, S> writer(Function<T, S> writer) {
this.writer = writer;
return this;
}
public ArgumentType<T> argument() {
return this.argument_type;
}
public ForgeConfigSpec.ConfigValue<List<? extends S>> value(ForgeConfigSpec.Builder builder) {
return builder
.comment(this.comment.get())
.defineList(
this.name.get(),
this.fallback.get(),
this.validator
);
}
public ForgeConfigSpec.ConfigValue<List<? extends S>> build(IModule module) {
ForgeConfigSpec.ConfigValue<List<? extends S>> conf = this.value(module.getConfigBuilder());
String optName = this.name.get();
ArgumentType<T> arg = this.argument();
Consumer<T> cb = this.callback.isPresent() ? this.callback.get() : null;
module.getDispatcher().register(
Commands.literal(module.getName().toLowerCase())
.then(
Commands.literal(optName)
.then(
Commands.literal("add")
.then(
Commands.argument(optName, arg)
.executes( ctx -> {
T value = ctx.getArgument(optName, this.clazz);
if (cb != null) {
cb.accept(value);
}
List<S> botch = Lists.newArrayList(conf.get());
botch.add(this.writer.apply(value));
conf.set(botch);
conf.save();
log(String.format("> %s -++> %s <", String.join(".", conf.getPath()), conf.get().toString()));
return 1;
})
)
)
.then(
Commands.literal("remove")
.then(
Commands.argument(optName, arg)
.executes( ctx -> {
T value = ctx.getArgument(optName, clazz);
if (cb != null) {
cb.accept(value);
}
List<S> botch = Lists.newArrayList(conf.get());
boolean removed = botch.remove(this.writer.apply(value));
conf.set(botch);
conf.save();
log(String.format("> %s -%s> %s <", String.join(".", conf.getPath()), removed ? "//" : "--", conf.get().toString()));
return 1;
})
)
)
.executes(ctx -> {
log(String.format("> %s: %s <", optName, conf.get().toString()));
return 1;
})
)
);
return conf;
}
}
}

View file

@ -5,3 +5,7 @@ public net.minecraft.network.play.client.CPlayerPacket field_149474_g # onGround
public net.minecraft.network.play.client.CPlayerPacket field_149477_b # y
public net.minecraft.client.multiplayer.PlayerController func_78750_j()V # ensureHasSentCarriedItem()
public net.minecraft.client.Minecraft field_71467_ac # rightClickDelay
public net.minecraft.client.renderer.FirstPersonRenderer field_187469_f # mainHandHeight
public net.minecraft.client.renderer.FirstPersonRenderer field_187470_g # oMainHandHeight
public net.minecraft.client.renderer.FirstPersonRenderer field_187471_h # offHandHeight
public net.minecraft.client.renderer.FirstPersonRenderer field_187472_i # oOffHandHeight