v2.6
This commit is contained in:
1 parent
f794457538
commit
9afaa4e0c8
59 files changed
+1605
-217
No files matched your search
@@ -25,7 +25,6 @@ dependencies {
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}"
|
||||
|
||||
}
|
||||
|
||||
loom {
|
||||
|
||||
+16
-3
@@ -1,15 +1,28 @@
|
||||
# v2.5
|
||||
# v2.6
|
||||
|
||||
## novedades
|
||||
|
||||
- grupos de ajustes, para mayor orden, y arreglo de algún que otro bug
|
||||
|
||||
### adiciones
|
||||
|
||||
- layouts de teclado (en_us y es_es) (fuck azerty)
|
||||
- comando `$config` para abrir el marco de ajustes de un módulo
|
||||
- elemento del hud que muestra la rotación de la cámara del jugador
|
||||
|
||||
#### módulos nuevos:
|
||||
|
||||
- fuentes: cambia la tipografía que usa todo el juego a una custom
|
||||
- escalones: actúa con la altura deseada como si se estuviesen subiendo escalones
|
||||
- escalones inversos: escalones, pabajo
|
||||
- partículas: genera particulas artificiales
|
||||
|
||||
### arreglos / mejoras
|
||||
|
||||
- ahora puedes cambiar el grosor de las líneas del contorno de los bloques
|
||||
- arreglada la compatibilidad con meteor client
|
||||
- optimizado y mejorado superposición de luz y resaltado de bloques
|
||||
- ahora, en los marcos de seleccion única, en el tooltip de cada opción dice "seleccionar" en lugar de "incluir"
|
||||
- ahora precoz también tiene una opción de reducir el cooldown al minar bloques
|
||||
|
||||
## problemas reconocidos
|
||||
|
||||
- muchos, pero repórtalos en la página de problemas si quieres para que queden bien registrados
|
||||
+1
-1
@@ -8,6 +8,6 @@ loom_version=1.13-SNAPSHOT
|
||||
|
||||
fabric_api_version=0.140.2+1.21.11
|
||||
|
||||
mod_version=2.5
|
||||
mod_version=2.6
|
||||
maven_group=me.retucio
|
||||
archives_base_name=sputnik
|
||||
@@ -29,6 +29,7 @@ import me.retucio.sputnik.ui.widgets.frames.SettingsFrame;
|
||||
import me.retucio.sputnik.ui.widgets.Button;
|
||||
|
||||
import me.retucio.sputnik.util.*;
|
||||
import me.retucio.sputnik.util.KeyUtil;
|
||||
import me.retucio.sputnik.util.render.DrawUtil;
|
||||
import me.retucio.sputnik.util.render.RenderUtil;
|
||||
|
||||
@@ -69,6 +70,11 @@ public class Sputnik implements ClientModInitializer {
|
||||
private Screen prevScreen;
|
||||
public static boolean settingsApplied = false;
|
||||
|
||||
static {
|
||||
// puta vida
|
||||
System.setProperty("java.awt.headless", "false");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
mc = MinecraftClient.getInstance();
|
||||
|
||||
@@ -32,6 +32,7 @@ public class CommandManager {
|
||||
|
||||
public static void registerCommands() {
|
||||
addCommand(new BindCommand());
|
||||
addCommand(new ConfigCommand());
|
||||
addCommand(new CopyScreenshotCommand());
|
||||
addCommand(new EnderChestCommand());
|
||||
addCommand(new GarbageCleanerCommand());
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import me.retucio.sputnik.module.Module;
|
||||
import me.retucio.sputnik.module.ModuleManager;
|
||||
import me.retucio.sputnik.util.MiscUtil;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
@@ -19,6 +20,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
public class ModuleArgumentType implements ArgumentType<Module> {
|
||||
|
||||
public static final ModuleArgumentType INSTANCE = new ModuleArgumentType();
|
||||
|
||||
private static final DynamicCommandExceptionType UNKNOWN_MODULE = new DynamicCommandExceptionType(
|
||||
name -> Text.literal("módulo \"" + name + "\" no encontrado"));
|
||||
|
||||
@@ -35,7 +37,8 @@ public class ModuleArgumentType implements ArgumentType<Module> {
|
||||
|
||||
@Override
|
||||
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
|
||||
return CommandSource.suggestMatching(ModuleManager.INSTANCE.getModules().stream().map(module -> module.getName().replace(" ", "_")), builder);
|
||||
return CommandSource.suggestMatching(ModuleManager.INSTANCE.getModules()
|
||||
.stream().map(module -> MiscUtil.removeAccentMarks(module.getName().replace(" ", "_"))), builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package me.retucio.sputnik.command.commands;
|
||||
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import me.retucio.sputnik.command.Command;
|
||||
import me.retucio.sputnik.command.args.ModuleArgumentType;
|
||||
import me.retucio.sputnik.module.setting.Setting;
|
||||
import me.retucio.sputnik.ui.screen.ClickGUI;
|
||||
import me.retucio.sputnik.ui.widgets.frames.SettingsFrame;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import me.retucio.sputnik.module.Module;
|
||||
|
||||
public class ConfigCommand extends Command {
|
||||
|
||||
public ConfigCommand() {
|
||||
super("config", "abre el marco de ajustes de un módulo", "ajustes", "settings");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(LiteralArgumentBuilder<CommandSource> builder) {
|
||||
builder
|
||||
.then(argument("módulo", ModuleArgumentType.INSTANCE)
|
||||
.executes(ctx -> {
|
||||
mc.execute(() -> openSf(ctx));
|
||||
return SUCCESS;
|
||||
})
|
||||
.then(argument("x", IntegerArgumentType.integer())
|
||||
.then(argument("y", IntegerArgumentType.integer())
|
||||
.executes(ctx -> {
|
||||
mc.execute(() -> openSfWithPos(ctx,
|
||||
ctx.getArgument("x", Integer.class),
|
||||
ctx.getArgument("y", Integer.class)));
|
||||
return SUCCESS;
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private void openSf(CommandContext<CommandSource> ctx) {
|
||||
Module module = ctx.getArgument("módulo", Module.class);
|
||||
mc.setScreen(ClickGUI.INSTANCE);
|
||||
|
||||
if (ClickGUI.INSTANCE.isSettingsFrameOpen(module)) return;
|
||||
|
||||
SettingsFrame sf = ClickGUI.INSTANCE.getSfOfModule(module);
|
||||
int x = mc.getWindow().getScaledWidth() / 2 - sf.getW() / 2;
|
||||
int y = 67;
|
||||
|
||||
ClickGUI.INSTANCE.openSettingsFrame(module, x, y);
|
||||
}
|
||||
|
||||
private void openSfWithPos(CommandContext<CommandSource> ctx, int x, int y) {
|
||||
Module module = ctx.getArgument("módulo", Module.class);
|
||||
mc.setScreen(ClickGUI.INSTANCE);
|
||||
|
||||
if (ClickGUI.INSTANCE.isSettingsFrameOpen(module)) {
|
||||
SettingsFrame sf = ClickGUI.INSTANCE.getSfOfModule(module);
|
||||
sf.setX(x);
|
||||
sf.setY(y);
|
||||
}
|
||||
|
||||
ClickGUI.INSTANCE.openSettingsFrame(module, x, y);
|
||||
}
|
||||
}
|
||||
@@ -189,8 +189,15 @@ public class ConfigManager {
|
||||
private static void applySettingsFrames() {
|
||||
config.settingsFrames.forEach((moduleName, position) -> {
|
||||
Module module = ModuleManager.INSTANCE.getModuleByName(moduleName);
|
||||
|
||||
if (module == null) {
|
||||
Sputnik.LOGGER.warn("\"null\" como módulo (\"{}\")", moduleName);
|
||||
return;
|
||||
}
|
||||
|
||||
ClickGUI.INSTANCE.openSettingsFrame(module, position[0], position[1]);
|
||||
});
|
||||
|
||||
Sputnik.LOGGER.info("estados de marcos de ajustes aplicados");
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ import java.util.Iterator;
|
||||
|
||||
import static me.retucio.sputnik.Sputnik.EVENT_BUS;
|
||||
|
||||
@Mixin(BossBarHud.class)
|
||||
|
||||
@Mixin(value = BossBarHud.class)
|
||||
public abstract class BossBarHudMixin {
|
||||
|
||||
@ModifyExpressionValue(method = "render", at = @At(value = "INVOKE", target = "Ljava/util/Collection;iterator()Ljava/util/Iterator;"))
|
||||
@@ -30,7 +31,8 @@ public abstract class BossBarHudMixin {
|
||||
return event.getName();
|
||||
}
|
||||
|
||||
@ModifyConstant(method = "render", constant = @Constant(intValue = 9, ordinal = 1))
|
||||
// require = 0 para meteor
|
||||
@ModifyConstant(method = "render", constant = @Constant(intValue = 9, ordinal = 1), require = 0)
|
||||
public int modifySpacingConstant(int constant) {
|
||||
RenderBossbarEvent.BossSpacing event = EVENT_BUS.post(new RenderBossbarEvent.BossSpacing(constant));
|
||||
return event.getSpacing();
|
||||
|
||||
@@ -6,6 +6,7 @@ import me.retucio.sputnik.event.events.InteractEntityEvent;
|
||||
import me.retucio.sputnik.event.events.PlaceBlockEvent;
|
||||
import me.retucio.sputnik.module.ModuleManager;
|
||||
import me.retucio.sputnik.module.modules.camera.Freecam;
|
||||
import me.retucio.sputnik.module.modules.player.FastUse;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
@@ -16,6 +17,8 @@ import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -31,8 +34,8 @@ import static me.retucio.sputnik.Sputnik.mc;
|
||||
@Mixin(ClientPlayerInteractionManager.class)
|
||||
public abstract class ClientPlayerInteractionManagerMixin {
|
||||
|
||||
@Shadow @Final
|
||||
private MinecraftClient client;
|
||||
@Shadow
|
||||
private int blockBreakingCooldown;
|
||||
|
||||
@Unique
|
||||
Freecam freecam;
|
||||
@@ -69,4 +72,13 @@ public abstract class ClientPlayerInteractionManagerMixin {
|
||||
AttackEntityEvent event = EVENT_BUS.post(new AttackEntityEvent(target));
|
||||
if (event.isCancelled()) ci.cancel();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Inject(method = "updateBlockBreakingProgress", at = @At(value = "FIELD", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;blockBreakingCooldown:I"))
|
||||
private void modifyBlockBreakingCooldown(BlockPos pos, Direction direction, CallbackInfoReturnable<Boolean> cir) {
|
||||
FastUse fastUse = ModuleManager.INSTANCE.getModuleByClass(FastUse.class);
|
||||
if (!fastUse.isEnabled() || !fastUse.mining.isEnabled()) return;
|
||||
blockBreakingCooldown = fastUse.miningCooldown.getIntValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package me.retucio.sputnik.mixin;
|
||||
|
||||
import me.retucio.sputnik.Sputnik;
|
||||
|
||||
import me.retucio.sputnik.module.ModuleManager;
|
||||
import me.retucio.sputnik.module.modules.render.Fonts;
|
||||
import net.minecraft.client.font.FontManager;
|
||||
import net.minecraft.client.font.FontStorage;
|
||||
import net.minecraft.text.StyleSpriteSource;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
|
||||
@Mixin(FontManager.class)
|
||||
public abstract class FontManagerMixin {
|
||||
|
||||
@Shadow
|
||||
public abstract FontStorage getStorageInternal(Identifier id);
|
||||
|
||||
@Inject(method = "getStorageInternal", at = @At("HEAD"), cancellable = true)
|
||||
private void onGetStorageInternal(Identifier id, CallbackInfoReturnable<FontStorage> cir) {
|
||||
Fonts fonts = ModuleManager.INSTANCE.getModuleByClass(Fonts.class);
|
||||
if (!fonts.isEnabled()) return;
|
||||
|
||||
if (id.equals(StyleSpriteSource.Font.DEFAULT.id())) {
|
||||
cir.setReturnValue(getStorageInternal(
|
||||
Identifier.of(
|
||||
Sputnik.MOD_ID,
|
||||
fonts.font.getValue())
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package me.retucio.sputnik.mixin;
|
||||
|
||||
import me.retucio.sputnik.module.ModuleManager;
|
||||
import me.retucio.sputnik.module.modules.player.ElytraBounce;
|
||||
import me.retucio.sputnik.module.modules.player.Step;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
@@ -12,6 +13,7 @@ import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import static me.retucio.sputnik.Sputnik.mc;
|
||||
|
||||
@@ -26,7 +28,7 @@ public abstract class LivingEntityMixin {
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Inject(method = "tickMovement", at = @At("TAIL"))
|
||||
public void recastIfLanded(CallbackInfo ci) {
|
||||
private void recastIfLanded(CallbackInfo ci) {
|
||||
ElytraBounce bounce = ModuleManager.INSTANCE.getModuleByClass(ElytraBounce.class);
|
||||
|
||||
if (!((Object) this instanceof ClientPlayerEntity)
|
||||
@@ -47,4 +49,11 @@ public abstract class LivingEntityMixin {
|
||||
|
||||
prevElytra = elytra;
|
||||
}
|
||||
|
||||
|
||||
@Inject(method = "getStepHeight", at = @At("RETURN"), cancellable = true)
|
||||
private void step(CallbackInfoReturnable<Float> cir) {
|
||||
Step step = ModuleManager.INSTANCE.getModuleByClass(Step.class);
|
||||
if (step.isEnabled()) cir.setReturnValue(step.height.getFloatValue());
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,9 @@ import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Hand;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.*;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.*;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@@ -27,6 +27,12 @@ public abstract class MinecraftClientMixin {
|
||||
@Shadow
|
||||
private int itemUseCooldown;
|
||||
|
||||
@Shadow
|
||||
public int attackCooldown;
|
||||
|
||||
|
||||
// eventos
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void onTickPre(CallbackInfo ci) {
|
||||
Sputnik.INSTANCE.onTick();
|
||||
@@ -49,9 +55,10 @@ public abstract class MinecraftClientMixin {
|
||||
if (event.isCancelled()) ci.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "isTelemetryEnabledByApi", at = @At("RETURN"), cancellable = true)
|
||||
private void disableMicropenisTelemetryShi(CallbackInfoReturnable<Boolean> cir) {
|
||||
cir.setReturnValue(false);
|
||||
@Inject(method = "joinWorld", at = @At("HEAD"), cancellable = true)
|
||||
private void onJoinWorld(ClientWorld world, CallbackInfo ci) {
|
||||
JoinWorldEvent event = Sputnik.EVENT_BUS.post(new JoinWorldEvent(world));
|
||||
if (event.isCancelled()) ci.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "doItemUse", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;getStackInHand(Lnet/minecraft/util/Hand;)Lnet/minecraft/item/ItemStack;"), cancellable = true)
|
||||
@@ -61,16 +68,21 @@ public abstract class MinecraftClientMixin {
|
||||
if (event.isCancelled()) ci.cancel();
|
||||
}
|
||||
|
||||
|
||||
// telemetría
|
||||
|
||||
@Inject(method = "isTelemetryEnabledByApi", at = @At("RETURN"), cancellable = true)
|
||||
private void disableMicropenisTelemetryShi(CallbackInfoReturnable<Boolean> cir) {
|
||||
cir.setReturnValue(false);
|
||||
}
|
||||
|
||||
|
||||
// precoz
|
||||
|
||||
@Inject(method = "doItemUse", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isItemEnabled(Lnet/minecraft/resource/featuretoggle/FeatureSet;)Z"))
|
||||
private void modifyItemUseCooldown(CallbackInfo ci, @Local ItemStack stack) {
|
||||
FastUse fastUse = ModuleManager.INSTANCE.getModuleByClass(FastUse.class);
|
||||
if (!fastUse.isEnabled()) return;
|
||||
itemUseCooldown = fastUse.getCooldown(stack);
|
||||
}
|
||||
|
||||
@Inject(method = "joinWorld", at = @At("HEAD"), cancellable = true)
|
||||
private void onJoinWorld(ClientWorld world, CallbackInfo ci) {
|
||||
JoinWorldEvent event = Sputnik.EVENT_BUS.post(new JoinWorldEvent(world));
|
||||
if (event.isCancelled()) ci.cancel();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.retucio.sputnik.mixin;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.buffers.GpuBufferSlice;
|
||||
import me.retucio.sputnik.Sputnik;
|
||||
@@ -18,13 +19,12 @@ import net.minecraft.util.profiler.Profiler;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector4f;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.*;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static me.retucio.sputnik.Sputnik.EVENT_BUS;
|
||||
import static me.retucio.sputnik.Sputnik.mc;
|
||||
|
||||
@@ -66,11 +66,18 @@ public abstract class WorldRendererMixin {
|
||||
if (!noRender.blindnessEffect.isEnabled() || !noRender.darknessEffect.isEnabled()) cir.setReturnValue(null);
|
||||
}
|
||||
|
||||
@Redirect(method = "renderTargetBlockOutline", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/ColorHelper;toAlpha(I)I"))
|
||||
private int modifyBlockOutlineColor(int alpha) {
|
||||
BlockOutline outline = ModuleManager.INSTANCE.getModuleByClass(BlockOutline.class);
|
||||
if (!outline.isEnabled()) return ColorHelper.toAlpha(alpha);
|
||||
|
||||
@ModifyArg(method = "renderTargetBlockOutline", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;drawBlockOutline(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;DDDLnet/minecraft/client/render/state/OutlineRenderState;IF)V"))
|
||||
private int modifyBlockOutlineColor(int original) {
|
||||
BlockOutline outline = ModuleManager.INSTANCE.getModuleByClass(BlockOutline.class);
|
||||
if (!outline.isEnabled()) return original;
|
||||
return outline.color.getRGB();
|
||||
}
|
||||
|
||||
@ModifyArg(method = "renderTargetBlockOutline", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;drawBlockOutline(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;DDDLnet/minecraft/client/render/state/OutlineRenderState;IF)V"))
|
||||
private float modifyBlockOutlineLineWidth(float original) {
|
||||
BlockOutline outline = ModuleManager.INSTANCE.getModuleByClass(BlockOutline.class);
|
||||
if (!outline.isEnabled()) return original;
|
||||
return outline.lineWidth.getFloatValue();
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import me.retucio.sputnik.module.modules.player.*;
|
||||
import me.retucio.sputnik.module.modules.render.*;
|
||||
import me.retucio.sputnik.module.modules.render.CritsPlus;
|
||||
import me.retucio.sputnik.module.modules.world.*;
|
||||
import me.retucio.sputnik.util.MiscUtil;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
@@ -47,6 +48,7 @@ public class ModuleManager {
|
||||
modules.add(new ElytraBounce());
|
||||
modules.add(new FakePlayer());
|
||||
modules.add(new FastUse());
|
||||
modules.add(new Fonts());
|
||||
modules.add(new Freecam());
|
||||
modules.add(new Freelook());
|
||||
modules.add(new Fullbright());
|
||||
@@ -62,15 +64,18 @@ public class ModuleManager {
|
||||
modules.add(new NoRender());
|
||||
modules.add(new Offhand());
|
||||
modules.add(new PacketDelay());
|
||||
modules.add(new Particles());
|
||||
modules.add(new PerspectivePlus());
|
||||
modules.add(new PortalGUI());
|
||||
modules.add(new Racist());
|
||||
modules.add(new Reconnect());
|
||||
modules.add(new ReverseStep());
|
||||
modules.add(new Rotations());
|
||||
modules.add(new RPackBypass());
|
||||
modules.add(new SafeWalk());
|
||||
modules.add(new ScreenshotPlus());
|
||||
modules.add(new ShulkerPeek());
|
||||
modules.add(new Step());
|
||||
modules.add(new TimeChanger());
|
||||
modules.add(new UIMove());
|
||||
modules.add(new WarnLowDurability());
|
||||
@@ -105,7 +110,8 @@ public class ModuleManager {
|
||||
|
||||
public Module getModuleByName(String name) {
|
||||
for (Module module : modules)
|
||||
if (module.getName().equalsIgnoreCase(name)) return module;
|
||||
if (MiscUtil.removeAccentMarks(module.getName()).equalsIgnoreCase(name))
|
||||
return module;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,21 +4,41 @@ import me.retucio.sputnik.event.events.RenderBossbarEvent;
|
||||
import me.retucio.sputnik.event.SubscribeEvent;
|
||||
import me.retucio.sputnik.module.Category;
|
||||
import me.retucio.sputnik.module.Module;
|
||||
import me.retucio.sputnik.module.setting.SettingGroup;
|
||||
import me.retucio.sputnik.module.setting.settings.BooleanSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.ColorSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.EnumSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.NumberSetting;
|
||||
import net.minecraft.client.gui.hud.ClientBossBar;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class BossbarStack extends Module {
|
||||
|
||||
public BooleanSetting stackBars = sgGeneral.add(new BooleanSetting("apilar barras", "apilar las bossbars", true));
|
||||
public BooleanSetting hideNames = sgGeneral.add(new BooleanSetting("esconder nombres", "no renderiza el nombre de los bosses", false));
|
||||
public NumberSetting spaceReduction = sgGeneral.add(new NumberSetting("reducción de espacio", "cuánto reducir el espacio entre bossbars",
|
||||
0, 0, 10, 0.1));
|
||||
public BooleanSetting stackBars = sgGeneral.add(new BooleanSetting(
|
||||
"apilar barras", "apilar las bossbars",
|
||||
true
|
||||
));
|
||||
|
||||
public BooleanSetting hideNames = sgGeneral.add(new BooleanSetting(
|
||||
"esconder nombres", "no renderiza el nombre de los bosses",
|
||||
false
|
||||
));
|
||||
|
||||
public NumberSetting spaceReduction = sgGeneral.add(new NumberSetting(
|
||||
"reducción de espacio",
|
||||
"cuánto reducir el espacio entre bossbars",
|
||||
0,
|
||||
0,
|
||||
10,
|
||||
0.1
|
||||
));
|
||||
|
||||
|
||||
private final Map<ClientBossBar, Integer> bossBarMap = new WeakHashMap<>();
|
||||
|
||||
|
||||
@@ -6,19 +6,60 @@ import me.retucio.sputnik.module.setting.settings.BooleanSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.NumberSetting;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
public class FastUse extends Module {
|
||||
|
||||
public BooleanSetting items = sgGeneral.add(new BooleanSetting("items", "usar items precozmente", true));
|
||||
public NumberSetting itemCooldown = sgGeneral.add(new NumberSetting("cooldown de items", "cooldown para usar items en ticks", 0, 0, 4, 1));
|
||||
public BooleanSetting items = sgGeneral.add(new BooleanSetting(
|
||||
"items",
|
||||
"usar items precozmente",
|
||||
true
|
||||
));
|
||||
|
||||
public NumberSetting itemCooldown = sgGeneral.add(new NumberSetting(
|
||||
"cooldown de items",
|
||||
"cooldown para usar items en ticks",
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
1
|
||||
));
|
||||
|
||||
|
||||
public BooleanSetting blocks = sgGeneral.add(new BooleanSetting(
|
||||
"bloques",
|
||||
"colocar bloques precozmente",
|
||||
true
|
||||
));
|
||||
|
||||
public NumberSetting blockCooldown = sgGeneral.add(new NumberSetting(
|
||||
"cooldown de bloques",
|
||||
"cooldown para colocar bloques en ticks",
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
1
|
||||
));
|
||||
|
||||
|
||||
public BooleanSetting mining = sgGeneral.add(new BooleanSetting(
|
||||
"minar",
|
||||
"minar precozmente",
|
||||
true
|
||||
));
|
||||
|
||||
public NumberSetting miningCooldown = sgGeneral.add(new NumberSetting(
|
||||
"cooldown al minar",
|
||||
"cooldown entre rotura de bloques en ticks",
|
||||
5, 0, 20, 1
|
||||
));
|
||||
|
||||
public BooleanSetting blocks = sgGeneral.add(new BooleanSetting("bloques", "colocar bloques precozmente", true));
|
||||
public NumberSetting blockCooldown = sgGeneral.add(new NumberSetting("cooldown de bloques", "cooldown para colocar bloques en ticks", 0, 0, 4, 1));
|
||||
|
||||
public FastUse() {
|
||||
super("precoz",
|
||||
"hace cosas como usar items o colocar bloques más rápido",
|
||||
Category.PLAYER);
|
||||
Category.PLAYER,
|
||||
GLFW.GLFW_KEY_F6);
|
||||
|
||||
items.onUpdate(v -> itemCooldown.setVisible(v));
|
||||
blocks.onUpdate(v -> blockCooldown.setVisible(v));
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package me.retucio.sputnik.module.modules.player;
|
||||
|
||||
import me.retucio.sputnik.module.Category;
|
||||
import me.retucio.sputnik.module.Module;
|
||||
import me.retucio.sputnik.module.setting.settings.BooleanSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.NumberSetting;
|
||||
import me.retucio.sputnik.util.ChatUtil;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.RaycastContext;
|
||||
|
||||
public class ReverseStep extends Module {
|
||||
|
||||
public NumberSetting height = sgGeneral.add(new NumberSetting(
|
||||
"altura", "altura máxima a bajar",
|
||||
1, 0, 20, 0.1
|
||||
));
|
||||
|
||||
public NumberSetting velocity = sgGeneral.add(new NumberSetting(
|
||||
"velocidad", "velocidad a la que caer en bps",
|
||||
1, 0, 10, 0.1
|
||||
));
|
||||
|
||||
public BooleanSetting jumping = sgGeneral.add(new BooleanSetting(
|
||||
"saltar", "permitir saltar",
|
||||
true
|
||||
));
|
||||
|
||||
public BooleanSetting disableInWater = sgGeneral.add(new BooleanSetting(
|
||||
"desactivar en agua", ".",
|
||||
true
|
||||
));
|
||||
|
||||
public ReverseStep() {
|
||||
super("escalones inversos",
|
||||
"escalones pero pabajo",
|
||||
Category.PLAYER
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick() {
|
||||
if (mc.player == null || mc.world == null) return;
|
||||
|
||||
if (!mc.player.isOnGround()) {
|
||||
if (jumping.isEnabled()) return;
|
||||
}
|
||||
|
||||
if ((mc.player.isTouchingWater() || mc.player.isInLava())) {
|
||||
if (disableInWater.isEnabled()) return;
|
||||
}
|
||||
|
||||
double dropHeight = getHeight();
|
||||
if (dropHeight > 0 && dropHeight <= height.getValue()) {
|
||||
mc.player.addVelocity(0, -height.getValue() + mc.player.getVelocity().getY(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private double getHeight() {
|
||||
Vec3d start = new Vec3d(mc.player.getX(), mc.player.getY() - 0.1, mc.player.getZ());
|
||||
Vec3d end = new Vec3d(mc.player.getX(), mc.player.getY() - height.getValue() - 1, mc.player.getZ());
|
||||
|
||||
RaycastContext context = new RaycastContext(
|
||||
start, end,
|
||||
RaycastContext.ShapeType.COLLIDER,
|
||||
RaycastContext.FluidHandling.ANY,
|
||||
mc.player
|
||||
);
|
||||
|
||||
HitResult hit = mc.world.raycast(context);
|
||||
|
||||
if (hit != null && hit.getType() == HitResult.Type.BLOCK) {
|
||||
BlockPos hitPos = new BlockPos(
|
||||
(int) hit.getPos().x,
|
||||
(int) hit.getPos().y,
|
||||
(int) hit.getPos().z
|
||||
);
|
||||
|
||||
return mc.player.getY() - (hitPos.getY());
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package me.retucio.sputnik.module.modules.player;
|
||||
|
||||
import me.retucio.sputnik.module.Category;
|
||||
import me.retucio.sputnik.module.Module;
|
||||
import me.retucio.sputnik.module.setting.settings.NumberSetting;
|
||||
|
||||
public class Step extends Module {
|
||||
|
||||
public NumberSetting height = sgGeneral.add(new NumberSetting(
|
||||
"altura", "altura máxima a subir",
|
||||
1, 0, 3, 0.1
|
||||
));
|
||||
|
||||
public Step() {
|
||||
super("escalones", "hace que el bloque de subida de escalón sea la distancia deseada", Category.PLAYER);
|
||||
}
|
||||
}
|
||||
@@ -14,30 +14,96 @@ import me.retucio.sputnik.util.Lists;
|
||||
import me.retucio.sputnik.util.render.RenderUtil;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.shape.VoxelShape;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
public class BlockESP extends Module {
|
||||
|
||||
SettingGroup sgSearch = addSg(new SettingGroup("búsqueda", true));
|
||||
SettingGroup sgOulines = addSg(new SettingGroup("contorno", true));
|
||||
SettingGroup sgFilling = addSg(new SettingGroup("relleno", true));
|
||||
|
||||
public ListSetting<Block> blocks = sgGeneral.add(new ListSetting<>("bloques", "bloques a resaltar",
|
||||
Lists.blockList, Lists.allFalse(Lists.blockList), Lists.blockNames));
|
||||
public NumberSetting radius = sgGeneral.add(new NumberSetting("radio", "radio de búsqueda de bloques",
|
||||
24, 2, 128, 1));
|
||||
|
||||
public BooleanSetting outlines = sgOulines.add(new BooleanSetting("contorno", "renderizar contorno de bloques", true));
|
||||
public ColorSetting outlineColor = sgOulines.add(new ColorSetting("color del contorno", "color del contorno", Colors.CELESTE, false));
|
||||
public NumberSetting lineWidth = sgOulines.add(new NumberSetting("grosor del contorno", "grosor de las líneas del contorno", 1, 1, 5, 0.2));
|
||||
// bloques
|
||||
|
||||
public BooleanSetting fillings = sgFilling.add(new BooleanSetting("relleno", "renderizar relleno de bloques", true));
|
||||
public ColorSetting fillingColor = sgFilling.add(new ColorSetting("color del relleno", "color del relleno", new Color(57, 177, 215, 67), false));
|
||||
public ListSetting<Block> blocks = sgGeneral.add(new ListSetting<>(
|
||||
"bloques", "bloques a resaltar",
|
||||
Lists.blockList,
|
||||
Lists.allFalse(Lists.blockList),
|
||||
Lists.blockNames
|
||||
));
|
||||
|
||||
public NumberSetting maxBlocks = sgGeneral.add(new NumberSetting(
|
||||
"máx. bloques", "número máximo de bloques a resaltar",
|
||||
500, 1, 2000, 1
|
||||
));
|
||||
|
||||
|
||||
// búsqueda
|
||||
|
||||
public NumberSetting radius = sgSearch.add(new NumberSetting(
|
||||
"radio", "radio de búsqueda de bloques",
|
||||
24, 2, 128, 1
|
||||
));
|
||||
|
||||
public NumberSetting searchInterval = sgSearch.add(new NumberSetting(
|
||||
"intervalo", "intervalo de búsqueda en ticks",
|
||||
10, 1, 40, 1
|
||||
));
|
||||
|
||||
public BooleanSetting asyncSearch = sgSearch.add(new BooleanSetting(
|
||||
"búsqueda asíncrona", "busca los bloques en un hilo separado (optimización)",
|
||||
true
|
||||
));
|
||||
|
||||
public NumberSetting distanceToMove = sgSearch.add(new NumberSetting(
|
||||
"distancia a moverse", "distancia a moverse antes de actualizar los bloques",
|
||||
3, 0, 10, 0.1
|
||||
));
|
||||
|
||||
|
||||
// contorno
|
||||
|
||||
public BooleanSetting outlines = sgOulines.add(new BooleanSetting(
|
||||
"contorno", "renderizar contorno de bloques",
|
||||
true
|
||||
));
|
||||
|
||||
public ColorSetting outlineColor = sgOulines.add(new ColorSetting(
|
||||
"color del contorno", "color del contorno",
|
||||
Colors.CELESTE, false
|
||||
));
|
||||
|
||||
public NumberSetting lineWidth = sgOulines.add(new NumberSetting(
|
||||
"grosor del contorno", "grosor de las líneas del contorno",
|
||||
1, 1, 5, 0.2
|
||||
));
|
||||
|
||||
|
||||
// relleno
|
||||
|
||||
public BooleanSetting fillings = sgFilling.add(new BooleanSetting(
|
||||
"relleno", "renderizar relleno de bloques",
|
||||
true
|
||||
));
|
||||
|
||||
public ColorSetting fillingColor = sgFilling.add(new ColorSetting(
|
||||
"color del relleno", "color del relleno",
|
||||
new Color(57, 177, 215, 67), false
|
||||
));
|
||||
|
||||
// caché
|
||||
private final Map<BlockPos, VoxelShape> cachedBlocks = new ConcurrentHashMap<>();
|
||||
private final Set<Block> enabledBlocks = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
private BlockPos lastPlayerPos = null;
|
||||
private int lastRadius = -1;
|
||||
private int searchTimer = 0;
|
||||
private boolean isSearching = false;
|
||||
|
||||
|
||||
public BlockESP() {
|
||||
@@ -45,61 +111,166 @@ public class BlockESP extends Module {
|
||||
"te muestra la posición de cierto tipo de bloque renderizando una caja con su forma",
|
||||
Category.RENDER);
|
||||
|
||||
blocks.onUpdate(v ->
|
||||
updateEnabledBlocks()
|
||||
);
|
||||
|
||||
outlines.onUpdate(v -> {
|
||||
outlineColor.setVisible(v);
|
||||
lineWidth.setVisible(v);
|
||||
});
|
||||
|
||||
fillings.onUpdate(v -> fillingColor.setVisible(v));
|
||||
fillings.onUpdate(v ->
|
||||
fillingColor.setVisible(v)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
cachedBlocks.clear();
|
||||
enabledBlocks.clear();
|
||||
updateEnabledBlocks();
|
||||
searchTimer = 0;
|
||||
|
||||
super.onEnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
cachedBlocks.clear();
|
||||
enabledBlocks.clear();
|
||||
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onRenderWorld(Render3DEvent event) {
|
||||
if (mc.player == null || mc.world == null) return;
|
||||
|
||||
for (Block block : blocks.getOptions()) {
|
||||
if (blocks.isEnabled(block)) {
|
||||
List<BlockPos> blocksToHighlight = getNearbyBlocks(block);
|
||||
for (BlockPos pos : blocksToHighlight) {
|
||||
if (outlines.isEnabled()) {
|
||||
RenderUtil.drawVoxelShapeOutline(
|
||||
event.getMatrices(),
|
||||
getVoxelShape(pos),
|
||||
pos,
|
||||
outlineColor.getColor(),
|
||||
lineWidth.getFloatValue(),
|
||||
false);
|
||||
}
|
||||
if (fillings.isEnabled()) {
|
||||
RenderUtil.drawVoxelShapeFilled(
|
||||
event.getMatrices(),
|
||||
getVoxelShape(pos),
|
||||
pos,
|
||||
fillingColor.getColor(),
|
||||
false);
|
||||
// aplicar el intervalo
|
||||
if (searchTimer++ >= searchInterval.getIntValue()) {
|
||||
searchTimer = 0;
|
||||
searchBlocks();
|
||||
}
|
||||
|
||||
Vec3d cameraPos = mc.gameRenderer.getCamera().getCameraPos();
|
||||
|
||||
int rendered = 0;
|
||||
Iterator<Map.Entry<BlockPos, VoxelShape>> iterator = cachedBlocks.entrySet().iterator();
|
||||
|
||||
while (iterator.hasNext() && rendered < maxBlocks.getIntValue()) {
|
||||
Map.Entry<BlockPos, VoxelShape> entry = iterator.next();
|
||||
BlockPos pos = entry.getKey();
|
||||
VoxelShape shape = entry.getValue();
|
||||
|
||||
if (!isValidBlock(pos)) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
// validación de distancia
|
||||
double distance = Math.sqrt(pos.getSquaredDistance(cameraPos));
|
||||
if (distance > radius.getIntValue()) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
// renderizado
|
||||
if (outlines.isEnabled()) {
|
||||
Color color = outlineColor.getColor();
|
||||
RenderUtil.drawVoxelShapeOutline(
|
||||
event.getMatrices(),
|
||||
shape,
|
||||
pos,
|
||||
color,
|
||||
lineWidth.getFloatValue(),
|
||||
false);
|
||||
}
|
||||
|
||||
if (fillings.isEnabled()) {
|
||||
Color color = fillingColor.getColor();
|
||||
RenderUtil.drawVoxelShapeFilled(
|
||||
event.getMatrices(),
|
||||
shape,
|
||||
pos,
|
||||
color,
|
||||
false);
|
||||
}
|
||||
|
||||
rendered++;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateEnabledBlocks() {
|
||||
enabledBlocks.clear();
|
||||
enabledBlocks.addAll(blocks.getEnabledOptions());
|
||||
}
|
||||
|
||||
private void searchBlocks() {
|
||||
if (mc.player == null || mc.world == null || enabledBlocks.isEmpty()) return;
|
||||
|
||||
BlockPos playerPos = mc.player.getBlockPos();
|
||||
int currentRadius = radius.getIntValue();
|
||||
|
||||
// si el jugador no se ha movido mucho, omitir la búsqueda
|
||||
if (lastPlayerPos != null && lastRadius == currentRadius &&
|
||||
playerPos.getSquaredDistance(lastPlayerPos) < (distanceToMove.getValue() * distanceToMove.getIntValue())) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastPlayerPos = playerPos;
|
||||
lastRadius = currentRadius;
|
||||
|
||||
// multithreading
|
||||
if (asyncSearch.isEnabled()) {
|
||||
if (isSearching) return;
|
||||
|
||||
isSearching = true;
|
||||
new Thread(() -> {
|
||||
try {
|
||||
performBlockSearch(playerPos, currentRadius);
|
||||
} finally {
|
||||
isSearching = false;
|
||||
}
|
||||
}, "sputnik-blockESP-search").start();
|
||||
} else {
|
||||
performBlockSearch(playerPos, currentRadius);
|
||||
}
|
||||
}
|
||||
|
||||
// buscar los bloques
|
||||
private void performBlockSearch(BlockPos center, int radius) {
|
||||
Map<BlockPos, VoxelShape> newBlocks = new HashMap<>();
|
||||
int radiusSq = radius * radius;
|
||||
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
for (int y = -radius; y <= radius; y++) {
|
||||
for (int z = -radius; z <= radius; z++) {
|
||||
if (x*x + y*y + z*z > radiusSq) continue;
|
||||
|
||||
BlockPos pos = center.add(x, y, z);
|
||||
Block block = mc.world.getBlockState(pos).getBlock();
|
||||
|
||||
if (enabledBlocks.contains(block)) {
|
||||
VoxelShape shape = mc.world.getBlockState(pos).getOutlineShape(mc.world, pos);
|
||||
if (!shape.isEmpty()) {
|
||||
newBlocks.put(pos.toImmutable(), shape);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// actualizar caché
|
||||
cachedBlocks.keySet().retainAll(newBlocks.keySet());
|
||||
cachedBlocks.putAll(newBlocks);
|
||||
}
|
||||
|
||||
private List<BlockPos> getNearbyBlocks(Block block) {
|
||||
List<BlockPos> blockPosList = new ArrayList<>();
|
||||
|
||||
for (int i = -radius.getIntValue(); i < radius.getIntValue(); i++) {
|
||||
for (int j = -radius.getIntValue(); j < radius.getIntValue(); j++) {
|
||||
for (int k = -radius.getIntValue(); k < radius.getIntValue(); k++) {
|
||||
BlockPos pos = mc.player.getBlockPos().add(new Vec3i(i, j, k));
|
||||
if (mc.world.getBlockState(pos).getBlock() == block) {
|
||||
blockPosList.add(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return blockPosList;
|
||||
}
|
||||
|
||||
private VoxelShape getVoxelShape(BlockPos pos) {
|
||||
return mc.world.getBlockState(pos).getOutlineShape(mc.world, pos);
|
||||
// verificar que el bloque sea válido
|
||||
@SuppressWarnings("deprecation")
|
||||
private boolean isValidBlock(BlockPos pos) {
|
||||
if (mc.world == null || !mc.world.isChunkLoaded(pos)) return false;
|
||||
Block block = mc.world.getBlockState(pos).getBlock();
|
||||
return enabledBlocks.contains(block);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package me.retucio.sputnik.module.modules.render;
|
||||
import me.retucio.sputnik.module.Category;
|
||||
import me.retucio.sputnik.module.Module;
|
||||
import me.retucio.sputnik.module.setting.settings.ColorSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.NumberSetting;
|
||||
import me.retucio.sputnik.util.Colors;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@@ -12,8 +14,21 @@ import java.awt.*;
|
||||
|
||||
public class BlockOutline extends Module {
|
||||
|
||||
public ColorSetting color = sgGeneral.add(new ColorSetting("color", "color del contorno de los bloques",
|
||||
new Color(0, 0, 0, 102), true));
|
||||
public ColorSetting color = sgGeneral.add(new ColorSetting(
|
||||
"color",
|
||||
"color del contorno de los bloques",
|
||||
Colors.mainColor,
|
||||
true)
|
||||
);
|
||||
|
||||
public NumberSetting lineWidth = sgGeneral.add(new NumberSetting(
|
||||
"grosor",
|
||||
"grosor de las líneas",
|
||||
0.5,
|
||||
0.1,
|
||||
10,
|
||||
0.1
|
||||
));
|
||||
|
||||
public BlockOutline() {
|
||||
super("contorno",
|
||||
|
||||
@@ -6,6 +6,7 @@ import me.retucio.sputnik.module.setting.SettingGroup;
|
||||
import me.retucio.sputnik.module.setting.settings.BooleanSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.ColorSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.NumberSetting;
|
||||
import me.retucio.sputnik.util.Colors;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@@ -19,7 +20,7 @@ public class CritsPlus extends Module {
|
||||
SettingGroup sgAppearance = addSg(new SettingGroup("aspecto", true));
|
||||
SettingGroup sgBehaviour = addSg(new SettingGroup("funcionamiento", true));
|
||||
|
||||
public ColorSetting color = sgAppearance.add(new ColorSetting("color", "color de las partículas", new Color(0, 0, 255, 255), false));
|
||||
public ColorSetting color = sgAppearance.add(new ColorSetting("color", "color de las partículas", Colors.mainColor, false));
|
||||
public NumberSetting scale = sgAppearance.add(new NumberSetting("escala", "tamaño", 1, 0, 2, 0.05));
|
||||
public NumberSetting multiplier = sgAppearance.add(new NumberSetting("múltiplo", "número por el que multiplicar la cantidad de partículas generadas", 1, 0, 10, 0.1));
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package me.retucio.sputnik.module.modules.render;
|
||||
|
||||
import me.retucio.sputnik.module.Category;
|
||||
import me.retucio.sputnik.module.Module;
|
||||
import me.retucio.sputnik.module.setting.settings.BooleanSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.OptionSetting;
|
||||
import me.retucio.sputnik.util.Lists;
|
||||
|
||||
|
||||
public class Fonts extends Module {
|
||||
|
||||
public OptionSetting<String> font = sgGeneral.add(new OptionSetting<>(
|
||||
"fuente", "fuente a emplear",
|
||||
Lists.fontList, "ubuntu")
|
||||
);
|
||||
|
||||
public BooleanSetting reload = sgGeneral.add(new BooleanSetting(
|
||||
"recargar", "recargar automáticamente",
|
||||
false
|
||||
));
|
||||
|
||||
public Fonts() {
|
||||
super("fuentes",
|
||||
"modifica el tipo de letra utilizado al renderizar texto",
|
||||
Category.RENDER);
|
||||
|
||||
font.onUpdate(v -> reload());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
reload();
|
||||
}
|
||||
|
||||
private void reload() {
|
||||
if (mc.getResourceManager() != null && reload.isEnabled()) {
|
||||
mc.reloadResources();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import me.retucio.sputnik.module.Category;
|
||||
import me.retucio.sputnik.module.Module;
|
||||
import me.retucio.sputnik.module.setting.settings.BooleanSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.EnumSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.NumberSetting;
|
||||
import me.retucio.sputnik.util.render.GlintRenderLayer;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.RenderLayers;
|
||||
@@ -17,9 +18,24 @@ import net.minecraft.util.DyeColor;
|
||||
|
||||
public class GlintPlus extends Module {
|
||||
|
||||
public BooleanSetting items = sgGeneral.add(new BooleanSetting("items", "modificar el destello de encantamiento de los items", true));
|
||||
public BooleanSetting armor = sgGeneral.add(new BooleanSetting("armadura", "modificar el destello de encantamiento de la armadura", true));
|
||||
public EnumSetting<GlintColors> glintColor = sgGeneral.add(new EnumSetting<>("colores", "color del glint", GlintColors.class, GlintColors.PURPLE));
|
||||
public BooleanSetting items = sgGeneral.add(new BooleanSetting(
|
||||
"items",
|
||||
"modificar el destello de encantamiento de los items",
|
||||
true
|
||||
));
|
||||
|
||||
public BooleanSetting armor = sgGeneral.add(new BooleanSetting(
|
||||
"armadura",
|
||||
"modificar el destello de encantamiento de la armadura",
|
||||
true
|
||||
));
|
||||
|
||||
public EnumSetting<GlintColors> glintColor = sgGeneral.add(new EnumSetting<>(
|
||||
"colores",
|
||||
"color del glint",
|
||||
GlintColors.class,
|
||||
GlintColors.PURPLE
|
||||
));
|
||||
|
||||
public GlintPlus() {
|
||||
super("destello de enchants.",
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
package me.retucio.sputnik.module.modules.render;
|
||||
|
||||
import me.retucio.sputnik.module.Category;
|
||||
import me.retucio.sputnik.module.Module;
|
||||
import me.retucio.sputnik.module.setting.SettingGroup;
|
||||
import me.retucio.sputnik.module.setting.settings.ListSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.NumberSetting;
|
||||
import me.retucio.sputnik.util.Lists;
|
||||
import net.minecraft.particle.SimpleParticleType;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class Particles extends Module {
|
||||
|
||||
SettingGroup sgDispersion = addSg(new SettingGroup("dispersión", true));
|
||||
SettingGroup sgOffset = addSg(new SettingGroup("desplazamiento", true));
|
||||
|
||||
List<SimpleParticleType> particleList = Lists.particleList.stream()
|
||||
.filter(particleType -> particleType instanceof SimpleParticleType)
|
||||
.map(particleType -> (SimpleParticleType) particleType)
|
||||
.toList();
|
||||
|
||||
Map<SimpleParticleType, String> particleNames = Lists.getMapOfLists(particleList,
|
||||
particleList.stream().map(particle -> Text.translatable(
|
||||
Registries.PARTICLE_TYPE.getId(particle).toShortTranslationKey()).getString()
|
||||
).toList());
|
||||
|
||||
public ListSetting<SimpleParticleType> particles = sgGeneral.add(new ListSetting<>(
|
||||
"partículas",
|
||||
"partículas a generar",
|
||||
particleList,
|
||||
Lists.allFalse(particleList),
|
||||
particleNames
|
||||
));
|
||||
|
||||
public NumberSetting spawnInterval = sgGeneral.add(new NumberSetting(
|
||||
"intervalo",
|
||||
"intervalo entre generaciones (en ticks)",
|
||||
4, 1, 100, 1
|
||||
));
|
||||
|
||||
public NumberSetting particleCount = sgGeneral.add(new NumberSetting(
|
||||
"cantidad",
|
||||
"partículas por generación",
|
||||
10, 1, 100, 1
|
||||
));
|
||||
|
||||
|
||||
public NumberSetting velocity = sgDispersion.add(new NumberSetting(
|
||||
"velocidad",
|
||||
"multiplicador de la velocidad de dispersión",
|
||||
0.2, 0, 2, 0.05
|
||||
));
|
||||
|
||||
public NumberSetting spreadX = sgDispersion.add(new NumberSetting(
|
||||
"dispersión X",
|
||||
"dispersión horizontal de posición",
|
||||
0.5, 0, 5, 0.1
|
||||
));
|
||||
|
||||
public NumberSetting spreadY = sgDispersion.add(new NumberSetting(
|
||||
"dispersión Y",
|
||||
"dispersión vertical de posición",
|
||||
0.5, 0, 5, 0.1
|
||||
));
|
||||
|
||||
public NumberSetting spreadZ = sgDispersion.add(new NumberSetting(
|
||||
"dispersión Z",
|
||||
"dispersión de profundidad de posición",
|
||||
0.5, 0, 5, 0.1
|
||||
));
|
||||
|
||||
public NumberSetting velocityRandomness = sgDispersion.add(new NumberSetting(
|
||||
"aleatoriedad velocidad",
|
||||
"variación aleatoria en la velocidad",
|
||||
0.3, 0, 1, 0.05
|
||||
));
|
||||
|
||||
public NumberSetting positionRandomness = sgDispersion.add(new NumberSetting(
|
||||
"aleatoriedad posición",
|
||||
"variación aleatoria en la posición",
|
||||
0.2, 0, 1, 0.05
|
||||
));
|
||||
|
||||
|
||||
public NumberSetting offsetX = sgOffset.add(new NumberSetting(
|
||||
"desplazamiento pos. X",
|
||||
"desplazamiento en el eje X respecto al jugador",
|
||||
0, -1, 1, 0.01
|
||||
));
|
||||
|
||||
public NumberSetting offsetY = sgOffset.add(new NumberSetting(
|
||||
"desplazamiento pos. Y",
|
||||
"desplazamiento en el eje Y respecto al jugador",
|
||||
0, -1, 1, 0.01
|
||||
));
|
||||
|
||||
public NumberSetting offsetZ = sgOffset.add(new NumberSetting(
|
||||
"desplazamiento pos. Z",
|
||||
"desplazamiento en el eje Z respecto al jugador",
|
||||
-0.8, -1, 1, 0.01
|
||||
));
|
||||
|
||||
|
||||
private final Random random = new Random();
|
||||
private int tickCounter = 0;
|
||||
|
||||
|
||||
public Particles() {
|
||||
super("partículas", "emite particulas artificiales", Category.RENDER);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
tickCounter = 0;
|
||||
super.onEnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick() {
|
||||
if (mc.player == null || mc.world == null) return;
|
||||
|
||||
tickCounter++;
|
||||
if (tickCounter < spawnInterval.getIntValue()) {
|
||||
return;
|
||||
}
|
||||
tickCounter = 0;
|
||||
|
||||
List<SimpleParticleType> enabledParticles = particles.getEnabledOptions();
|
||||
if (enabledParticles.isEmpty()) return;
|
||||
|
||||
Vec3d basePos = new Vec3d(
|
||||
mc.player.getX(),
|
||||
mc.player.getY() + mc.player.getEyeHeight(mc.player.getPose()),
|
||||
mc.player.getZ()
|
||||
);
|
||||
|
||||
for (int i = 0; i < particleCount.getIntValue(); i++) {
|
||||
SimpleParticleType particle = enabledParticles.get(
|
||||
random.nextInt(enabledParticles.size())
|
||||
);
|
||||
|
||||
Vec3d pos = getPos(basePos);
|
||||
Vec3d vel = getVel();
|
||||
|
||||
double yaw = Math.toRadians(mc.player.getYaw());
|
||||
double offX = offsetX.getValue() * Math.cos(yaw) - offsetZ.getValue() * Math.sin(yaw);
|
||||
double offZ = offsetX.getValue() * Math.sin(yaw) + offsetZ.getValue() * Math.cos(yaw);
|
||||
|
||||
mc.world.addParticleClient(
|
||||
particle,
|
||||
pos.x + offX,
|
||||
pos.y + offsetY.getValue(),
|
||||
pos.z + offZ,
|
||||
vel.x, vel.y, vel.z
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private Vec3d getPos(Vec3d basePos) {
|
||||
double randX = (random.nextDouble() - 0.5) * 2 * positionRandomness.getValue();
|
||||
double randY = (random.nextDouble() - 0.5) * 2 * positionRandomness.getValue();
|
||||
double randZ = (random.nextDouble() - 0.5) * 2 * positionRandomness.getValue();
|
||||
|
||||
return new Vec3d(
|
||||
basePos.x + (random.nextDouble() - 0.5) * spreadX.getValue() + randX,
|
||||
basePos.y + (random.nextDouble() - 0.5) * spreadY.getValue() + randY,
|
||||
basePos.z + (random.nextDouble() - 0.5) * spreadZ.getValue() + randZ
|
||||
);
|
||||
}
|
||||
|
||||
private Vec3d getVel() {
|
||||
double randX = (random.nextDouble() - 0.5) * 2 * velocityRandomness.getValue();
|
||||
double randY = (random.nextDouble() - 0.5) * 2 * velocityRandomness.getValue();
|
||||
double randZ = (random.nextDouble() - 0.5) * 2 * velocityRandomness.getValue();
|
||||
|
||||
return new Vec3d(
|
||||
(random.nextDouble() - 0.5) * velocity.getValue() + randX,
|
||||
(random.nextDouble() - 0.5) * velocity.getValue() + randY,
|
||||
(random.nextDouble() - 0.5) * velocity.getValue() + randZ
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -10,140 +10,350 @@ import me.retucio.sputnik.module.setting.settings.ColorSetting;
|
||||
import me.retucio.sputnik.module.setting.settings.NumberSetting;
|
||||
import me.retucio.sputnik.util.render.RenderUtil;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.Heightmap;
|
||||
import net.minecraft.world.LightType;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class LightOverlay extends Module {
|
||||
|
||||
SettingGroup sgDetection = addSg(new SettingGroup("detección", true));
|
||||
SettingGroup sgColors = addSg(new SettingGroup("colores", true));
|
||||
SettingGroup sgOptimization = addSg(new SettingGroup("optimización", true));
|
||||
|
||||
public NumberSetting radius = sgDetection.add(new NumberSetting("radio", "radio a tener en cuenta al renderizar superposición",
|
||||
// detección
|
||||
public NumberSetting radius = sgDetection.add(new NumberSetting(
|
||||
"radio",
|
||||
"radio a tener en cuenta al renderizar superposición",
|
||||
16, 5, 128, 1));
|
||||
public NumberSetting yRadius = sgDetection.add(new NumberSetting("rango vertical", "distancia vertical a tener en cuenta",
|
||||
|
||||
public NumberSetting yRadius = sgDetection.add(new NumberSetting(
|
||||
"rango vertical",
|
||||
"distancia vertical a tener en cuenta",
|
||||
4, 1, 16, 1));
|
||||
|
||||
public NumberSetting interval = sgDetection.add(new NumberSetting("intervalo", "cada cuántos ticks comprobar el nivel de luz",
|
||||
public BooleanSetting onWater = sgDetection.add(new BooleanSetting(
|
||||
"en agua",
|
||||
"mostrar también bloques cubiertos en agua", true));
|
||||
|
||||
public BooleanSetting dontCullWater = sgDetection.add(new BooleanSetting(
|
||||
"evitar culling en agua",
|
||||
"mostrar superposición a través de bloques para poder verla desde fuera del agua", false));
|
||||
|
||||
|
||||
// optimización, porque iba como la mierda
|
||||
public NumberSetting updateInterval = sgOptimization.add(new NumberSetting(
|
||||
"intervalo de búsqueda",
|
||||
"cada cuántos ticks actualizar la búsqueda de bloques",
|
||||
10, 1, 80, 1));
|
||||
|
||||
public BooleanSetting onWater = sgDetection.add(new BooleanSetting("en agua", "mostrar también bloques cubiertos en agua", true));
|
||||
public BooleanSetting dontCullWater = sgDetection.add(new BooleanSetting("evitar culling en agua", "mostrar superposición a través de bloques para poder verla desde fuera del agua", false));
|
||||
public NumberSetting movementThreshold = sgOptimization.add(new NumberSetting(
|
||||
"umbral de movimiento",
|
||||
"distancia que debe moverse el jugador antes de forzar una actualización",
|
||||
3.0, 0.5, 10.0, 0.5));
|
||||
|
||||
public ColorSetting lightColor = sgColors.add(new ColorSetting("color de la luz", "color de los bloques con luz",
|
||||
public BooleanSetting asyncSearch = sgOptimization.add(new BooleanSetting(
|
||||
"búsqueda asíncrona",
|
||||
"buscar bloques en un hilo separado (reduce lag)",
|
||||
true));
|
||||
|
||||
public BooleanSetting incrementalUpdates = sgOptimization.add(new BooleanSetting(
|
||||
"actualizaciones incrementales",
|
||||
"actualizar solo los bloques nuevos / eliminados en lugar de recalcular todo",
|
||||
true));
|
||||
|
||||
// colores
|
||||
public ColorSetting lightColor = sgColors.add(new ColorSetting(
|
||||
"color de la luz",
|
||||
"color de los bloques con luz",
|
||||
new Color(0, 255, 0, 67), false));
|
||||
public ColorSetting darknessColor = sgColors.add(new ColorSetting("color de oscuridad", "color de bloques con 0 luz",
|
||||
|
||||
public ColorSetting darknessColor = sgColors.add(new ColorSetting(
|
||||
"color de oscuridad",
|
||||
"color de bloques con 0 luz",
|
||||
new Color(255, 0, 0, 67), false));
|
||||
|
||||
|
||||
List<BlockPos> blocks = new ArrayList<>();
|
||||
// caché y estado
|
||||
private final Set<BlockPos> cachedBlocks = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
private final Set<BlockPos> blocksToRender = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
private BlockPos lastPlayerPos = null;
|
||||
private int lastRadius = -1;
|
||||
private int lastYRadius = -1;
|
||||
private int updateTimer = 0;
|
||||
private boolean isSearching = false;
|
||||
|
||||
// para actualizaciones incrementales
|
||||
private int incrementalLayer = 0;
|
||||
private boolean fullRescanNeeded = false;
|
||||
|
||||
public LightOverlay() {
|
||||
super("superposición de luz",
|
||||
"te muestra el nivel de luz en bloques, para prevenir mob spawns",
|
||||
Category.WORLD);
|
||||
|
||||
onWater.onUpdate(v -> dontCullWater.setVisible(v));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
cachedBlocks.clear();
|
||||
blocksToRender.clear();
|
||||
lastPlayerPos = null;
|
||||
lastRadius = -1;
|
||||
lastYRadius = -1;
|
||||
updateTimer = 0;
|
||||
incrementalLayer = 0;
|
||||
fullRescanNeeded = true;
|
||||
|
||||
super.onEnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
cachedBlocks.clear();
|
||||
blocksToRender.clear();
|
||||
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@SuppressWarnings("deprecation")
|
||||
public void onRenderWorld(Render3DEvent event) {
|
||||
if (mc.player == null || mc.world == null) return;
|
||||
if (mc.player.age % interval.getIntValue() == 0) {
|
||||
blocks = findExposedBlocks(
|
||||
radius.getIntValue(),
|
||||
yRadius.getIntValue()
|
||||
);
|
||||
|
||||
// actualización periódica
|
||||
if (updateTimer++ >= updateInterval.getIntValue()) {
|
||||
updateTimer = 0;
|
||||
updateBlocks();
|
||||
}
|
||||
|
||||
for (BlockPos block : blocks) {
|
||||
if (mc.world.getBlockState(block).isAir() || !canSpawnOn(block)) continue;
|
||||
if (!mc.world.getBlockState(block).isOpaque()) continue;
|
||||
// renderizado
|
||||
Vec3d cameraPos = mc.gameRenderer.getCamera().getCameraPos();
|
||||
int radiusValue = radius.getIntValue();
|
||||
double radiusSq = radiusValue * radiusValue;
|
||||
|
||||
// actualizar lista de renderizado basado en distancia
|
||||
blocksToRender.clear();
|
||||
for (BlockPos pos : cachedBlocks) {
|
||||
double distanceSq = pos.getSquaredDistance(cameraPos);
|
||||
if (distanceSq <= radiusSq) {
|
||||
blocksToRender.add(pos);
|
||||
}
|
||||
}
|
||||
|
||||
// renderizar bloques visibles
|
||||
for (BlockPos block : blocksToRender) {
|
||||
if (!mc.world.isChunkLoaded(block)) continue;
|
||||
|
||||
BlockState state = mc.world.getBlockState(block);
|
||||
BlockState aboveState = mc.world.getBlockState(block.up());
|
||||
|
||||
if (!isValidSpawnSurface(block, state, aboveState)) continue;
|
||||
|
||||
// nivel de luz
|
||||
int light = mc.world.getLightLevel(LightType.BLOCK, block.up());
|
||||
|
||||
Color color = light == 0 ? darknessColor.getColor()
|
||||
: new Color(
|
||||
(lightColor.getR() / 15) * light,
|
||||
(lightColor.getG() / 15) * light,
|
||||
(lightColor.getB() / 15) * light,
|
||||
lightColor.getA());
|
||||
// color
|
||||
Color color;
|
||||
if (light == 0) {
|
||||
color = darknessColor.getColor();
|
||||
} else {
|
||||
float ratio = light / 15.0f;
|
||||
color = new Color(
|
||||
(int)(lightColor.getR() * ratio),
|
||||
(int)(lightColor.getG() * ratio),
|
||||
(int)(lightColor.getB() * ratio),
|
||||
lightColor.getA()
|
||||
);
|
||||
}
|
||||
|
||||
boolean shouldCull = !(onWater.isEnabled() && mc.world.getBlockState(block.up()).isOf(Blocks.WATER) && dontCullWater.isEnabled());
|
||||
// renderizar
|
||||
boolean shouldCull = !(onWater.isEnabled() && aboveState.isOf(Blocks.WATER) && dontCullWater.isEnabled());
|
||||
RenderUtil.drawBlockFaceFilled(event.getMatrices(), block, Direction.UP, color, 0.001f, shouldCull);
|
||||
}
|
||||
}
|
||||
|
||||
private List<BlockPos> findExposedBlocks(int radius, int yRadius) {
|
||||
List<BlockPos> results = new ArrayList<>();
|
||||
private void updateBlocks() {
|
||||
if (mc.player == null || mc.world == null) return;
|
||||
|
||||
BlockPos pos = mc.player.getBlockPos();
|
||||
BlockPos playerPos = mc.player.getBlockPos();
|
||||
int currentRadius = radius.getIntValue();
|
||||
int currentYRadius = yRadius.getIntValue();
|
||||
|
||||
int minX = pos.getX() - radius;
|
||||
int maxX = pos.getX() + radius;
|
||||
int minY = Math.max(mc.world.getDimension().minY(), pos.getY() - yRadius);
|
||||
int maxY = Math.min(mc.world.getDimension().height() - 1, pos.getY() + yRadius);
|
||||
int minZ = pos.getZ() - radius;
|
||||
int maxZ = pos.getZ() + radius;
|
||||
// verificar si hace falta actualizar
|
||||
boolean needsUpdate = fullRescanNeeded ||
|
||||
lastRadius != currentRadius ||
|
||||
lastYRadius != currentYRadius ||
|
||||
(lastPlayerPos != null &&
|
||||
playerPos.getSquaredDistance(lastPlayerPos) > (movementThreshold.getValue() * movementThreshold.getValue()));
|
||||
|
||||
maxY = Math.min(maxY, mc.world.getDimension().height() - 2);
|
||||
if (!needsUpdate && incrementalUpdates.isEnabled() && incrementalLayer >= 0) {
|
||||
// actualización incremental de una sola capa
|
||||
performIncrementalUpdate(playerPos, currentRadius, currentYRadius);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!needsUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastPlayerPos = playerPos;
|
||||
lastRadius = currentRadius;
|
||||
lastYRadius = currentYRadius;
|
||||
fullRescanNeeded = false;
|
||||
incrementalLayer = 0;
|
||||
|
||||
// búsqueda
|
||||
if (asyncSearch.isEnabled()) {
|
||||
if (isSearching) return;
|
||||
|
||||
isSearching = true;
|
||||
new Thread(() -> {
|
||||
try {
|
||||
performFullBlockSearch(playerPos, currentRadius, currentYRadius);
|
||||
} finally {
|
||||
isSearching = false;
|
||||
}
|
||||
}, "sputnik-lightoverlay-search").start();
|
||||
} else {
|
||||
performFullBlockSearch(playerPos, currentRadius, currentYRadius);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void performFullBlockSearch(BlockPos center, int radius, int yRadius) {
|
||||
Set<BlockPos> newBlocks = new HashSet<>();
|
||||
int radiusSq = radius * radius;
|
||||
|
||||
int minY = Math.max(mc.world.getBottomY(), center.getY() - yRadius);
|
||||
int maxY = Math.min(mc.world.getTopY(Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, mc.player.getBlockPos()) - 1, center.getY() + yRadius);
|
||||
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
for (int z = -radius; z <= radius; z++) {
|
||||
if (x*x + z*z > radiusSq) continue;
|
||||
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
BlockPos current = new BlockPos(x, y, z);
|
||||
BlockPos pos = center.add(x, y - center.getY(), z);
|
||||
|
||||
if (!mc.world.isAir(current) && canSpawnOn(current))
|
||||
results.add(current);
|
||||
// nuh uh si el chunk no está cargado
|
||||
if (!mc.world.isChunkLoaded(pos)) continue;
|
||||
|
||||
BlockState state = mc.world.getBlockState(pos);
|
||||
BlockState aboveState = mc.world.getBlockState(pos.up());
|
||||
|
||||
if (isValidSpawnSurface(pos, state, aboveState)) {
|
||||
newBlocks.add(pos.toImmutable());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
// actualizar caché
|
||||
cachedBlocks.clear();
|
||||
cachedBlocks.addAll(newBlocks);
|
||||
}
|
||||
|
||||
private boolean canSpawnOn(BlockPos pos) {
|
||||
BlockState aboveState = mc.world.getBlockState(pos.up());
|
||||
@SuppressWarnings("deprecation")
|
||||
private void performIncrementalUpdate(BlockPos center, int radius, int yRadius) {
|
||||
if (incrementalLayer > radius * 2) {
|
||||
incrementalLayer = -radius;
|
||||
}
|
||||
|
||||
int currentX = center.getX() - radius + incrementalLayer;
|
||||
int radiusSq = radius * radius;
|
||||
int minY = Math.max(mc.world.getBottomY(), center.getY() - yRadius);
|
||||
int maxY = Math.min(mc.world.getTopY(Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, mc.player.getBlockPos()) - 1, center.getY() + yRadius);
|
||||
|
||||
// buscar en una columna específica (x fijo, variar z)
|
||||
for (int z = -radius; z <= radius; z++) {
|
||||
int xDist = incrementalLayer;
|
||||
if (xDist*xDist + z*z > radiusSq) continue;
|
||||
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
BlockPos pos = new BlockPos(currentX, y, center.getZ() + z);
|
||||
|
||||
if (!mc.world.isChunkLoaded(pos)) continue;
|
||||
|
||||
BlockState state = mc.world.getBlockState(pos);
|
||||
BlockState aboveState = mc.world.getBlockState(pos.up());
|
||||
|
||||
boolean isValid = isValidSpawnSurface(pos, state, aboveState);
|
||||
|
||||
if (isValid) {
|
||||
cachedBlocks.add(pos.toImmutable());
|
||||
} else {
|
||||
cachedBlocks.remove(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
incrementalLayer++;
|
||||
|
||||
// cada 10 actualizaciones incrementales, hacer una limpieza de bloques lejanos
|
||||
if (incrementalLayer % 10 == 0) {
|
||||
cleanupDistantBlocks(center, radius);
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupDistantBlocks(BlockPos center, int radius) {
|
||||
int radiusSq = radius * radius * 2;
|
||||
Iterator<BlockPos> iterator = cachedBlocks.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
BlockPos pos = iterator.next();
|
||||
int dx = pos.getX() - center.getX();
|
||||
int dz = pos.getZ() - center.getZ();
|
||||
|
||||
if (dx * dx + dz * dz > radiusSq) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidSpawnSurface(BlockPos pos, BlockState state, BlockState aboveState) {
|
||||
if (state.isAir() || !state.isOpaque() || !state.isFullCube(mc.world, pos)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Block aboveBlock = aboveState.getBlock();
|
||||
|
||||
if (aboveState.isAir()) return true;
|
||||
if (aboveBlock == Blocks.WATER && onWater.isEnabled()) return true;
|
||||
|
||||
if (aboveBlock instanceof PlantBlock) return true;
|
||||
|
||||
if (!aboveState.isOpaque() && !aboveState.isFullCube(mc.world, pos.up())) {
|
||||
|
||||
if (aboveBlock instanceof SlabBlock
|
||||
|| aboveBlock instanceof StairsBlock
|
||||
|| aboveBlock instanceof ButtonBlock
|
||||
|| aboveBlock instanceof CarpetBlock
|
||||
|| aboveBlock instanceof PressurePlateBlock
|
||||
|| aboveBlock instanceof PaneBlock
|
||||
|| aboveBlock instanceof TrapdoorBlock
|
||||
|| aboveBlock instanceof FenceBlock
|
||||
|| aboveBlock instanceof WallBlock
|
||||
|| aboveBlock instanceof AnvilBlock
|
||||
|| aboveBlock instanceof BedBlock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aboveBlock == Blocks.CHEST ||
|
||||
aboveBlock == Blocks.ENDER_CHEST ||
|
||||
aboveBlock == Blocks.BARREL ||
|
||||
aboveBlock == Blocks.TRAPPED_CHEST) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return aboveBlock != Blocks.ENCHANTING_TABLE
|
||||
&& aboveBlock != Blocks.GRINDSTONE
|
||||
&& aboveBlock != Blocks.STONECUTTER
|
||||
&& aboveBlock != Blocks.LOOM
|
||||
&& aboveBlock != Blocks.COMPOSTER
|
||||
&& aboveBlock != Blocks.CAKE;
|
||||
if (aboveBlock instanceof SlabBlock ||
|
||||
aboveBlock instanceof StairsBlock ||
|
||||
aboveBlock instanceof ButtonBlock ||
|
||||
aboveBlock instanceof CarpetBlock ||
|
||||
aboveBlock instanceof PressurePlateBlock ||
|
||||
aboveBlock instanceof PaneBlock ||
|
||||
aboveBlock instanceof TrapdoorBlock ||
|
||||
aboveBlock instanceof FenceBlock ||
|
||||
aboveBlock instanceof WallBlock ||
|
||||
aboveBlock instanceof AnvilBlock ||
|
||||
aboveBlock instanceof BedBlock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (aboveBlock == Blocks.CHEST ||
|
||||
aboveBlock == Blocks.ENDER_CHEST ||
|
||||
aboveBlock == Blocks.BARREL ||
|
||||
aboveBlock == Blocks.TRAPPED_CHEST ||
|
||||
aboveBlock == Blocks.ENCHANTING_TABLE ||
|
||||
aboveBlock == Blocks.GRINDSTONE ||
|
||||
aboveBlock == Blocks.STONECUTTER ||
|
||||
aboveBlock == Blocks.LOOM ||
|
||||
aboveBlock == Blocks.COMPOSTER ||
|
||||
aboveBlock == Blocks.CAKE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !aboveState.isOpaque() || !aboveState.isFullCube(mc.world, pos.up());
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,16 @@ public class ListSetting<T> extends Setting {
|
||||
return options;
|
||||
}
|
||||
|
||||
public List<T> getEnabledOptions() {
|
||||
List<T> enabledOptions = new ArrayList<>();
|
||||
for (T option : options) {
|
||||
if (isEnabled(option)) {
|
||||
enabledOptions.add(option);
|
||||
}
|
||||
}
|
||||
return enabledOptions;
|
||||
}
|
||||
|
||||
public Map<T, String> getDisplayNames() {
|
||||
return displayNames;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ public class HudRenderer {
|
||||
addElement(new CustomTextElement(), positions, visibilities);
|
||||
addElement(new TimeElement(), positions, visibilities);
|
||||
addElement(new PingElement(), positions, visibilities);
|
||||
addElement(new RotationElement(), positions, visibilities);
|
||||
|
||||
addElement(new DynoElement(), positions, visibilities);
|
||||
addElement(new EchestElement(), positions, visibilities);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package me.retucio.sputnik.ui.hud.elements;
|
||||
|
||||
import me.retucio.sputnik.module.ModuleManager;
|
||||
import me.retucio.sputnik.module.modules.client.HUD;
|
||||
import me.retucio.sputnik.ui.hud.TextHudElement;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RotationElement extends TextHudElement {
|
||||
|
||||
public RotationElement() {
|
||||
super("rotation", mc.getWindow().getScaledWidth() - mc.textRenderer.getWidth("180º 180º (N)"), mc.getWindow().getScaledHeight() - mc.textRenderer.fontHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(float delta, HUD hud) {
|
||||
if (mc.player == null) return getPreviewText();
|
||||
return String.format("%.2f", mc.player.getYaw()) + "º " + String.format("%.2f", mc.player.getPitch()) + "º (" + getDirection() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreviewText() {
|
||||
if (mc.player == null)
|
||||
return "69º 69º (W)";
|
||||
return getText(mc.getRenderTickCounter().getDynamicDeltaTicks(), ModuleManager.INSTANCE.getModuleByClass(HUD.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Text> getTooltip() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private String getDirection() {
|
||||
return switch (mc.player.getHorizontalFacing()) {
|
||||
case NORTH -> "N";
|
||||
case SOUTH -> "S";
|
||||
case EAST -> "E";
|
||||
case WEST -> "O";
|
||||
default -> "?";
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import org.lwjgl.glfw.GLFW;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static me.retucio.sputnik.ui.widgets.frames.settings.ClientSettingsFrame.guiSettings;
|
||||
|
||||
@@ -248,15 +249,21 @@ public class ClickGUI extends Screen {
|
||||
}
|
||||
}
|
||||
|
||||
public SettingsFrame getSfOfModule(Module module) {
|
||||
Optional<SettingsFrame> frame = settingsFrames.stream()
|
||||
.filter(sf -> sf.getModule().equals(module))
|
||||
.findFirst();
|
||||
|
||||
return frame.orElseGet(() ->
|
||||
new SettingsFrame(module, 0, 0, 100, 20)
|
||||
);
|
||||
}
|
||||
|
||||
// abrir un marco donde se encuentran los ajustes del módulo deseado
|
||||
public void openSettingsFrame(Module module, int x, int y) {
|
||||
for (SettingsFrame frame : settingsFrames) {
|
||||
if (frame.getModule() == module) {
|
||||
frame.setX(x);
|
||||
frame.setY(y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// asegurarse de que no se sale de la pantalla
|
||||
x = Math.clamp(x, 0, mc.getWindow().getScaledWidth() - 80);
|
||||
y = Math.clamp(y, 0, mc.getWindow().getScaledHeight() - 120);
|
||||
|
||||
SettingsFrame frame = new SettingsFrame(module, x, y, 100, 20);
|
||||
settingsFrames.add(frame);
|
||||
@@ -289,8 +296,8 @@ public class ClickGUI extends Screen {
|
||||
|
||||
// verificar si un módulo tiene su marco de ajustes abierto
|
||||
public boolean isSettingsFrameOpen(Module module) {
|
||||
return settingsFrames.stream()
|
||||
.anyMatch(sf -> sf.getModule().getName().equals(module.getName()));
|
||||
return settingsFrames.stream().anyMatch(
|
||||
sf -> sf.getModule().equals(module));
|
||||
}
|
||||
|
||||
public boolean isColorPickerFrameOpen(ColorSetting setting) {
|
||||
|
||||
@@ -43,7 +43,7 @@ public class ModuleButton extends Button {
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int mouseX, int mouseY, int button) {
|
||||
if (isHovered((int) mouseX, (int) mouseY) && ClickGUI.INSTANCE.trySelect(this)) {
|
||||
if (isHovered(mouseX, mouseY) && ClickGUI.INSTANCE.trySelect(this)) {
|
||||
if (button == 0) { // clic izquierdo para activar / desactivar el módulo
|
||||
module.toggle();
|
||||
} else if (button == 1) { // clic derecho para el marco de ajustes (también lo cierra si está abierto)
|
||||
@@ -56,12 +56,6 @@ public class ModuleButton extends Button {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(int mouseX, int mouseY) {}
|
||||
|
||||
@Override
|
||||
public void onKey(int key, int action) {}
|
||||
|
||||
// verifica si el puntero del ratón se encuentra sobre el botón del módulo
|
||||
@Override
|
||||
public boolean isHovered(int mouseX, int mouseY) {
|
||||
|
||||
@@ -81,7 +81,7 @@ public class ChooseButton<T> extends SettingButton<OptionSetting<T>> {
|
||||
String displayName = setting.getDisplayName(option);
|
||||
BooleanSetting b = new BooleanSetting(
|
||||
displayName,
|
||||
"incluir " + displayName,
|
||||
"seleccionar " + displayName,
|
||||
setting.is(option)
|
||||
);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import me.retucio.sputnik.module.setting.settings.ListSetting;
|
||||
import me.retucio.sputnik.ui.widgets.buttons.SettingButton;
|
||||
import me.retucio.sputnik.ui.screen.ClickGUI;
|
||||
import me.retucio.sputnik.ui.widgets.frames.SettingsFrame;
|
||||
import me.retucio.sputnik.util.ChatUtil;
|
||||
import me.retucio.sputnik.util.Colors;
|
||||
import me.retucio.sputnik.util.KeyUtil;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
|
||||
@@ -5,6 +5,11 @@ import net.minecraft.client.input.KeyInput;
|
||||
import net.minecraft.client.option.KeyBinding;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.im.InputContext;
|
||||
import java.util.Locale;
|
||||
|
||||
import static me.retucio.sputnik.Sputnik.mc;
|
||||
|
||||
// cosas útiles relacionadas a las teclas
|
||||
@@ -28,6 +33,11 @@ public class KeyUtil {
|
||||
|| isKeyDown(GLFW.GLFW_KEY_RIGHT_SHIFT);
|
||||
}
|
||||
|
||||
|
||||
public static boolean isCapsLockOn() throws HeadlessException {
|
||||
return Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK);
|
||||
}
|
||||
|
||||
public static void pressKey(int key, int action) {
|
||||
pressKey(key, action, 0, 0);
|
||||
}
|
||||
@@ -36,7 +46,12 @@ public class KeyUtil {
|
||||
mc.keyboard.onKey(
|
||||
mc.getWindow().getHandle(),
|
||||
action,
|
||||
new KeyInput(key, scancode, modifiers));
|
||||
new KeyInput(
|
||||
key,
|
||||
scancode,
|
||||
modifiers
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static String getKeyName(int key) {
|
||||
@@ -72,31 +87,93 @@ public class KeyUtil {
|
||||
};
|
||||
}
|
||||
|
||||
// quizás debería de añadir layouts...
|
||||
|
||||
public static String shiftKey(String c) {
|
||||
return switch (c) {
|
||||
case "`" -> "~";
|
||||
case "1" -> "!";
|
||||
case "2" -> "@";
|
||||
case "3" -> "#";
|
||||
case "4" -> "$";
|
||||
case "5" -> "%";
|
||||
case "6" -> "^";
|
||||
case "7" -> "&";
|
||||
case "8" -> "*";
|
||||
case "9" -> "(";
|
||||
case "0" -> ")";
|
||||
case "-" -> "_";
|
||||
case "=" -> "+";
|
||||
case "[" -> "{";
|
||||
case "]" -> "}";
|
||||
case "\\" -> "|";
|
||||
case ";" -> ":";
|
||||
case "'" -> "\"";
|
||||
case "," -> "<";
|
||||
case "." -> ">";
|
||||
case "/" -> "?";
|
||||
default -> c.toUpperCase();
|
||||
};
|
||||
return shiftKey(c, getLayout());
|
||||
}
|
||||
|
||||
public static String shiftKey(String c, KeyboardLayout layout) {
|
||||
String uppercase = isCapsLockOn() ? c.toLowerCase() : c.toUpperCase();
|
||||
|
||||
switch (layout) {
|
||||
case EN_US -> {
|
||||
return switch (c) {
|
||||
case "`" -> "~";
|
||||
case "1" -> "!";
|
||||
case "2" -> "@";
|
||||
case "3" -> "#";
|
||||
case "4" -> "$";
|
||||
case "5" -> "%";
|
||||
case "6" -> "^";
|
||||
case "7" -> "&";
|
||||
case "8" -> "*";
|
||||
case "9" -> "(";
|
||||
case "0" -> ")";
|
||||
case "-" -> "_";
|
||||
case "=" -> "+";
|
||||
case "[" -> "{";
|
||||
case "]" -> "}";
|
||||
case "\\" -> "|";
|
||||
case ";" -> ":";
|
||||
case "'" -> "\"";
|
||||
case "," -> "<";
|
||||
case "." -> ">";
|
||||
case "/" -> "?";
|
||||
default -> uppercase;
|
||||
};
|
||||
}
|
||||
|
||||
case ES_ES -> {
|
||||
return switch (c) {
|
||||
case "º" -> "ª";
|
||||
case "1" -> "!";
|
||||
case "2" -> "\"";
|
||||
case "3" -> "·";
|
||||
case "4" -> "$";
|
||||
case "5" -> "%";
|
||||
case "6" -> "&";
|
||||
case "7" -> "/";
|
||||
case "8" -> "(";
|
||||
case "9" -> ")";
|
||||
case "0" -> "=";
|
||||
case "'" -> "?";
|
||||
case "¡" -> "¿";
|
||||
case "`" -> "^";
|
||||
case "+" -> "*";
|
||||
case "´" -> "¨";
|
||||
case "," -> ";";
|
||||
case "." -> ":";
|
||||
case "-" -> "_";
|
||||
case "<" -> ">";
|
||||
default -> uppercase;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return uppercase;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static KeyboardLayout getLayout() {
|
||||
Locale locale = InputContext.getInstance().getLocale();
|
||||
if (locale == null) locale = Locale.getDefault();
|
||||
|
||||
String country = locale.getCountry();
|
||||
String lang = locale.getLanguage();
|
||||
|
||||
if (country.equals("US") && lang.equals("en")) {
|
||||
return KeyboardLayout.EN_US;
|
||||
} else if (country.equals("ES") && lang.equals("es")) {
|
||||
return KeyboardLayout.ES_ES;
|
||||
}
|
||||
|
||||
// fallback
|
||||
return KeyboardLayout.EN_US;
|
||||
}
|
||||
|
||||
public enum KeyboardLayout {
|
||||
EN_US,
|
||||
ES_ES;
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ public class Lists {
|
||||
public static Map<ScreenHandlerType<?>, String> screenNames;
|
||||
|
||||
public static final List<Color> colorList = new ArrayList<>();
|
||||
public static final List<String> fontList = new ArrayList<>();
|
||||
|
||||
// intentar traducir nombres y fallar miserablemente
|
||||
public static void init() {
|
||||
@@ -68,7 +69,16 @@ public class Lists {
|
||||
).toList());
|
||||
|
||||
colorList.addAll(Arrays.asList(
|
||||
RED, ORANGE, YELLOW, LIME, GREEN, CYAN, CELESTE, BLUE, PURPLE, MAGENTA, PINK, LAVENDER, WHITE, SILVER, GRAY, BLACK, BROWN));
|
||||
RED, ORANGE, YELLOW, LIME, GREEN, CYAN,
|
||||
CELESTE, BLUE, PURPLE, MAGENTA, PINK,
|
||||
LAVENDER, WHITE, SILVER, GRAY, BLACK, BROWN
|
||||
));
|
||||
|
||||
fontList.addAll(List.of(
|
||||
"bahnschrift", "calibri", "cantarell", "comic-sans-ms",
|
||||
"deja-vu-sans-mono", "new-times-roman", "roboto", "segoe-ui",
|
||||
"ubuntu"
|
||||
));
|
||||
}
|
||||
|
||||
public static <T> Map<T, Boolean> allTrue(List<T> options) {
|
||||
|
||||
@@ -14,6 +14,8 @@ public class Layers {
|
||||
private static final RenderLayer QUADS;
|
||||
private static final RenderLayer QUADS_CULL;
|
||||
|
||||
private static final RenderLayer TEXT;
|
||||
|
||||
|
||||
public static RenderLayer lines() {
|
||||
return LINES;
|
||||
@@ -31,12 +33,18 @@ public class Layers {
|
||||
return QUADS_CULL;
|
||||
}
|
||||
|
||||
public static RenderLayer text() {
|
||||
return TEXT;
|
||||
}
|
||||
|
||||
static {
|
||||
LINES = RenderLayer.of(Sputnik.MOD_ID + "_lines", RenderSetup.builder(LINES_PIPELINE).build());
|
||||
LINES_CULL = RenderLayer.of(Sputnik.MOD_ID + "_lines_cull", RenderSetup.builder(LINES_CULL_PIPELINE).build());
|
||||
|
||||
QUADS = RenderLayer.of(Sputnik.MOD_ID + "_quads", RenderSetup.builder(QUADS_PIPELINE).build());
|
||||
QUADS_CULL = RenderLayer.of(Sputnik.MOD_ID + "quads_cull", RenderSetup.builder(QUADS_CULL_PIPELINE).build());
|
||||
QUADS_CULL = RenderLayer.of(Sputnik.MOD_ID + "_quads_cull", RenderSetup.builder(QUADS_CULL_PIPELINE).build());
|
||||
|
||||
TEXT = RenderLayer.of(Sputnik.MOD_ID + "_text", RenderSetup.builder(TEXT_PIPELINE).build());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,12 +6,18 @@ import com.mojang.blaze3d.platform.DepthTestFunction;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import me.retucio.sputnik.Sputnik;
|
||||
import net.minecraft.client.gl.RenderPipelines;
|
||||
import net.minecraft.client.gl.UniformType;
|
||||
import net.minecraft.client.render.VertexFormats;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
|
||||
public class Pipelines {
|
||||
|
||||
static final RenderPipeline.Snippet MESH_UNIFORMS = RenderPipeline.builder()
|
||||
.withUniform("MeshData",UniformType.UNIFORM_BUFFER)
|
||||
.buildSnippet();
|
||||
|
||||
|
||||
static final RenderPipeline LINES_PIPELINE = RenderPipeline.builder(RenderPipelines.RENDERTYPE_LINES_SNIPPET)
|
||||
.withLocation(Identifier.of(Sputnik.MOD_ID, "pipeline/lines"))
|
||||
.withVertexFormat(VertexFormats.POSITION_COLOR_NORMAL_LINE_WIDTH, VertexFormat.DrawMode.LINES)
|
||||
@@ -45,4 +51,16 @@ public class Pipelines {
|
||||
.withDepthWrite(false)
|
||||
.withCull(false)
|
||||
.build();
|
||||
|
||||
public static final RenderPipeline TEXT_PIPELINE = RenderPipeline.builder(RenderPipelines.POSITION_TEX_COLOR_SNIPPET)
|
||||
.withLocation(Identifier.of(Sputnik.MOD_ID, "pipeline/text"))
|
||||
.withVertexFormat(VertexFormats.POSITION_TEXTURE_COLOR, VertexFormat.DrawMode.TRIANGLES)
|
||||
.withVertexShader(Identifier.of(Sputnik.MOD_ID, "shaders/text.vert"))
|
||||
.withFragmentShader(Identifier.of(Sputnik.MOD_ID,"shaders/text.frag"))
|
||||
.withSampler("u_Texture")
|
||||
.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST)
|
||||
.withDepthWrite(false)
|
||||
.withBlend(BlendFunction.TRANSLUCENT)
|
||||
.withCull(false)
|
||||
.build();
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package me.retucio.sputnik.util.render;
|
||||
|
||||
import com.mojang.blaze3d.platform.TextureUtil;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.textures.AddressMode;
|
||||
import com.mojang.blaze3d.textures.FilterMode;
|
||||
import com.mojang.blaze3d.textures.TextureFormat;
|
||||
import net.minecraft.client.texture.AbstractTexture;
|
||||
import net.minecraft.client.texture.NativeImage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.stb.STBImage;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
public class Texture extends AbstractTexture {
|
||||
public Texture(int width, int height, TextureFormat format, FilterMode min, FilterMode mag) {
|
||||
glTexture = RenderSystem.getDevice().createTexture("", 15, format, width, height, 1, 1);
|
||||
sampler = RenderSystem.getSamplerCache().get(AddressMode.REPEAT, AddressMode.REPEAT, min, mag, false);
|
||||
|
||||
glTextureView = RenderSystem.getDevice().createTextureView(glTexture);
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return getGlTexture().getWidth(0);
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return getGlTexture().getHeight(0);
|
||||
}
|
||||
|
||||
public void upload(byte[] bytes) {
|
||||
upload(BufferUtils.createByteBuffer(bytes.length).put(bytes));
|
||||
}
|
||||
|
||||
public void upload(ByteBuffer buffer) {
|
||||
NativeImage image = getImage();
|
||||
|
||||
buffer.rewind();
|
||||
MemoryUtil.memCopy(MemoryUtil.memAddress(buffer), image.imageId(), buffer.remaining());
|
||||
|
||||
RenderSystem.getDevice().createCommandEncoder().writeToTexture(glTexture, image);
|
||||
|
||||
image.close();
|
||||
}
|
||||
|
||||
private @NotNull NativeImage getImage() {
|
||||
NativeImage.Format imageFormat = switch (glTexture.getFormat()) {
|
||||
case RGBA8 -> NativeImage.Format.RGBA;
|
||||
case RED8 -> NativeImage.Format.LUMINANCE;
|
||||
default -> throw new IllegalArgumentException();
|
||||
};
|
||||
|
||||
// Workaround for writeToTexture(IntBuffer) overload comparing width * height to the size of the int buffer.
|
||||
// And since we are working with pixels which are only one byte in size, the sizes don't match
|
||||
return new NativeImage(imageFormat, getWidth(), getHeight(), false);
|
||||
}
|
||||
|
||||
public static Texture readResource(String path, boolean flipY, FilterMode filter) {
|
||||
try (var in = Texture.class.getResourceAsStream(path)) {
|
||||
if (in == null) return null;
|
||||
|
||||
var data = TextureUtil.readResource(in).rewind();
|
||||
|
||||
try (MemoryStack stack = MemoryStack.stackPush()) {
|
||||
IntBuffer width = stack.mallocInt(1);
|
||||
IntBuffer height = stack.mallocInt(1);
|
||||
IntBuffer comp = stack.mallocInt(1);
|
||||
|
||||
STBImage.stbi_set_flip_vertically_on_load(flipY);
|
||||
ByteBuffer image = STBImage.stbi_load_from_memory(data, width, height, comp, 4);
|
||||
|
||||
var texture = new Texture(width.get(0), height.get(0), TextureFormat.RGBA8, filter, filter);
|
||||
texture.upload(image);
|
||||
|
||||
STBImage.stbi_image_free(image);
|
||||
STBImage.stbi_set_flip_vertically_on_load(false);
|
||||
|
||||
return texture;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"providers": [
|
||||
{
|
||||
"type": "ttf",
|
||||
"file": "sputnik:bahnschrift.ttf",
|
||||
"size": 10.0,
|
||||
"oversample": 2.0,
|
||||
"shift": [0.0, 0.0],
|
||||
"range": "0x0000-0x00FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"providers": [
|
||||
{
|
||||
"type": "ttf",
|
||||
"file": "sputnik:calibri.ttf",
|
||||
"size": 10.0,
|
||||
"oversample": 2.0,
|
||||
"shift": [0.0, 0.0],
|
||||
"range": "0x0000-0x00FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"providers": [
|
||||
{
|
||||
"type": "ttf",
|
||||
"file": "sputnik:cantarell.ttf",
|
||||
"size": 10.0,
|
||||
"oversample": 2.0,
|
||||
"shift": [0.0, 0.0],
|
||||
"range": "0x0000-0x00FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"providers": [
|
||||
{
|
||||
"type": "ttf",
|
||||
"file": "sputnik:comic-sans-ms.ttf",
|
||||
"size": 10.0,
|
||||
"oversample": 2.0,
|
||||
"shift": [0.0, 0.0],
|
||||
"range": "0x0000-0x00FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"providers": [
|
||||
{
|
||||
"type": "ttf",
|
||||
"file": "sputnik:deja-vu-sans-mono.ttf",
|
||||
"size": 10.0,
|
||||
"oversample": 2.0,
|
||||
"shift": [0.0, 0.0],
|
||||
"range": "0x0000-0x00FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"providers": [
|
||||
{
|
||||
"type": "ttf",
|
||||
"file": "sputnik:new-times-roman.ttf",
|
||||
"size": 10.0,
|
||||
"oversample": 2.0,
|
||||
"shift": [0.0, 0.0],
|
||||
"range": "0x0000-0x00FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"providers": [
|
||||
{
|
||||
"type": "ttf",
|
||||
"file": "sputnik:roboto.ttf",
|
||||
"size": 10.0,
|
||||
"oversample": 2.0,
|
||||
"shift": [0.0, 0.0],
|
||||
"range": "0x0000-0x00FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"providers": [
|
||||
{
|
||||
"type": "ttf",
|
||||
"file": "sputnik:segoe-ui.ttf",
|
||||
"size": 10.0,
|
||||
"oversample": 2.0,
|
||||
"shift": [0.0, 0.0],
|
||||
"range": "0x0000-0x00FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"providers": [
|
||||
{
|
||||
"type": "ttf",
|
||||
"file": "sputnik:ubuntu.ttf",
|
||||
"size": 10.0,
|
||||
"oversample": 2.0,
|
||||
"shift": [0.0, 0.0],
|
||||
"range": "0x0000-0x00FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
#version 150
|
||||
in vec2 vTexCoord;
|
||||
in vec4 vColor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform sampler2D u_Texture;
|
||||
|
||||
void main() {
|
||||
float distance = texture(u_Texture, vTexCoord).r;
|
||||
float alpha = smoothstep(0.4, 0.6, distance);
|
||||
|
||||
fragColor = vec4(vColor.rgb, vColor.a * alpha);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#version 150
|
||||
in vec3 aPos;
|
||||
in vec2 aTexCoord;
|
||||
in vec4 aColor;
|
||||
|
||||
out vec2 vTexCoord;
|
||||
out vec4 vColor;
|
||||
|
||||
uniform mat4 u_ProjectionMatrix;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_ProjectionMatrix * vec4(aPos, 1.0);
|
||||
vTexCoord = aTexCoord;
|
||||
vColor = aColor;
|
||||
}
|
||||
@@ -52,6 +52,7 @@
|
||||
"EmitterParticleMixin",
|
||||
"EquipmentRendererMixin",
|
||||
"FogRendererMixin",
|
||||
"FontManagerMixin",
|
||||
"GameOptionsMixin",
|
||||
"GameRendererMixin",
|
||||
"HeldItemRendererMixin",
|
||||
|
||||
Reference in new issue
Block a user