Compare commits

..

1 commit

Author SHA1 Message Date
33ece210f5 chore: initial work on a better chat patch 2023-03-20 23:28:27 +01:00
44 changed files with 355 additions and 902 deletions

3
.gitignore vendored
View file

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

View file

@ -6,10 +6,12 @@ plugins {
alias libs.plugins.checkerFramework
}
version = versionDetails().lastTag
version = gitVersion()
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", ".")
@ -64,11 +66,11 @@ dependencies {
}
compileJava { //mappings for lillero-processor
options.compilerArgs << '-AmappingsFile=https://data.fantabos.co/1.16.5.tsrg'
options.compilerArgs << '-AmappingsFile=https://data.fantabos.co/output.tsrg'
}
jar {
archiveFileName = "${jar.archiveBaseName.get()}-${archiveVersion.get()}.${jar.archiveExtension.get()}"
archiveFileName = "${jar.archiveBaseName.get()}-${shortVersion}.${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.4.1"
lilleroProcessor = "0.5.2"
lillero = "0.3.4"
lilleroProcessor = "0.4.2"
checkerFramework = "0.6.24"
[plugins]

View file

@ -8,7 +8,6 @@ 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;
@ -43,9 +42,6 @@ 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);
@ -57,8 +53,6 @@ public class Boscovicino implements ICommons {
Boscovicino.modManager.finish();
Boscovicino.ruler = new Ruler();
Boscovicino.spec = cfg.build();
ForgeConfigSpec.Builder friendSpec = new ForgeConfigSpec.Builder();
@ -77,13 +71,9 @@ 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), overlay);
MC.player.displayClientMessage(new StringTextComponent(message), true);
}
}

View file

@ -1,72 +0,0 @@
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,7 +4,6 @@ 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;
@ -19,18 +18,17 @@ public class Cursor extends AbstractCommand {
public LiteralArgumentBuilder<CommandSource> register(LiteralArgumentBuilder<CommandSource> builder) {
return builder
.then(
Commands.literal("info")
Commands.literal("pos")
.executes(ctx -> {
switch (MC.hitResult.getType()) {
case BLOCK:
BlockRayTraceResult result = (BlockRayTraceResult) MC.hitResult;
Direction dir = result.getDirection();
BlockPos pos = result.getBlockPos();
BlockState state = MC.level.getBlockState(pos);
log("Block @ %s (%s): %s", pos.toString(), dir.toString(), state.toString());
BlockPos pos =result.getBlockPos();
log("Block @ %s (%s)", pos.toString(), dir.toString());
return 1;
case ENTITY:
log("Entity @ %s (TODO!)", MC.hitResult.getLocation().toString());
log("Entity @ %s", MC.hitResult.getLocation().toString());
return 1;
default:
case MISS:

View file

@ -1,25 +1,18 @@
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 ItemCommand extends AbstractCommand {
@Override
public String getName() { return "item"; }
public class Item extends AbstractCommand {
public LiteralArgumentBuilder<CommandSource> register(LiteralArgumentBuilder<CommandSource> builder) {
return builder
@ -39,29 +32,6 @@ public class ItemCommand 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 java.util.stream.Collectors;
import static ftbsc.bscv.Boscovicino.log;
@AutoService(ILoadable.class)
public class ModCommands extends AbstractCommand {
@ -43,11 +43,8 @@ public class ModCommands extends AbstractCommand {
})
)
.executes(ctx -> {
String mods = Boscovicino.modManager.mods.stream()
.map(x -> x.getName())
.collect(Collectors.joining(","));
Boscovicino.log("[ %s ]", mods);
return 1;
log("no args specified");
return 0;
});
}

View file

@ -1,7 +1,6 @@
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;
@ -52,7 +51,7 @@ public abstract class QuickModule extends AbstractModule {
public QuickModule() {
super();
this.keybind = new KeyBinding(Keybind.name(this.getName()), this.getDefaultKey(), Keybind.category());
this.keybind = new KeyBinding(key_name(this.getName()), this.getDefaultKey(), key_category());
ClientRegistry.registerKeyBinding(this.keybind);
// register a separate subclass on the hook, so that it's always listening
@ -77,4 +76,12 @@ 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,6 +3,7 @@ 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;
@ -22,7 +23,7 @@ import net.minecraftforge.event.TickEvent.Phase;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class Aura extends QuickModule {
public class Aura extends QuickModule implements ICommons {
private enum LookType {
NONE,
@ -52,7 +53,7 @@ public class Aura extends QuickModule {
this.reach = Setting.Decimal.builder()
.min(0.)
.fallback(4.)
.fallback(5.)
.name("reach")
.comment("aura attack reach")
.build(this);
@ -128,9 +129,6 @@ public class Aura extends QuickModule {
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;
@ -145,21 +143,13 @@ public class Aura extends QuickModule {
}
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, target.getEyePosition(1.0F));
MC.player.lookAt(Type.EYES, e.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, target.getEyePosition(1.0F));
this.lookAtHidden(Type.EYES, e.getEyePosition(1.0F));
break;
case NONE: break;
}
@ -167,10 +157,12 @@ public class Aura extends QuickModule {
if (this.tool.get()) {
this.autotool.selectBestWeapon();
}
MC.gameMode.attack(MC.player, target);
MC.gameMode.attack(MC.player, e);
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,7 +4,6 @@ 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;
@ -49,6 +48,38 @@ 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();
@ -60,7 +91,7 @@ public class Highlighter extends AbstractModule {
for (Slot slot : screen.getMenu().slots) {
ItemStack stack = slot.getItem();
if (Inventory.matchItem(this.pattern, stack)) {
if (this.matches(stack)) {
GuiUtils.drawGradientRect(
matrix.last().pose(), 0,
slot.x, slot.y, slot.x + 16, slot.y + 16,

View file

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

View file

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

View file

@ -1,38 +1,19 @@
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 {
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);
}
public class PlayerList extends HudModule implements ICommons {
@SubscribeEvent
public void onRenderOverlay(RenderGameOverlayEvent event) {
@ -54,14 +35,4 @@ public class PlayerList extends HudModule {
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

@ -0,0 +1,21 @@
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,11 +1,12 @@
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;
@ -25,7 +26,6 @@ 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,24 +40,18 @@ 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.1)
.fallback(0.05)
.name("speed")
.comment("flight speed to set")
.build(this);
this.antikick = Setting.Switch.builder(AntikickMode.class)
.fallback(AntikickMode.PACKET)
.fallback(AntikickMode.NONE)
.name("antikick")
.comment("prevent vanilla flight kick by descending")
.build(this);
@ -109,10 +103,6 @@ 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,6 +1,7 @@
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;
@ -12,7 +13,7 @@ import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class AntiHunger extends AbstractModule {
public class AntiHunger extends AbstractModule implements ICommons {
public final ForgeConfigSpec.ConfigValue<Boolean> sprint;
public final ForgeConfigSpec.ConfigValue<Boolean> hover;

View file

@ -1,6 +1,7 @@
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;
@ -12,7 +13,7 @@ import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class AutoDisconnect extends AbstractModule {
public class AutoDisconnect extends AbstractModule implements ICommons {
public final ForgeConfigSpec.ConfigValue<Double> threshold;

View file

@ -1,6 +1,7 @@
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;
@ -9,16 +10,14 @@ 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 {
public class AutoFish extends AbstractModule implements ICommons {
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() {
@ -35,23 +34,13 @@ public class AutoFish extends AbstractModule {
.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;
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())
) {
if (packet.getSound().equals(SoundEvents.FISHING_BOBBER_SPLASH)) {
MC.gameMode.useItem(MC.player, MC.level, Hand.MAIN_HAND);
if (this.recast.get()) {
new RecastThread(MC, this.delay.get()).start();
@ -60,7 +49,6 @@ public class AutoFish extends AbstractModule {
}
}
// 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,14 +1,12 @@
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.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;
@ -19,10 +17,9 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
import java.util.List;
@AutoService(ILoadable.class)
public class AutoTool extends AbstractModule {
public class AutoTool extends AbstractModule implements ICommons {
public final ForgeConfigSpec.ConfigValue<Integer> limit;
public final ForgeConfigSpec.ConfigValue<Boolean> prefer_looting;
public AutoTool() {
super();
@ -32,12 +29,6 @@ public class AutoTool extends AbstractModule {
.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) {
@ -57,12 +48,6 @@ public class AutoTool extends AbstractModule {
}
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

@ -1,79 +0,0 @@
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

@ -1,39 +0,0 @@
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,13 +1,18 @@
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 {
public class FastInteract extends QuickModule implements ICommons {
protected int getDefaultKey() { return UNBOUND; }

View file

@ -2,6 +2,7 @@ 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;
@ -17,7 +18,7 @@ import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@AutoService(ILoadable.class)
public class Freecam extends QuickModule {
public class Freecam extends QuickModule implements ICommons {
public final ForgeConfigSpec.ConfigValue<Boolean> log;
public final ForgeConfigSpec.ConfigValue<Double> speed;

View file

@ -1,72 +0,0 @@
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

@ -5,13 +5,14 @@ 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 {
public class Chams extends QuickModule implements ICommons {
protected int getDefaultKey() { return UNBOUND; }

View file

@ -1,6 +1,7 @@
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;
@ -11,7 +12,7 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
import java.awt.event.KeyEvent;
@AutoService(ILoadable.class)
public class Fullbright extends QuickModule {
public class Fullbright extends QuickModule implements ICommons {
private final static int NIGHT_VISION_ID = 16;
private final static int FOUR_MINUTES_TWENTY_SECONDS = 5204;

View file

@ -1,5 +1,7 @@
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;
@ -9,7 +11,7 @@ import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import ftbsc.bscv.api.ILoadable;
import ftbsc.bscv.modules.AbstractModule;
import ftbsc.bscv.modules.QuickModule;
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
import ftbsc.bscv.tools.Setting;
import net.minecraft.client.renderer.BufferBuilder;
@ -18,10 +20,8 @@ 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 AbstractModule {
public class UpdateESP extends QuickModule {
public final ForgeConfigSpec.ConfigValue<Integer> duration;
public final ForgeConfigSpec.ConfigValue<Double> alpha;
@ -144,7 +144,7 @@ public class UpdateESP extends AbstractModule {
if (event.packet instanceof SMultiBlockChangePacket) {
SMultiBlockChangePacket packet = (SMultiBlockChangePacket) event.packet;
packet.runUpdates( (pos, state) -> this.updates.add(new Tuple<>(new BlockPos(pos), System.currentTimeMillis())) );
packet.runUpdates( (pos, state) -> this.updates.add(new Tuple<>(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.impl.MethodProxy;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.PatternMatcher;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
@ -20,6 +20,11 @@ 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;
@ -29,21 +34,15 @@ public class BackgroundPatch implements ICommons {
}
}
@Patch(Screen.class)
@Patch(value = Screen.class, reason = "add hook to cancel background on some screens")
public abstract static class BackgroundOverride implements Opcodes {
@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")
@Find(parent = BackgroundPatch.class)
abstract MethodProxy shouldDrawBackground();
@Target
abstract void renderBackground(MatrixStack stack, int x);
@Injector(reason = "add hook to cancel background on some screens")
public void injectCancelBackgroundHook(ClassNode clazz, MethodNode main) {
@Injector
public void inject(ClassNode clazz, MethodNode main) {
AbstractInsnNode found = PatternMatcher.builder()
.opcodes(ALOAD, ALOAD, ICONST_0, ICONST_0)
.ignoreFrames()
@ -56,7 +55,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.impl.MethodProxy;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
import net.minecraft.client.entity.player.ClientPlayerEntity;
@ -20,24 +20,23 @@ 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());
}
@Target(of = "injectCancelCollisionsHook")
@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
abstract void moveTowardsClosestSpace(double x, double z);
@Injector(reason = "add hook to cancel block collisions")
public void injectCancelCollisionsHook(ClassNode clazz, MethodNode main) {
@Injector
public void inject(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.impl.MethodProxy;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
import net.minecraft.entity.Entity;
@ -30,66 +30,14 @@ 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;
@ -97,16 +45,65 @@ public class BoatPatch implements ICommons {
return MinecraftForge.EVENT_BUS.post(new BoatEvent.Gravity());
}
@Target(of = "injectGravityHook")
@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
public abstract boolean isNoGravity();
@Injector(reason = "add hook to alter vanilla boat gravity")
public void injectGravityHook(ClassNode clazz, MethodNode main) {
@Injector
public void inject(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,12 +1,21 @@
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.*;
@ -14,30 +23,55 @@ import org.objectweb.asm.tree.*;
public class ChatPatch {
@Patch(Minecraft.class)
@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")
public abstract static class ChatClearInterceptor implements Opcodes {
// TODO this should be optional
@Target(of = "injectClearChatHook")
@Target
abstract void setScreen(Screen screen);
@Injector(reason = "skips chat clearing")
public void injectClearChatHook(ClassNode clazz, MethodNode main) {
@Injector
public void inject(ClassNode clazz, MethodNode method) {
InsnSequence match = PatternMatcher.builder()
.opcodes(ALOAD, GETFIELD, INVOKEVIRTUAL, ICONST_1, INVOKEVIRTUAL)
.ignoreLineNumbers()
.ignoreLabels()
.ignoreFrames()
.build()
.find(main);
.find(method);
LabelNode skip = new LabelNode();
JumpInsnNode jump = new JumpInsnNode(GOTO, skip);
main.instructions.insertBefore(match.getFirst(), jump);
main.instructions.insert(match.getLast(), skip);
method.instructions.insertBefore(match.getFirst(), jump);
method.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,9 +4,10 @@ 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.impl.MethodProxy;
import ftbsc.lll.proxies.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;
@ -29,21 +30,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));
}
@Target(of = "injectCommandHandler")
@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
abstract void handleCommands(SCommandListPacket pkt);
@Injector(reason = "add hook to insert our command suggestions")
public void injectCommandHandler(ClassNode clazz, MethodNode main) {
@Injector
public void inject(ClassNode clazz, MethodNode main) {
BytecodePrinter.logAsmMethod(main, "pre.log");
AbstractInsnNode found = PatternMatcher.builder()
.opcodes(ALOAD, INVOKEVIRTUAL, INVOKESPECIAL)
.ignoreFrames()
@ -55,9 +56,10 @@ 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.impl.MethodProxy;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
import net.minecraft.entity.Entity;
@ -21,12 +21,6 @@ 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());
@ -34,15 +28,20 @@ public class EntityPushPatch implements ICommons {
return false;
}
@Target(of = "injectEntityCollisionHook")
@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
abstract void push(double x, double y, double z);
@Injector(reason = "add hook to cancel entity collisions")
public void injectEntityCollisionHook(ClassNode clazz, MethodNode main) {
@Injector
public void inject(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.impl.MethodProxy;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
import net.minecraft.entity.player.PlayerEntity;
@ -21,12 +21,6 @@ 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());
@ -34,15 +28,20 @@ public class LiquidPushPatch implements ICommons {
return false;
}
@Target(of = "injectLiquidCollisionHook")
@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
abstract boolean isPushedByFluid();
@Injector(reason = "add hook to cancel liquid collisions")
public void injectLiquidCollisionHook(ClassNode clazz, MethodNode main) {
@Injector
public void inject(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.impl.MethodProxy;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.tools.InsnSequence;
import ftbsc.lll.tools.PatternMatcher;
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
@ -21,22 +21,21 @@ 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());
}
@Target(of = "injectNoSlowHook")
@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
abstract void aiStep();
@Injector(reason = "add hook to cancel slowing down effect of using items")
public void injectNoSlowHook(ClassNode clazz, MethodNode main) {
@Injector
public void inject(ClassNode clazz, MethodNode main) {
AbstractInsnNode found = PatternMatcher.builder()
.opcodes(ALOAD, INVOKEVIRTUAL, IFEQ, ALOAD, INVOKEVIRTUAL, IFNE)
.ignoreFrames()
@ -57,7 +56,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,9 +4,10 @@ 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.impl.MethodProxy;
import ftbsc.lll.proxies.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;
@ -42,21 +43,24 @@ 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));
}
@Target(of = "injectIncomingInterceptor")
abstract void channelRead0(ChannelHandlerContext ctx, IPacket<?> pak);
public static boolean pktOut(IPacket<?> pkt) {
return MinecraftForge.EVENT_BUS.post(new PacketEvent.Outgoing(pkt));
}
@Injector(reason = "add hook to intercept and alter/cancel incoming packets")
public void injectIncomingInterceptor(ClassNode clazz, MethodNode main) {
@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) {
AbstractInsnNode found = PatternMatcher.builder()
.opcodes(ALOAD, GETFIELD, INVOKEINTERFACE, IFEQ)
.ignoreFrames()
@ -69,7 +73,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);
@ -78,26 +82,21 @@ public class PacketPatch {
}
}
@Patch(NetworkManager.class)
@Patch(value = NetworkManager.class, reason = "add hook to intercept and alter/cancel outgoing packets")
public abstract static class OutgoingPacketInterceptor implements Opcodes {
@Find(OutgoingPacketInterceptor.class)
MethodProxy pktOut;
@Find(parent = PacketPatch.class)
abstract MethodProxy pktOut();
@Target(of = "pktOut")
public static boolean pktOut(IPacket<?> pkt) {
return MinecraftForge.EVENT_BUS.post(new PacketEvent.Outgoing(pkt));
}
@Target(of = "injectOutgoingInterceptor")
@Target
public abstract void sendPacket(IPacket<?> pak, GenericFutureListener<? extends Future<? super Void>> gfl);
@Injector(reason = "add hook to intercept and alter/cancel outgoing packets")
public void injectOutgoingInterceptor(ClassNode clazz, MethodNode main) {
@Injector
public void inject(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(ClientPlayerEntity.class)
@Patch(value = ClientPlayerEntity.class, reason = "prevent minecraft from force closing guis when entering portals")
public abstract class PortalGuiPatch implements Opcodes {
@Target(of = "inject")
@Target
abstract void handleNetherPortalClient();
@Injector(reason = "prevent minecraft from force closing guis when entering portals")
@Injector
public void inject(ClassNode clazz, MethodNode main) {
LabelNode skip = new LabelNode();

View file

@ -1,85 +0,0 @@
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,19 +7,13 @@ 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 {
@ -74,44 +68,4 @@ 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

@ -1,13 +0,0 @@
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,28 +1,23 @@
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, I> {
public abstract class Setting<T> {
protected Optional<String> name;
protected Optional<String> comment;
protected Optional<T> fallback;
protected Optional<Consumer<I>> callback;
protected Optional<Consumer<T>> callback;
Setting() {
this.name = Optional.empty();
@ -31,35 +26,29 @@ public abstract class Setting<T, I> {
this.callback = Optional.empty();
}
public Setting<T, I> name(String name) {
public Setting<T> name(String name) {
this.name = Optional.of(name);
return this;
}
public Setting<T, I> comment(String comment) {
public Setting<T> comment(String comment) {
this.comment = Optional.of(comment);
return this;
}
public Setting<T, I> fallback(T fallback) {
public Setting<T> fallback(T fallback) {
this.fallback = Optional.of(fallback);
return this;
}
public Setting<T, I> callback(Consumer<I> callback) {
public Setting<T> callback(Consumer<T> callback) {
this.callback = Optional.of(callback);
return this;
}
abstract ForgeConfigSpec.ConfigValue<T> value(ForgeConfigSpec.Builder builder);
abstract ArgumentType<I> argument();
public abstract ForgeConfigSpec.ConfigValue<T> build(IModule module);
private static abstract class ValueSetting<T> extends Setting<T, T> {
abstract ArgumentType<T> argument();
abstract Class<T> clazz();
@ -95,11 +84,10 @@ public abstract class Setting<T, I> {
);
return conf;
}
}
public static class Bool extends ValueSetting<Boolean> {
public static class Bool extends Setting<Boolean> {
public static Bool builder() { return new Bool(); }
public Class<Boolean> clazz() { return Boolean.class; }
@ -113,7 +101,7 @@ public abstract class Setting<T, I> {
}
public static class Decimal extends ValueSetting<Double> {
public static class Decimal extends Setting<Double> {
protected Optional<Double> min;
protected Optional<Double> max;
@ -145,7 +133,7 @@ public abstract class Setting<T, I> {
}
public static class Number extends ValueSetting<Integer> {
public static class Number extends Setting<Integer> {
protected Optional<Integer> min;
protected Optional<Integer> max;
@ -177,7 +165,7 @@ public abstract class Setting<T, I> {
}
public static class Str extends ValueSetting<String> {
public static class Str extends Setting<String> {
public static Str builder() { return new Str(); }
protected boolean greedy = false;
@ -202,7 +190,7 @@ public abstract class Setting<T, I> {
}
public static class Switch<T extends Enum<T>> extends ValueSetting<T> {
public static class Switch<T extends Enum<T>> extends Setting<T> {
private final Class<T> enumClazz;
public static<T extends Enum<T>> Switch<T> builder(Class<T> type) { return new Switch<T>(type); }
@ -226,102 +214,4 @@ public abstract class Setting<T, I> {
}
}
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,7 +5,3 @@ 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