chore(history): squash 100 commit(s) from 2026-09-24
- fix(backend): case-insensitive unique email, revoke PUBLIC schema access, pin Argon2id params - test(backend): assert password length cap boundary (256 ok, 257 rejected) - docs(backend): plan — typed JWT token kinds so refresh/device tokens cannot pass as access tokens - feat(backend): JWT access/refresh token issue and verify - feat(backend): accounts repository (create/find_by_email/find_by_id) - refactor(gui): LoVisualAddonManagerScreen 989→10 файлов addon/ (8.5.2) - docs(backend): plan — fix sqlx::migrate! path in integration tests - feat(backend): POST /auth/register and /auth/login - refactor(settings): SettingsPanelComponent 715→81 + 6 helpers (8.5.2) - docs(backend): plan — harden device flow (single-use codes, bounded store, 404/429) - feat(backend): OAuth device authorization grant for mod login - fix(backend): first confirm wins for device codes - docs(backend): plan — split Task 8 (refactor) and Task 9 (avatars), harden avatar handling - refactor(mixins): LocalPlayerMixin 691→111 + 4 handlers (8.5.2) - refactor(visuals): Trails 687→130 (8.5.2) - refactor(render): ItemBatchRenderer 677->100 (8.5.2) - refactor(visuals): ReimaginedVisual 674→118 + 5 helpers (8.5.2) - refactor(config): ConfigSerializer 668→91 + 4 helpers (8.5.2) - refactor(hud): DynamicIsland 661→158 + 4 helpers (8.5.2) - refactor(render): GlStencilFramebufferSupport 666→169 (8.5.2) - refactor(gui): MenuScreen 669→128 + 4 helpers (8.5.2) - refactor(render): UiStyle 644→170 + 3 helpers (8.5.2) - refactor(gui): ModuleComponent 613→98 + 4 helpers (8.5.2) - refactor(media): MediaSessionService 616→200 + 4 helpers (8.5.2) - refactor(gui): RelationsComponent 661→59 + 4 helpers (8.5.2) - chore(license): strip GPL file headers from all Java sources - refactor(aiming): PointTracker 583→168 + 2 helpers (8.5.2) - refactor(gui): LoVisualProxyManagerScreen 591→132 + 2 helpers (8.5.2) - refactor(visuals): KillEffect 588→96 + 4 helpers (8.5.2) - refactor(render): MeshBuilder +4 helpers (8.5.2) - refactor(visuals): extract WorldParticlesRender helper (8.5.2) - refactor(world): ExplosionDamageUtil 551→116 + 2 helpers (8.5.2) - refactor(visuals): TazikHat 596->179 + Model + Palette in hats/tazik (8.5.2) - chore(license): strip GPL header from remaining 30 files and make strip script variant-aware - refactor(gui): ThemeComponent 561->166 + CardRenderer + ScrollState (8.5.2) - refactor(hud): CustomHotbar 556→178 + Renderer + Selection + SelectionGradient (8.5.2) - refactor(gui): ThemeCardRenderer perf + readability polish - refactor(clickgui): CooldownRulesSetting 596->198 + Editor + DetailRenderer (8.5.2) - refactor(hud): HudNotifier 561->200 + Painter + runtime/HudNotifierRuntime (8.5.2) - refactor(theme): Themes 555->168 + impl/Transition + impl/Blending + impl/ProfileCodec (8.5.2) - refactor(theme): EditableClickGuiTheme 205->185 + JavaDoc (8.5.2) - refactor(theme): ThemeStore 491->128 + store/ThemeStoreJson + store/ThemeStoreIO (8.5.2) - refactor(clickgui): ClickGuiRenderer 604->200 compacted one-line delegators + JavaDoc (8.5.2) - refactor(mainmenu): LoVisualMainMenuScreen 551->161 + impl/Painter + impl/Renderer + impl/TextUtil (8.5.2) - refactor(clickgui): ClickGuiTextEditorState 531->187 + impl/EditorCaret + impl/EditorPainter (8.5.2) - refactor(tab): TabListModel 525->139 + model/Collector + model/Reader + model/Signature + model/TextSplitter (8.5.2) - refactor(backend): shared bearer helper and test helpers, build_app takes Config, validate JWT secret strength - refactor(module): ModuleManager 521->198 + impl/Registrar + impl/Dispatcher (8.5.2) - feat(backend): avatar upload with decode, square crop, PNG re-encode and S3 storage - refactor(clip): ClipFunction 512->146 + impl/Geometry + impl/Debug (8.5.2) - docs(backend): implementation plans for gateway (auth hardening, gRPC, rate limits) and configs-service - refactor(iris-patch): ShaderPatchEngine 499->146 + impl/Repo (8.5.2) - chore(frontend): add router, react-query, fonts and vitest; dev proxy to gateway - refactor(hud): ScriptedListHudPanel 499->158 + panel/Props + panel/Signature (8.5.2) - refactor(hud): BaseHudElement 499->199 + impl/Registry + impl/Namer + impl/Prewarm (8.5.2) - refactor(clickgui): Setting 498->170 + impl/Localization + impl/I18n (8.5.2) - refact(viewmodel): split swing animations into camera/swing package - refact(kineticlyrics): split module into stage, playback and modes - rename(holeesp): module HoleESP -> CrystalHoles - refact(crystalholes): split module into crystal scanner, renderer and safety - refact(addonmanager): split manager into lifecycle, runtime, descriptors and profiles - refact(accountconfig): split config into store, session and value helpers - refactor(render): CustomTextRenderer 229->195, extract glyph-pass into GradientTexts helper - docs(TODO): mark AddonManager split done; close 9.2 refactor gate - refactor(media): LinuxMediaSession 441->148, split reader + track/seek state - refactor(nametags): split NameTags into facade + impl helpers - refactor(clickgui): split MainSettingsComponent into facade + scroll + model - refactor(hud): split CustomBar into facade, model and BarSettings - docs(frontend): implementation plan with design system from the mod theme - feat(frontend): design tokens from the mod theme, fonts and shared UI kit - fix(accounts): run migrations on startup, offload Argon2, validate register input, JSON error shape - docs(gateway): plan note on splitting auth handlers before refresh endpoints - feat(frontend): API client with silent refresh, error descriptions and test helpers - style(mod): group compact one-line bulk query methods in ModuleManager - feat(frontend): session restore, login and registration with client-side validation - refactor(hud): split CustomHealthBar into facade + painter + script renderer - docs(mod): record the 2026-09-24 HUD/settings split wave in TODO phase 8.5 - refactor(rhi): split GlStencilShapeClipBackend into facade + native-state + pass-lifecycle helpers - refactor(rhi): split VulkanRenderStateBridge into facade + MSAA and stencil state helpers - refactor(backtrack): split BacktrackController into facade + model + impl helpers - refactor(svg): split SvgPathParser into facade + arc geometry + command/curve helpers - refactor(mixin): split ClientPacketListenerMixin into hook-only mixin + handlers - refactor(renderer3d): un-nest batch bindings + culling into sibling impl types - refactor(renderwarp): extract static factories + geometry into impl helpers - feat(backend): add common crate with shared JWT, internal gateway contract and accounts proto - refactor(guimixin): move hook bodies into handlers, keep mixin as hooks + shadows - feat(accounts): accept only gateway traffic, read identity from gateway header - refactor(cacheduiscriptruntime): extract engine, hashing and frame stats into impl - refactor(customskyboxrenderer): extract projection, shader passes and sun into impl - refactor(betterchatstoremanager): extract persistence, key/path and hover helpers into impl - feat(accounts): rotating opaque refresh tokens in httpOnly cookie, /auth/refresh and /auth/logout - refactor(targetesp): extract crystal rendering subsystem into impl/TargetEspCrystalRenderer - refactor(betterchathovercache): extract disk codec and lookup indexing into impl/ChatHoverCacheCodec - refactor(microsoftauth): split HTTP transport, device-code and Xbox flows into impl/ - refactor(pvpcooldowns): extract local item-rule engine and defaults into impl/PvpCooldownRules - refactor(lovisual): extract HUD/world render orchestration into HudRender helper - refactor(statuseffectheuristics): extract palette/inference into ParticlePalette and color utils into ParticleColors - refactor(dropesp): extract overlay/label render subsystem into impl/DropEspOverlayRenderer - refactor(proxy): extract SOCKS handshake message builders into ProxyProtocolMessages - refactor(eagleutil): promote EdgeRecovery controller and RecoveryMode to top-level class
This commit is contained in:
parent
9d08fa910a
commit
72bc4c7148
1897 changed files with 36199 additions and 39289 deletions
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util;
|
||||
|
||||
import lombok.Getter;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util;
|
||||
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming;
|
||||
import dev.loki.lovisual.util.aiming.rotation.RotationUtil;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming;
|
||||
|
||||
import dev.loki.lovisual.features.module.core.Module;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming;
|
||||
|
||||
public final class RestrictedSingleUseAction {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.data;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.data;
|
||||
|
||||
public record RotationDelta(float deltaYaw, float deltaPitch) {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.data;
|
||||
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features;
|
||||
|
||||
import dev.loki.lovisual.config.values.mode.EnumValue;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors;
|
||||
import dev.loki.lovisual.util.aiming.features.processors.RotationProcessor;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors;
|
||||
|
||||
import dev.loki.lovisual.util.aiming.rotation.RotationTarget;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.anglesmooth;
|
||||
|
||||
import dev.loki.lovisual.util.aiming.rotation.RotationTarget;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.anglesmooth;
|
||||
|
||||
import dev.loki.lovisual.util.aiming.rotation.RotationTarget;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.anglesmooth;
|
||||
|
||||
import dev.loki.lovisual.util.aiming.rotation.RotationTarget;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl;
|
||||
|
||||
import dev.loki.lovisual.config.values.primitive.BooleanValue;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl;
|
||||
|
||||
import dev.loki.lovisual.config.values.primitive.NumberValue;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl;
|
||||
|
||||
import dev.loki.lovisual.config.values.primitive.NumberValue;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl.curves;
|
||||
|
||||
import dev.loki.lovisual.config.values.primitive.NumberValue;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl.curves;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.anglesmooth.impl.curves;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.impl;
|
||||
import dev.loki.lovisual.util.aiming.features.processors.RotationProcessor;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.impl;
|
||||
import dev.loki.lovisual.util.aiming.features.processors.RotationProcessor;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.impl;
|
||||
import dev.loki.lovisual.util.aiming.features.processors.RotationProcessor;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.features.processors.impl;
|
||||
import dev.loki.lovisual.util.aiming.features.processors.RotationProcessor;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,193 @@
|
|||
package dev.loki.lovisual.util.aiming.point;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import dev.loki.lovisual.util.aiming.data.Rotation;
|
||||
import dev.loki.lovisual.util.raycast.RaycastUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* Pure geometry, scoring and small random helpers shared by {@link PointTracker}
|
||||
* and {@link PointProcessor}. Package-private: not part of the public aiming API.
|
||||
*/
|
||||
final class PointGeometry {
|
||||
private PointGeometry() {}
|
||||
/** Composite cost used by {@link PointTracker#findPoint} to rank candidate aim points. */
|
||||
static float scoreCandidate(Vec3 eyes, Rotation initialRotation, Rotation candidateRotation,
|
||||
Vec3 point, Vec3 center, AABB box, Vec3 aimDir,
|
||||
Vec3 movement, double movementStrength) {
|
||||
float rotationScore = initialRotation.angleTo(candidateRotation) * 1.15f;
|
||||
double halfX = Math.max(1.0E-4, box.getXsize() * 0.5);
|
||||
double halfY = Math.max(1.0E-4, box.getYsize() * 0.5);
|
||||
double halfZ = Math.max(1.0E-4, box.getZsize() * 0.5);
|
||||
double nx = Math.abs(point.x - center.x) / halfX;
|
||||
double ny = Math.abs(point.y - center.y) / halfY;
|
||||
double nz = Math.abs(point.z - center.z) / halfZ;
|
||||
double edgeFactor = Math.max(Math.max(nx, nz), ny * 0.65);
|
||||
double centerPenalty = (1.0 - Mth.clamp(edgeFactor, 0.0, 1.0)) * (movementStrength > 0.035 ? 6.0 : 4.0);
|
||||
double rayDistance = distanceToRay(eyes, aimDir, point);
|
||||
double rayScale = Math.max(0.08, Math.max(box.getXsize(), Math.max(box.getYsize(), box.getZsize())) * 0.5);
|
||||
double rayScore = (rayDistance / rayScale) * (movementStrength > 0.035 ? 5.5 : 4.0);
|
||||
double movementBenefit = movingPointBenefit(point, center, box, movement, movementStrength);
|
||||
return rotationScore + (float) rayScore + (float) centerPenalty - (float) movementBenefit;
|
||||
}
|
||||
/** Drops candidates that sit too close to {@code reference}, encouraging aim diversity. */
|
||||
static List<Candidate> filterDiverse(List<Candidate> candidates, Vec3 reference, AABB box, boolean movingTarget) {
|
||||
List<Candidate> out = new ArrayList<>();
|
||||
if (reference == null) return out;
|
||||
double minAxis = Math.min(box.getXsize(), Math.min(box.getYsize(), box.getZsize()));
|
||||
double minDistance = Math.max(movingTarget ? 0.085 : 0.055, minAxis * (movingTarget ? 0.26 : 0.18));
|
||||
double minDistanceSq = minDistance * minDistance;
|
||||
for (Candidate candidate : candidates) {
|
||||
if (candidate.point().distanceToSqr(reference) >= minDistanceSq) out.add(candidate);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
/** Softmax-like weighted pick among close-scoring candidates to avoid deterministic aim. */
|
||||
static Candidate selectWeighted(List<Candidate> candidates, float bestScore) {
|
||||
if (candidates.size() == 1) return candidates.get(0);
|
||||
double total = 0.0;
|
||||
double[] weights = new double[candidates.size()];
|
||||
for (int i = 0; i < candidates.size(); i++) {
|
||||
double delta = Math.max(0.0, candidates.get(i).score() - bestScore);
|
||||
double weight = 1.0 / (1.0 + delta * delta * 0.08);
|
||||
weights[i] = weight;
|
||||
total += weight;
|
||||
}
|
||||
double pick = ThreadLocalRandom.current().nextDouble(total);
|
||||
for (int i = 0; i < candidates.size(); i++) {
|
||||
pick -= weights[i];
|
||||
if (pick <= 0.0) return candidates.get(i);
|
||||
}
|
||||
return candidates.get(candidates.size() - 1);
|
||||
}
|
||||
/** Bonus for leading a moving target: reward points on the forward / lateral sides of the box. */
|
||||
static double movingPointBenefit(Vec3 point, Vec3 center, AABB box, Vec3 movement, double movementStrength) {
|
||||
if (movementStrength <= 0.035) return 0.0;
|
||||
double halfX = Math.max(1.0E-4, box.getXsize() * 0.5);
|
||||
double halfZ = Math.max(1.0E-4, box.getZsize() * 0.5);
|
||||
double dirX = movement.x / movementStrength;
|
||||
double dirZ = movement.z / movementStrength;
|
||||
double offX = Mth.clamp((point.x - center.x) / halfX, -1.0, 1.0);
|
||||
double offZ = Mth.clamp((point.z - center.z) / halfZ, -1.0, 1.0);
|
||||
double lead = Mth.clamp(offX * dirX + offZ * dirZ, -1.0, 1.0);
|
||||
double sideStrength = Math.min(1.0, Math.hypot(offX, offZ));
|
||||
return Math.max(0.0, lead) * 4.0 + sideStrength * 1.4;
|
||||
}
|
||||
static double distanceToRay(Vec3 origin, Vec3 direction, Vec3 point) {
|
||||
Vec3 diff = point.subtract(origin);
|
||||
double t = Math.max(0.0, diff.dot(direction));
|
||||
return point.distanceTo(origin.add(direction.scale(t)));
|
||||
}
|
||||
/** Intersection of the aim ray with the target box, or {@code null} if the ray misses within {@code maxDistance}. */
|
||||
static Vec3 findRayHitPoint(Vec3 eyes, Vec3 aimDir, AABB box, double maxDistance) {
|
||||
double range = maxDistance > 0.0 && maxDistance < Double.MAX_VALUE ? maxDistance : 6.0;
|
||||
return box.clip(eyes, eyes.add(aimDir.scale(range))).orElse(null);
|
||||
}
|
||||
static double horizontalLength(Vec3 vec) {
|
||||
return vec == null ? 0.0 : Math.hypot(vec.x, vec.z);
|
||||
}
|
||||
static boolean isValidPoint(Vec3 startPoint, Vec3 endPoint, double maxDistance, boolean ignoreWalls) {
|
||||
if (startPoint == null || endPoint == null) return false;
|
||||
if (maxDistance > 0.0 && startPoint.distanceToSqr(endPoint) > maxDistance * maxDistance) return false;
|
||||
return ignoreWalls || RaycastUtil.hasLineOfSightPoint(startPoint, endPoint);
|
||||
}
|
||||
/** Sample a directional offset biased along the entity's motion (or perpendicular to aim when stationary). */
|
||||
static Vec3 randomInstabilityOffset(AABB box, Vec3 entityVelocity, Vec3 aimDirection, double intensity) {
|
||||
double halfX = Math.max(0.001, box.getXsize() * 0.5);
|
||||
double halfY = Math.max(0.001, box.getYsize() * 0.5);
|
||||
double halfZ = Math.max(0.001, box.getZsize() * 0.5);
|
||||
double speed = horizontalLength(entityVelocity);
|
||||
double sideX, sideZ;
|
||||
if (speed > 0.035) {
|
||||
sideX = entityVelocity.x / speed;
|
||||
sideZ = entityVelocity.z / speed;
|
||||
} else {
|
||||
Vec3 horizontalAim = new Vec3(aimDirection.x, 0.0, aimDirection.z);
|
||||
double aimLen = Math.max(1.0E-4, horizontalLength(horizontalAim));
|
||||
sideX = -horizontalAim.z / aimLen;
|
||||
sideZ = horizontalAim.x / aimLen;
|
||||
}
|
||||
double lateral = randomDouble(-1.0, 1.0) * (0.14 + 0.22 * intensity);
|
||||
double lead = speed > 0.035 ? randomDouble(0.05, 0.24) * intensity : 0.0;
|
||||
double vertical = randomDouble(-0.16, 0.14) * intensity;
|
||||
return new Vec3(
|
||||
sideX * halfX * lateral + sideX * halfX * lead,
|
||||
halfY * vertical,
|
||||
sideZ * halfZ * lateral + sideZ * halfZ * lead
|
||||
);
|
||||
}
|
||||
static Vec3 clampToBox(Vec3 point, AABB box) {
|
||||
return new Vec3(
|
||||
Mth.clamp(point.x, box.minX, box.maxX),
|
||||
Mth.clamp(point.y, box.minY, box.maxY),
|
||||
Mth.clamp(point.z, box.minZ, box.maxZ)
|
||||
);
|
||||
}
|
||||
static Vec3 getNearestPoint(AABB box, Vec3 eyes) {
|
||||
return new Vec3(
|
||||
Mth.clamp(eyes.x, box.minX, box.maxX),
|
||||
Mth.clamp(eyes.y, box.minY, box.maxY),
|
||||
Mth.clamp(eyes.z, box.minZ, box.maxZ)
|
||||
);
|
||||
}
|
||||
/** Sample a grid of surface (or interior, when eyes are inside) points on the target's bounding box. */
|
||||
static List<Vec3> projectPointsOnBox(Vec3 eyes, AABB box) {
|
||||
List<Vec3> points = new ArrayList<>();
|
||||
double[] steps = proportions();
|
||||
if (!box.contains(eyes)) {
|
||||
for (double y : steps) {
|
||||
for (double z : steps) {
|
||||
points.add(new Vec3(box.minX, box.minY + box.getYsize() * y, box.minZ + box.getZsize() * z));
|
||||
points.add(new Vec3(box.maxX, box.minY + box.getYsize() * y, box.minZ + box.getZsize() * z));
|
||||
}
|
||||
}
|
||||
for (double x : steps) {
|
||||
for (double z : steps) {
|
||||
points.add(new Vec3(box.minX + box.getXsize() * x, box.minY, box.minZ + box.getZsize() * z));
|
||||
points.add(new Vec3(box.minX + box.getXsize() * x, box.maxY, box.minZ + box.getZsize() * z));
|
||||
}
|
||||
}
|
||||
for (double x : steps) {
|
||||
for (double y : steps) {
|
||||
points.add(new Vec3(box.minX + box.getXsize() * x, box.minY + box.getYsize() * y, box.minZ));
|
||||
points.add(new Vec3(box.minX + box.getXsize() * x, box.minY + box.getYsize() * y, box.maxZ));
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
for (double x : steps) {
|
||||
for (double y : steps) {
|
||||
for (double z : steps) {
|
||||
points.add(new Vec3(
|
||||
box.minX + box.getXsize() * x,
|
||||
box.minY + box.getYsize() * y,
|
||||
box.minZ + box.getZsize() * z
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
static int randomInt(int min, int max) {
|
||||
if (max <= min) return min;
|
||||
return ThreadLocalRandom.current().nextInt(min, max + 1);
|
||||
}
|
||||
static double randomDouble(double min, double max) {
|
||||
if (max <= min) return min;
|
||||
return ThreadLocalRandom.current().nextDouble(min, max);
|
||||
}
|
||||
private static double[] proportions() {
|
||||
double[] steps = new double[13];
|
||||
for (int i = 0; i < steps.length; i++) {
|
||||
steps[i] = (i + 0.5) / steps.length;
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
/** Scored aim candidate used by {@link PointTracker} during multi-point selection. */
|
||||
record Candidate(Vec3 point, float score) {}
|
||||
}
|
||||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.point;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,185 @@
|
|||
package dev.loki.lovisual.util.aiming.point;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import dev.loki.lovisual.util.aiming.data.Rotation;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* Holds tunable aim-behaviour options and applies the post-selection point pipeline
|
||||
* (delay, lazy hold, gaussian jitter, motion instability) for a single tracked entity.
|
||||
* Package-private: only {@link PointTracker} composes it.
|
||||
*/
|
||||
final class PointProcessor {
|
||||
private boolean delayEnabled = true;
|
||||
private int delayMin = 2;
|
||||
private int delayMax = 4;
|
||||
private boolean lazyEnabled = true;
|
||||
private double lazyMin = 0.10;
|
||||
private double lazyMax = 0.20;
|
||||
private boolean gaussianEnabled;
|
||||
private double gaussianYawFactor;
|
||||
private double gaussianPitchFactor;
|
||||
private int gaussianChance = 100;
|
||||
private double gaussianSpeed = 0.15;
|
||||
private PointInsideBox delayedPoint;
|
||||
private int currentDelay = PointGeometry.randomInt(2, 4);
|
||||
private PointInsideBox lazyPoint;
|
||||
private double currentLazyThreshold;
|
||||
private Vec3 currentOffset = Vec3.ZERO;
|
||||
private Vec3 targetOffset = Vec3.ZERO;
|
||||
private Vec3 lastEyes;
|
||||
private Vec3 lastAimDirection;
|
||||
private Vec3 instabilityOffset = Vec3.ZERO;
|
||||
private Vec3 targetInstabilityOffset = Vec3.ZERO;
|
||||
private int instabilityRetargetTicks;
|
||||
/**
|
||||
* Replaces all runtime options in one shot; clamps each field so min/max pairs stay consistent.
|
||||
* Called by {@link PointTracker#setOptions}.
|
||||
*/
|
||||
void setOptions(boolean delayEnabled, int delayMin, int delayMax,
|
||||
boolean lazyEnabled, double lazyMin, double lazyMax,
|
||||
boolean gaussianEnabled, double gaussianYawFactor, double gaussianPitchFactor,
|
||||
int gaussianChance, double gaussianSpeed) {
|
||||
this.delayEnabled = delayEnabled;
|
||||
this.delayMin = Math.max(0, Math.min(delayMin, delayMax));
|
||||
this.delayMax = Math.max(this.delayMin, delayMax);
|
||||
this.lazyEnabled = lazyEnabled;
|
||||
this.lazyMin = Math.max(0.0, Math.min(lazyMin, lazyMax));
|
||||
this.lazyMax = Math.max(this.lazyMin, lazyMax);
|
||||
this.gaussianEnabled = gaussianEnabled;
|
||||
this.gaussianYawFactor = Math.max(0.0, gaussianYawFactor);
|
||||
this.gaussianPitchFactor = Math.max(0.0, gaussianPitchFactor);
|
||||
this.gaussianChance = Math.max(0, Math.min(100, gaussianChance));
|
||||
this.gaussianSpeed = Math.max(0.01, Math.min(1.0, gaussianSpeed));
|
||||
}
|
||||
/** Clears every per-target counter so a new entity starts with fresh delay / lazy / instability state. */
|
||||
void reset() {
|
||||
delayedPoint = null;
|
||||
currentDelay = PointGeometry.randomInt(delayMin, delayMax);
|
||||
lazyPoint = null;
|
||||
currentLazyThreshold = 0.0;
|
||||
currentOffset = Vec3.ZERO;
|
||||
targetOffset = Vec3.ZERO;
|
||||
lastEyes = null;
|
||||
lastAimDirection = null;
|
||||
instabilityOffset = Vec3.ZERO;
|
||||
targetInstabilityOffset = Vec3.ZERO;
|
||||
instabilityRetargetTicks = 0;
|
||||
}
|
||||
/** Runs the selected point through delay -> lazy -> gaussian -> motion-instability filters. */
|
||||
PointInsideBox process(PointInsideBox point, Vec3 eyes, Entity entity, Rotation initialRotation) {
|
||||
point = applyDelay(point);
|
||||
point = applyLazy(point);
|
||||
point = applyGaussian(point);
|
||||
return applyMotionInstability(point, eyes, entity, initialRotation);
|
||||
}
|
||||
/** Keeps the previously emitted point for a random short window before switching to the new one. */
|
||||
private PointInsideBox applyDelay(PointInsideBox point) {
|
||||
if (!delayEnabled) {
|
||||
delayedPoint = point;
|
||||
currentDelay = 0;
|
||||
return point;
|
||||
}
|
||||
if (delayedPoint != null) {
|
||||
delayedPoint = new PointInsideBox(PointGeometry.clampToBox(delayedPoint.pos(), point.box()), point.box());
|
||||
}
|
||||
if (point.equals(delayedPoint)) return point;
|
||||
if (delayedPoint == null) {
|
||||
delayedPoint = point;
|
||||
currentDelay = PointGeometry.randomInt(delayMin, delayMax);
|
||||
return point;
|
||||
}
|
||||
PointInsideBox currentPoint = delayedPoint;
|
||||
currentDelay--;
|
||||
if (currentDelay > 0) return currentPoint;
|
||||
delayedPoint = point;
|
||||
currentDelay = PointGeometry.randomInt(delayMin, delayMax);
|
||||
return currentPoint;
|
||||
}
|
||||
/** Snaps the emitted point back to the previous one until the raw movement exceeds a lazy threshold. */
|
||||
private PointInsideBox applyLazy(PointInsideBox point) {
|
||||
if (!lazyEnabled) {
|
||||
lazyPoint = point;
|
||||
currentLazyThreshold = 0.0;
|
||||
return point;
|
||||
}
|
||||
if (lazyPoint != null) {
|
||||
lazyPoint = new PointInsideBox(PointGeometry.clampToBox(lazyPoint.pos(), point.box()), point.box());
|
||||
}
|
||||
if (lazyPoint == null) {
|
||||
lazyPoint = point;
|
||||
currentLazyThreshold = PointGeometry.randomDouble(lazyMin, lazyMax);
|
||||
return point;
|
||||
}
|
||||
PointInsideBox currentPoint = lazyPoint;
|
||||
double thresholdSq = currentLazyThreshold * currentLazyThreshold;
|
||||
if (point.pos().distanceToSqr(currentPoint.pos()) < thresholdSq) return currentPoint;
|
||||
lazyPoint = point;
|
||||
currentLazyThreshold = PointGeometry.randomDouble(lazyMin, lazyMax);
|
||||
return currentPoint;
|
||||
}
|
||||
/** Adds a slowly-lerping Gaussian offset that occasionally re-targets (per {@code gaussianChance}% of ticks). */
|
||||
private PointInsideBox applyGaussian(PointInsideBox point) {
|
||||
if (!gaussianEnabled || (gaussianYawFactor <= 0.0 && gaussianPitchFactor <= 0.0)) {
|
||||
currentOffset = Vec3.ZERO;
|
||||
targetOffset = Vec3.ZERO;
|
||||
return point;
|
||||
}
|
||||
if (hasReachedOffsetTarget()) {
|
||||
if (ThreadLocalRandom.current().nextInt(100) < gaussianChance) {
|
||||
targetOffset = new Vec3(
|
||||
ThreadLocalRandom.current().nextGaussian() * gaussianYawFactor,
|
||||
ThreadLocalRandom.current().nextGaussian() * gaussianPitchFactor,
|
||||
ThreadLocalRandom.current().nextGaussian() * gaussianYawFactor
|
||||
);
|
||||
} else {
|
||||
targetOffset = Vec3.ZERO;
|
||||
}
|
||||
} else {
|
||||
currentOffset = new Vec3(
|
||||
Mth.lerp(gaussianSpeed, currentOffset.x, targetOffset.x),
|
||||
Mth.lerp(gaussianSpeed, currentOffset.y, targetOffset.y),
|
||||
Mth.lerp(gaussianSpeed, currentOffset.z, targetOffset.z)
|
||||
);
|
||||
}
|
||||
return new PointInsideBox(point.pos().add(currentOffset), point.box());
|
||||
}
|
||||
/** Biases the aim point outward when the player turns fast, moves, or the target itself is in motion. */
|
||||
private PointInsideBox applyMotionInstability(PointInsideBox point, Vec3 eyes, Entity entity, Rotation initialRotation) {
|
||||
Vec3 aimDirection = initialRotation.directionVector().normalize();
|
||||
double angleChange = lastAimDirection != null
|
||||
? Math.toDegrees(Math.acos(Mth.clamp(lastAimDirection.dot(aimDirection), -1.0, 1.0)))
|
||||
: 0.0;
|
||||
double playerMove = lastEyes != null ? eyes.distanceTo(lastEyes) : 0.0;
|
||||
Vec3 entityVelocity = entity != null ? entity.getDeltaMovement() : Vec3.ZERO;
|
||||
double entityMove = PointGeometry.horizontalLength(entityVelocity) + Math.abs(entityVelocity.y) * 0.45;
|
||||
lastEyes = eyes;
|
||||
lastAimDirection = aimDirection;
|
||||
double intensity = Mth.clamp(angleChange / 14.0 + playerMove / 0.14 + entityMove / 0.11, 0.0, 1.0);
|
||||
if (intensity < 0.12) {
|
||||
instabilityOffset = instabilityOffset.scale(0.72);
|
||||
targetInstabilityOffset = targetInstabilityOffset.scale(0.72);
|
||||
return new PointInsideBox(PointGeometry.clampToBox(point.pos().add(instabilityOffset), point.box()), point.box());
|
||||
}
|
||||
instabilityRetargetTicks--;
|
||||
if (instabilityRetargetTicks <= 0 || instabilityOffset.distanceToSqr(targetInstabilityOffset) < 1.0E-4) {
|
||||
targetInstabilityOffset = PointGeometry.randomInstabilityOffset(point.box(), entityVelocity, aimDirection, intensity);
|
||||
instabilityRetargetTicks = PointGeometry.randomInt(2, intensity > 0.65 ? 4 : 6);
|
||||
}
|
||||
double blend = 0.14 + 0.18 * intensity;
|
||||
instabilityOffset = new Vec3(
|
||||
Mth.lerp(blend, instabilityOffset.x, targetInstabilityOffset.x),
|
||||
Mth.lerp(blend, instabilityOffset.y, targetInstabilityOffset.y),
|
||||
Mth.lerp(blend, instabilityOffset.z, targetInstabilityOffset.z)
|
||||
);
|
||||
return new PointInsideBox(PointGeometry.clampToBox(point.pos().add(instabilityOffset), point.box()), point.box());
|
||||
}
|
||||
private boolean hasReachedOffsetTarget() {
|
||||
return Math.abs(currentOffset.x - targetOffset.x) < 0.01
|
||||
&& Math.abs(currentOffset.y - targetOffset.y) < 0.01
|
||||
&& Math.abs(currentOffset.z - targetOffset.z) < 0.01;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.point;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
|
|
@ -13,265 +6,25 @@ import net.minecraft.world.phys.AABB;
|
|||
import net.minecraft.world.phys.Vec3;
|
||||
import dev.loki.lovisual.util.aiming.data.Rotation;
|
||||
import dev.loki.lovisual.util.entity.simulation.PositionExtrapolation;
|
||||
import dev.loki.lovisual.util.raycast.RaycastUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* Chooses and stabilises an aim point on a target's hitbox across ticks.
|
||||
* Public entry point of the point-tracking util: callers invoke {@link #findPoint} every tick
|
||||
* and configure behaviour via {@link #setOptions}.
|
||||
*
|
||||
* <p>Internal layout: pure geometry helpers live in {@link PointGeometry}; the stateful
|
||||
* post-selection pipeline (delay, lazy hold, gaussian jitter, motion instability) lives in
|
||||
* {@link PointProcessor}. This class keeps only cross-tick selection state and continuity.</p>
|
||||
*/
|
||||
public final class PointTracker {
|
||||
|
||||
private final PointProcessor processor = new PointProcessor();
|
||||
private int trackedEntityId = -1;
|
||||
private PointInsideBox delayedPoint;
|
||||
private int currentDelay = randomInt(2, 4);
|
||||
private PointInsideBox lazyPoint;
|
||||
private double currentLazyThreshold;
|
||||
private Vec3 currentOffset = Vec3.ZERO;
|
||||
private Vec3 targetOffset = Vec3.ZERO;
|
||||
private Vec3 smoothedPoint;
|
||||
private Vec3 lastSelectedPoint;
|
||||
private Vec3 lastEyes;
|
||||
private Vec3 lastAimDirection;
|
||||
private Vec3 instabilityOffset = Vec3.ZERO;
|
||||
private Vec3 targetInstabilityOffset = Vec3.ZERO;
|
||||
private int instabilityRetargetTicks;
|
||||
|
||||
private boolean delayEnabled = true;
|
||||
private int delayMin = 2;
|
||||
private int delayMax = 4;
|
||||
private boolean lazyEnabled = true;
|
||||
private double lazyMin = 0.10;
|
||||
private double lazyMax = 0.20;
|
||||
private boolean gaussianEnabled;
|
||||
private double gaussianYawFactor;
|
||||
private double gaussianPitchFactor;
|
||||
private int gaussianChance = 100;
|
||||
private double gaussianSpeed = 0.15;
|
||||
|
||||
private static float scoreCandidate(Vec3 eyes,
|
||||
Rotation initialRotation,
|
||||
Rotation candidateRotation,
|
||||
Vec3 point,
|
||||
Vec3 center,
|
||||
AABB box,
|
||||
Vec3 aimDir,
|
||||
Vec3 movement,
|
||||
double movementStrength) {
|
||||
float rotationScore = initialRotation.angleTo(candidateRotation) * 1.15f;
|
||||
double halfX = Math.max(1.0E-4, box.getXsize() * 0.5);
|
||||
double halfY = Math.max(1.0E-4, box.getYsize() * 0.5);
|
||||
double halfZ = Math.max(1.0E-4, box.getZsize() * 0.5);
|
||||
|
||||
double nx = Math.abs(point.x - center.x) / halfX;
|
||||
double ny = Math.abs(point.y - center.y) / halfY;
|
||||
double nz = Math.abs(point.z - center.z) / halfZ;
|
||||
double edgeFactor = Math.max(Math.max(nx, nz), ny * 0.65);
|
||||
double centerPenalty = (1.0 - Mth.clamp(edgeFactor, 0.0, 1.0))
|
||||
* (movementStrength > 0.035 ? 6.0 : 4.0);
|
||||
|
||||
double rayDistance = distanceToRay(eyes, aimDir, point);
|
||||
double rayScale = Math.max(0.08, Math.max(box.getXsize(), Math.max(box.getYsize(), box.getZsize())) * 0.5);
|
||||
double rayScore = (rayDistance / rayScale) * (movementStrength > 0.035 ? 5.5 : 4.0);
|
||||
|
||||
double movementBenefit = movingPointBenefit(point, center, box, movement, movementStrength);
|
||||
return rotationScore + (float) rayScore + (float) centerPenalty - (float) movementBenefit;
|
||||
}
|
||||
|
||||
private static List<Candidate> filterDiverse(List<Candidate> candidates, Vec3 reference, AABB box, boolean movingTarget) {
|
||||
List<Candidate> out = new ArrayList<>();
|
||||
if (reference == null) {
|
||||
return out;
|
||||
}
|
||||
|
||||
double minAxis = Math.min(box.getXsize(), Math.min(box.getYsize(), box.getZsize()));
|
||||
double minDistance = Math.max(movingTarget ? 0.085 : 0.055, minAxis * (movingTarget ? 0.26 : 0.18));
|
||||
double minDistanceSq = minDistance * minDistance;
|
||||
for (Candidate candidate : candidates) {
|
||||
if (candidate.point().distanceToSqr(reference) >= minDistanceSq) {
|
||||
out.add(candidate);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private static Candidate selectWeighted(List<Candidate> candidates, float bestScore) {
|
||||
if (candidates.size() == 1) {
|
||||
return candidates.get(0);
|
||||
}
|
||||
|
||||
double total = 0.0;
|
||||
double[] weights = new double[candidates.size()];
|
||||
for (int i = 0; i < candidates.size(); i++) {
|
||||
double delta = Math.max(0.0, candidates.get(i).score() - bestScore);
|
||||
double weight = 1.0 / (1.0 + delta * delta * 0.08);
|
||||
weights[i] = weight;
|
||||
total += weight;
|
||||
}
|
||||
|
||||
double pick = ThreadLocalRandom.current().nextDouble(total);
|
||||
for (int i = 0; i < candidates.size(); i++) {
|
||||
pick -= weights[i];
|
||||
if (pick <= 0.0) {
|
||||
return candidates.get(i);
|
||||
}
|
||||
}
|
||||
return candidates.get(candidates.size() - 1);
|
||||
}
|
||||
|
||||
private static double movingPointBenefit(Vec3 point, Vec3 center, AABB box, Vec3 movement, double movementStrength) {
|
||||
if (movementStrength <= 0.035) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double halfX = Math.max(1.0E-4, box.getXsize() * 0.5);
|
||||
double halfZ = Math.max(1.0E-4, box.getZsize() * 0.5);
|
||||
double dirX = movement.x / movementStrength;
|
||||
double dirZ = movement.z / movementStrength;
|
||||
double offX = Mth.clamp((point.x - center.x) / halfX, -1.0, 1.0);
|
||||
double offZ = Mth.clamp((point.z - center.z) / halfZ, -1.0, 1.0);
|
||||
double lead = Mth.clamp(offX * dirX + offZ * dirZ, -1.0, 1.0);
|
||||
double sideStrength = Math.min(1.0, Math.hypot(offX, offZ));
|
||||
|
||||
return Math.max(0.0, lead) * 4.0 + sideStrength * 1.4;
|
||||
}
|
||||
|
||||
private static double distanceToRay(Vec3 origin, Vec3 direction, Vec3 point) {
|
||||
Vec3 diff = point.subtract(origin);
|
||||
double t = Math.max(0.0, diff.dot(direction));
|
||||
Vec3 closest = origin.add(direction.scale(t));
|
||||
return point.distanceTo(closest);
|
||||
}
|
||||
|
||||
private static Vec3 findRayHitPoint(Vec3 eyes, Vec3 aimDir, AABB box, double maxDistance) {
|
||||
double range = maxDistance > 0.0 && maxDistance < Double.MAX_VALUE ? maxDistance : 6.0;
|
||||
return box.clip(eyes, eyes.add(aimDir.scale(range))).orElse(null);
|
||||
}
|
||||
|
||||
private static double horizontalLength(Vec3 vec) {
|
||||
if (vec == null) {
|
||||
return 0.0;
|
||||
}
|
||||
return Math.hypot(vec.x, vec.z);
|
||||
}
|
||||
|
||||
private static boolean isValidPoint(Vec3 startPoint,
|
||||
Vec3 endPoint,
|
||||
double maxDistance,
|
||||
boolean ignoreWalls) {
|
||||
if (startPoint == null || endPoint == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (maxDistance > 0.0 && startPoint.distanceToSqr(endPoint) > maxDistance * maxDistance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ignoreWalls || RaycastUtil.hasLineOfSightPoint(startPoint, endPoint);
|
||||
}
|
||||
|
||||
private static Vec3 randomInstabilityOffset(AABB box, Vec3 entityVelocity, Vec3 aimDirection, double intensity) {
|
||||
double halfX = Math.max(0.001, box.getXsize() * 0.5);
|
||||
double halfY = Math.max(0.001, box.getYsize() * 0.5);
|
||||
double halfZ = Math.max(0.001, box.getZsize() * 0.5);
|
||||
|
||||
double speed = horizontalLength(entityVelocity);
|
||||
double sideX;
|
||||
double sideZ;
|
||||
if (speed > 0.035) {
|
||||
sideX = entityVelocity.x / speed;
|
||||
sideZ = entityVelocity.z / speed;
|
||||
} else {
|
||||
Vec3 horizontalAim = new Vec3(aimDirection.x, 0.0, aimDirection.z);
|
||||
double aimLen = Math.max(1.0E-4, horizontalLength(horizontalAim));
|
||||
sideX = -horizontalAim.z / aimLen;
|
||||
sideZ = horizontalAim.x / aimLen;
|
||||
}
|
||||
|
||||
double lateral = randomDouble(-1.0, 1.0) * (0.14 + 0.22 * intensity);
|
||||
double lead = speed > 0.035 ? randomDouble(0.05, 0.24) * intensity : 0.0;
|
||||
double vertical = randomDouble(-0.16, 0.14) * intensity;
|
||||
|
||||
return new Vec3(
|
||||
sideX * halfX * lateral + sideX * halfX * lead,
|
||||
halfY * vertical,
|
||||
sideZ * halfZ * lateral + sideZ * halfZ * lead
|
||||
);
|
||||
}
|
||||
|
||||
private static Vec3 clampToBox(Vec3 point, AABB box) {
|
||||
return new Vec3(
|
||||
Mth.clamp(point.x, box.minX, box.maxX),
|
||||
Mth.clamp(point.y, box.minY, box.maxY),
|
||||
Mth.clamp(point.z, box.minZ, box.maxZ)
|
||||
);
|
||||
}
|
||||
|
||||
private static Vec3 getNearestPoint(AABB box, Vec3 eyes) {
|
||||
return new Vec3(
|
||||
Mth.clamp(eyes.x, box.minX, box.maxX),
|
||||
Mth.clamp(eyes.y, box.minY, box.maxY),
|
||||
Mth.clamp(eyes.z, box.minZ, box.maxZ)
|
||||
);
|
||||
}
|
||||
|
||||
private static List<Vec3> projectPointsOnBox(Vec3 eyes, AABB box) {
|
||||
List<Vec3> points = new ArrayList<>();
|
||||
double[] steps = proportions();
|
||||
|
||||
if (!box.contains(eyes)) {
|
||||
for (double y : steps) {
|
||||
for (double z : steps) {
|
||||
points.add(new Vec3(box.minX, box.minY + box.getYsize() * y, box.minZ + box.getZsize() * z));
|
||||
points.add(new Vec3(box.maxX, box.minY + box.getYsize() * y, box.minZ + box.getZsize() * z));
|
||||
}
|
||||
}
|
||||
for (double x : steps) {
|
||||
for (double z : steps) {
|
||||
points.add(new Vec3(box.minX + box.getXsize() * x, box.minY, box.minZ + box.getZsize() * z));
|
||||
points.add(new Vec3(box.minX + box.getXsize() * x, box.maxY, box.minZ + box.getZsize() * z));
|
||||
}
|
||||
}
|
||||
for (double x : steps) {
|
||||
for (double y : steps) {
|
||||
points.add(new Vec3(box.minX + box.getXsize() * x, box.minY + box.getYsize() * y, box.minZ));
|
||||
points.add(new Vec3(box.minX + box.getXsize() * x, box.minY + box.getYsize() * y, box.maxZ));
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
for (double x : steps) {
|
||||
for (double y : steps) {
|
||||
for (double z : steps) {
|
||||
points.add(new Vec3(
|
||||
box.minX + box.getXsize() * x,
|
||||
box.minY + box.getYsize() * y,
|
||||
box.minZ + box.getZsize() * z
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
private static int randomInt(int min, int max) {
|
||||
if (max <= min) return min;
|
||||
return ThreadLocalRandom.current().nextInt(min, max + 1);
|
||||
}
|
||||
|
||||
private static double randomDouble(double min, double max) {
|
||||
if (max <= min) return min;
|
||||
return ThreadLocalRandom.current().nextDouble(min, max);
|
||||
}
|
||||
|
||||
private static double[] proportions() {
|
||||
double[] steps = new double[13];
|
||||
for (int i = 0; i < steps.length; i++) {
|
||||
steps[i] = (i + 0.5) / steps.length;
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
|
||||
/** Applies runtime tuning for the point-processing pipeline. See {@link PointProcessor#setOptions}. */
|
||||
public void setOptions(boolean delayEnabled,
|
||||
int delayMin,
|
||||
int delayMax,
|
||||
|
|
@ -283,19 +36,13 @@ public final class PointTracker {
|
|||
double gaussianPitchFactor,
|
||||
int gaussianChance,
|
||||
double gaussianSpeed) {
|
||||
this.delayEnabled = delayEnabled;
|
||||
this.delayMin = Math.max(0, Math.min(delayMin, delayMax));
|
||||
this.delayMax = Math.max(this.delayMin, delayMax);
|
||||
this.lazyEnabled = lazyEnabled;
|
||||
this.lazyMin = Math.max(0.0, Math.min(lazyMin, lazyMax));
|
||||
this.lazyMax = Math.max(this.lazyMin, lazyMax);
|
||||
this.gaussianEnabled = gaussianEnabled;
|
||||
this.gaussianYawFactor = Math.max(0.0, gaussianYawFactor);
|
||||
this.gaussianPitchFactor = Math.max(0.0, gaussianPitchFactor);
|
||||
this.gaussianChance = Math.max(0, Math.min(100, gaussianChance));
|
||||
this.gaussianSpeed = Math.max(0.01, Math.min(1.0, gaussianSpeed));
|
||||
processor.setOptions(delayEnabled, delayMin, delayMax, lazyEnabled, lazyMin, lazyMax,
|
||||
gaussianEnabled, gaussianYawFactor, gaussianPitchFactor, gaussianChance, gaussianSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the aim point for the entity's hitbox extrapolated {@code ticks} forward,
|
||||
* honouring max-distance and wall visibility constraints.
|
||||
*/
|
||||
public PointInsideBox findPoint(Vec3 eyes,
|
||||
Entity entity,
|
||||
int ticks,
|
||||
|
|
@ -303,38 +50,42 @@ public final class PointTracker {
|
|||
double maxDistance,
|
||||
boolean ignoreWalls) {
|
||||
AABB box = PositionExtrapolation.getBestForEntity(entity).getBoxInTicks(ticks);
|
||||
List<Vec3> points = projectPointsOnBox(eyes, box);
|
||||
|
||||
List<Vec3> points = PointGeometry.projectPointsOnBox(eyes, box);
|
||||
if (trackedEntityId != entity.getId()) {
|
||||
resetProcessors();
|
||||
reset();
|
||||
trackedEntityId = entity.getId();
|
||||
}
|
||||
|
||||
Vec3 bestPoint = selectMultiPoint(eyes, entity, box, initialRotation, maxDistance, ignoreWalls);
|
||||
if (bestPoint == null) {
|
||||
Vec3 anchor = smoothedPoint != null ? clampToBox(smoothedPoint, box) : eyes;
|
||||
bestPoint = points.isEmpty() ? getNearestPoint(box, anchor) : points.get(0);
|
||||
Vec3 anchor = smoothedPoint != null ? PointGeometry.clampToBox(smoothedPoint, box) : eyes;
|
||||
bestPoint = points.isEmpty() ? PointGeometry.getNearestPoint(box, anchor) : points.get(0);
|
||||
for (Vec3 point : points) {
|
||||
if (point.distanceToSqr(anchor) < bestPoint.distanceToSqr(anchor)) {
|
||||
bestPoint = point;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PointInsideBox point = new PointInsideBox(clampToBox(bestPoint, box), box);
|
||||
point = applyDelay(point);
|
||||
point = applyLazy(point);
|
||||
point = applyGaussian(point);
|
||||
point = applyMotionInstability(point, eyes, entity, initialRotation);
|
||||
PointInsideBox point = new PointInsideBox(PointGeometry.clampToBox(bestPoint, box), box);
|
||||
point = processor.process(point, eyes, entity, initialRotation);
|
||||
point = applyContinuity(point);
|
||||
smoothedPoint = point.pos();
|
||||
return new PointInsideBox(clampToBox(point.pos(), box), box);
|
||||
return new PointInsideBox(PointGeometry.clampToBox(point.pos(), box), box);
|
||||
}
|
||||
|
||||
/** Convenience overload with unlimited range and walls ignored. */
|
||||
public PointInsideBox findPoint(Vec3 eyes, Entity entity, int ticks, Rotation initialRotation) {
|
||||
return findPoint(eyes, entity, ticks, initialRotation, Double.MAX_VALUE, true);
|
||||
}
|
||||
|
||||
/** Forgets the tracked entity and every per-target counter (selection, delay, lazy, gaussian, instability). */
|
||||
public void reset() {
|
||||
trackedEntityId = -1;
|
||||
smoothedPoint = null;
|
||||
lastSelectedPoint = null;
|
||||
processor.reset();
|
||||
}
|
||||
/**
|
||||
* Scores every projected box point (plus the aim-ray hit) and picks one from a
|
||||
* diverse, weighted pool. Falls back to {@code null} when no valid candidate exists.
|
||||
*/
|
||||
private Vec3 selectMultiPoint(Vec3 eyes,
|
||||
Entity entity,
|
||||
AABB box,
|
||||
|
|
@ -344,46 +95,41 @@ public final class PointTracker {
|
|||
if (eyes == null || box == null || initialRotation == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Candidate> candidates = new ArrayList<>();
|
||||
List<PointGeometry.Candidate> candidates = new ArrayList<>();
|
||||
float bestScore = Float.MAX_VALUE;
|
||||
Vec3 center = box.getCenter();
|
||||
Vec3 aimDir = initialRotation.directionVector().normalize();
|
||||
Vec3 movement = entity != null ? entity.getDeltaMovement() : Vec3.ZERO;
|
||||
double movementStrength = horizontalLength(movement);
|
||||
|
||||
Vec3 rayHit = findRayHitPoint(eyes, aimDir, box, maxDistance);
|
||||
if (rayHit != null && isValidPoint(eyes, rayHit, maxDistance, ignoreWalls)) {
|
||||
double movementStrength = PointGeometry.horizontalLength(movement);
|
||||
Vec3 rayHit = PointGeometry.findRayHitPoint(eyes, aimDir, box, maxDistance);
|
||||
if (rayHit != null && PointGeometry.isValidPoint(eyes, rayHit, maxDistance, ignoreWalls)) {
|
||||
Rotation rayRotation = Rotation.lookingAt(rayHit, eyes).normalize();
|
||||
float score = scoreCandidate(eyes, initialRotation, rayRotation, rayHit, center, box,
|
||||
float score = PointGeometry.scoreCandidate(eyes, initialRotation, rayRotation, rayHit, center, box,
|
||||
aimDir, movement, movementStrength) - 2.0f;
|
||||
candidates.add(new Candidate(rayHit, score));
|
||||
candidates.add(new PointGeometry.Candidate(rayHit, score));
|
||||
bestScore = score;
|
||||
}
|
||||
|
||||
for (Vec3 point : projectPointsOnBox(eyes, box)) {
|
||||
if (!isValidPoint(eyes, point, maxDistance, ignoreWalls)) {
|
||||
for (Vec3 point : PointGeometry.projectPointsOnBox(eyes, box)) {
|
||||
if (!PointGeometry.isValidPoint(eyes, point, maxDistance, ignoreWalls)) {
|
||||
continue;
|
||||
}
|
||||
Rotation candidateRotation = Rotation.lookingAt(point, eyes).normalize();
|
||||
float score = scoreCandidate(eyes, initialRotation, candidateRotation, point, center, box,
|
||||
float score = PointGeometry.scoreCandidate(eyes, initialRotation, candidateRotation, point, center, box,
|
||||
aimDir, movement, movementStrength);
|
||||
candidates.add(new Candidate(point, score));
|
||||
candidates.add(new PointGeometry.Candidate(point, score));
|
||||
if (score < bestScore) {
|
||||
bestScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean movingTarget = movementStrength > 0.035 || Math.abs(movement.y) > 0.03;
|
||||
float threshold = movingTarget
|
||||
? Math.max(7.0f, Math.min(28.0f, bestScore * 0.55f + 6.0f))
|
||||
: Math.max(4.0f, Math.min(18.0f, bestScore * 0.35f + 3.0f));
|
||||
List<Candidate> pool = new ArrayList<>();
|
||||
for (Candidate candidate : candidates) {
|
||||
List<PointGeometry.Candidate> pool = new ArrayList<>();
|
||||
for (PointGeometry.Candidate candidate : candidates) {
|
||||
if (candidate.score() <= bestScore + threshold) {
|
||||
pool.add(candidate);
|
||||
}
|
||||
|
|
@ -391,177 +137,26 @@ public final class PointTracker {
|
|||
if (pool.isEmpty()) {
|
||||
pool = candidates;
|
||||
}
|
||||
|
||||
Vec3 reference = lastSelectedPoint != null ? lastSelectedPoint : smoothedPoint;
|
||||
List<Candidate> diversePool = filterDiverse(pool, reference, box, movingTarget);
|
||||
List<PointGeometry.Candidate> diversePool = PointGeometry.filterDiverse(pool, reference, box, movingTarget);
|
||||
if (!diversePool.isEmpty()) {
|
||||
pool = diversePool;
|
||||
}
|
||||
|
||||
Candidate selected = selectWeighted(pool, bestScore);
|
||||
PointGeometry.Candidate selected = PointGeometry.selectWeighted(pool, bestScore);
|
||||
lastSelectedPoint = selected.point();
|
||||
return selected.point();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
trackedEntityId = -1;
|
||||
resetProcessors();
|
||||
}
|
||||
|
||||
private void resetProcessors() {
|
||||
delayedPoint = null;
|
||||
currentDelay = randomInt(delayMin, delayMax);
|
||||
lazyPoint = null;
|
||||
currentLazyThreshold = 0.0;
|
||||
currentOffset = Vec3.ZERO;
|
||||
targetOffset = Vec3.ZERO;
|
||||
smoothedPoint = null;
|
||||
lastSelectedPoint = null;
|
||||
lastEyes = null;
|
||||
lastAimDirection = null;
|
||||
instabilityOffset = Vec3.ZERO;
|
||||
targetInstabilityOffset = Vec3.ZERO;
|
||||
instabilityRetargetTicks = 0;
|
||||
}
|
||||
|
||||
private PointInsideBox applyDelay(PointInsideBox point) {
|
||||
if (!delayEnabled) {
|
||||
delayedPoint = point;
|
||||
currentDelay = 0;
|
||||
return point;
|
||||
}
|
||||
|
||||
if (delayedPoint != null) {
|
||||
delayedPoint = new PointInsideBox(clampToBox(delayedPoint.pos(), point.box()), point.box());
|
||||
}
|
||||
|
||||
if (point.equals(delayedPoint)) {
|
||||
return point;
|
||||
}
|
||||
|
||||
if (delayedPoint == null) {
|
||||
delayedPoint = point;
|
||||
currentDelay = randomInt(delayMin, delayMax);
|
||||
return point;
|
||||
}
|
||||
|
||||
PointInsideBox currentPoint = delayedPoint;
|
||||
currentDelay--;
|
||||
if (currentDelay > 0) {
|
||||
return currentPoint;
|
||||
}
|
||||
|
||||
delayedPoint = point;
|
||||
currentDelay = randomInt(delayMin, delayMax);
|
||||
return currentPoint;
|
||||
}
|
||||
|
||||
private PointInsideBox applyLazy(PointInsideBox point) {
|
||||
if (!lazyEnabled) {
|
||||
lazyPoint = point;
|
||||
currentLazyThreshold = 0.0;
|
||||
return point;
|
||||
}
|
||||
|
||||
if (lazyPoint != null) {
|
||||
lazyPoint = new PointInsideBox(clampToBox(lazyPoint.pos(), point.box()), point.box());
|
||||
}
|
||||
|
||||
if (lazyPoint == null) {
|
||||
lazyPoint = point;
|
||||
currentLazyThreshold = randomDouble(lazyMin, lazyMax);
|
||||
return point;
|
||||
}
|
||||
|
||||
PointInsideBox currentPoint = lazyPoint;
|
||||
double thresholdSq = currentLazyThreshold * currentLazyThreshold;
|
||||
if (point.pos().distanceToSqr(currentPoint.pos()) < thresholdSq) {
|
||||
return currentPoint;
|
||||
}
|
||||
|
||||
lazyPoint = point;
|
||||
currentLazyThreshold = randomDouble(lazyMin, lazyMax);
|
||||
return currentPoint;
|
||||
}
|
||||
|
||||
private PointInsideBox applyGaussian(PointInsideBox point) {
|
||||
if (!gaussianEnabled || (gaussianYawFactor <= 0.0 && gaussianPitchFactor <= 0.0)) {
|
||||
currentOffset = Vec3.ZERO;
|
||||
targetOffset = Vec3.ZERO;
|
||||
return point;
|
||||
}
|
||||
|
||||
if (hasReachedOffsetTarget()) {
|
||||
if (ThreadLocalRandom.current().nextInt(100) < gaussianChance) {
|
||||
targetOffset = new Vec3(
|
||||
ThreadLocalRandom.current().nextGaussian() * gaussianYawFactor,
|
||||
ThreadLocalRandom.current().nextGaussian() * gaussianPitchFactor,
|
||||
ThreadLocalRandom.current().nextGaussian() * gaussianYawFactor
|
||||
);
|
||||
} else {
|
||||
targetOffset = Vec3.ZERO;
|
||||
}
|
||||
} else {
|
||||
currentOffset = new Vec3(
|
||||
Mth.lerp(gaussianSpeed, currentOffset.x, targetOffset.x),
|
||||
Mth.lerp(gaussianSpeed, currentOffset.y, targetOffset.y),
|
||||
Mth.lerp(gaussianSpeed, currentOffset.z, targetOffset.z)
|
||||
);
|
||||
}
|
||||
|
||||
return new PointInsideBox(point.pos().add(currentOffset), point.box());
|
||||
}
|
||||
|
||||
private PointInsideBox applyMotionInstability(PointInsideBox point,
|
||||
Vec3 eyes,
|
||||
Entity entity,
|
||||
Rotation initialRotation) {
|
||||
Vec3 aimDirection = initialRotation.directionVector().normalize();
|
||||
double angleChange = lastAimDirection != null
|
||||
? Math.toDegrees(Math.acos(Mth.clamp(lastAimDirection.dot(aimDirection), -1.0, 1.0)))
|
||||
: 0.0;
|
||||
double playerMove = lastEyes != null ? eyes.distanceTo(lastEyes) : 0.0;
|
||||
Vec3 entityVelocity = entity != null ? entity.getDeltaMovement() : Vec3.ZERO;
|
||||
double entityMove = horizontalLength(entityVelocity) + Math.abs(entityVelocity.y) * 0.45;
|
||||
|
||||
lastEyes = eyes;
|
||||
lastAimDirection = aimDirection;
|
||||
|
||||
double intensity = Mth.clamp(angleChange / 14.0 + playerMove / 0.14 + entityMove / 0.11, 0.0, 1.0);
|
||||
if (intensity < 0.12) {
|
||||
instabilityOffset = instabilityOffset.scale(0.72);
|
||||
targetInstabilityOffset = targetInstabilityOffset.scale(0.72);
|
||||
return new PointInsideBox(clampToBox(point.pos().add(instabilityOffset), point.box()), point.box());
|
||||
}
|
||||
|
||||
instabilityRetargetTicks--;
|
||||
if (instabilityRetargetTicks <= 0 || instabilityOffset.distanceToSqr(targetInstabilityOffset) < 1.0E-4) {
|
||||
targetInstabilityOffset = randomInstabilityOffset(point.box(), entityVelocity, aimDirection, intensity);
|
||||
instabilityRetargetTicks = randomInt(2, intensity > 0.65 ? 4 : 6);
|
||||
}
|
||||
|
||||
double blend = 0.14 + 0.18 * intensity;
|
||||
instabilityOffset = new Vec3(
|
||||
Mth.lerp(blend, instabilityOffset.x, targetInstabilityOffset.x),
|
||||
Mth.lerp(blend, instabilityOffset.y, targetInstabilityOffset.y),
|
||||
Mth.lerp(blend, instabilityOffset.z, targetInstabilityOffset.z)
|
||||
);
|
||||
|
||||
return new PointInsideBox(clampToBox(point.pos().add(instabilityOffset), point.box()), point.box());
|
||||
}
|
||||
|
||||
/** Lerps the freshly processed point towards the previous smoothed position so aim does not teleport. */
|
||||
private PointInsideBox applyContinuity(PointInsideBox point) {
|
||||
if (smoothedPoint == null) {
|
||||
return point;
|
||||
}
|
||||
|
||||
Vec3 current = clampToBox(smoothedPoint, point.box());
|
||||
Vec3 target = clampToBox(point.pos(), point.box());
|
||||
Vec3 current = PointGeometry.clampToBox(smoothedPoint, point.box());
|
||||
Vec3 target = PointGeometry.clampToBox(point.pos(), point.box());
|
||||
double distance = current.distanceTo(target);
|
||||
if (distance <= 1.0E-4) {
|
||||
return new PointInsideBox(current, point.box());
|
||||
}
|
||||
|
||||
double blend = distance > 0.35 ? 0.42 : distance > 0.15 ? 0.28 : 0.18;
|
||||
Vec3 blended = new Vec3(
|
||||
Mth.lerp(blend, current.x, target.x),
|
||||
|
|
@ -570,13 +165,4 @@ public final class PointTracker {
|
|||
);
|
||||
return new PointInsideBox(blended, point.box());
|
||||
}
|
||||
|
||||
private boolean hasReachedOffsetTarget() {
|
||||
return Math.abs(currentOffset.x - targetOffset.x) < 0.01
|
||||
&& Math.abs(currentOffset.y - targetOffset.y) < 0.01
|
||||
&& Math.abs(currentOffset.z - targetOffset.z) < 0.01;
|
||||
}
|
||||
|
||||
private record Candidate(Vec3 point, float score) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.preference;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.preference;
|
||||
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.raytrace;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.rotation;
|
||||
import dev.loki.lovisual.util.aiming.RequestHandler;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.rotation;
|
||||
import dev.loki.lovisual.util.aiming.RestrictedSingleUseAction;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.aiming.rotation;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.animation;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.animation;
|
||||
import dev.loki.lovisual.features.module.modules.visuals.camera.ViewModel;
|
||||
import dev.loki.lovisual.features.module.modules.visuals.items.held.HoldMyItems;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.animation;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.animation;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.animation.hand;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.animation.hand;
|
||||
import dev.loki.lovisual.util.animation.hand.state.HandAnimState;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.animation.hand;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.animation.hand;
|
||||
|
||||
import net.minecraft.tags.ItemTags;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.animation.hand.state;
|
||||
|
||||
import dev.loki.lovisual.util.animation.SmoothValue;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.animation.hand.state;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.block.bed;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.block.bed;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.block.bed;
|
||||
|
||||
import dev.loki.lovisual.config.values.mode.EnumValue;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.block.bed;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.block.render;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.block.render;
|
||||
|
||||
import dev.loki.lovisual.config.values.mode.EnumValue;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.block.render;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.block.render;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.block.scan;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.block.scan;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.block.scan;
|
||||
|
||||
import dev.loki.lovisual.config.values.mode.EnumValue;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.block.scan;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.click;
|
||||
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.click;
|
||||
|
||||
import dev.loki.lovisual.config.values.primitive.BooleanMapValue;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.click;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.attack;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.attack;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.attack;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.hit;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.protocol;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.protocol;
|
||||
|
||||
import com.viaversion.viafabricplus.ViaFabricPlus;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.protocol.heuristics;
|
||||
|
||||
public enum CombatProtocolHeuristicSource {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.protocol.heuristics;
|
||||
|
||||
import dev.loki.lovisual.events.meta.EventHandler;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.protocol.heuristics;
|
||||
|
||||
import dev.loki.lovisual.config.definition.ConfigNameProvider;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.protocol.vfp;
|
||||
|
||||
import com.viaversion.viafabricplus.ViaFabricPlus;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.protocol.vfp;
|
||||
|
||||
import com.viaversion.viafabricplus.ViaFabricPlus;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.rotation;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.rotation;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.rotation;
|
||||
|
||||
import dev.loki.lovisual.features.module.lifecycle.Modules;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.rotation;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.tracking;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.combat.tracking;
|
||||
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.entity;
|
||||
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
|
|
@ -21,8 +14,6 @@ public enum EagleUtil {
|
|||
private static final double MIN_AXIS_COMPONENT = 0.18;
|
||||
private static final double MAX_RESCUE_LOOKAHEAD = 0.42;
|
||||
private static final double MIN_TICK_DELTA_LEAD = 0.25;
|
||||
private static final double CENTER_DEAD_ANGLE_COS = 0.34;
|
||||
private static final int DIAGONAL_RESCUE_TICKS = 2;
|
||||
|
||||
public static EdgeCheck checkEdge(LocalPlayer player, MovementInputEvent event, double edgeDistance) {
|
||||
return checkEdge(player, event, edgeDistance, TickDelta.get());
|
||||
|
|
@ -173,196 +164,6 @@ public enum EagleUtil {
|
|||
return Math.max(0.0, Math.min(1.0, value));
|
||||
}
|
||||
|
||||
public enum RecoveryMode {
|
||||
STOP,
|
||||
INVERT,
|
||||
CENTER
|
||||
}
|
||||
|
||||
public static final class EdgeRecovery {
|
||||
private Vec3 center;
|
||||
private int overwriteTicks;
|
||||
private int sneakTicks;
|
||||
|
||||
private static Vec3 blockBottomCenter(LocalPlayer player) {
|
||||
return new Vec3(
|
||||
player.blockPosition().getX() + 0.5,
|
||||
player.blockPosition().getY(),
|
||||
player.blockPosition().getZ() + 0.5
|
||||
);
|
||||
}
|
||||
|
||||
private static double horizontalDistanceSquared(Vec3 a, Vec3 b) {
|
||||
double x = a.x - b.x;
|
||||
double z = a.z - b.z;
|
||||
return x * x + z * z;
|
||||
}
|
||||
|
||||
public boolean handleDiagonalRescue(LocalPlayer player, MovementInputEvent event, double edgeDistance) {
|
||||
if (player == null || event == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
updateSafeCenter(player);
|
||||
|
||||
EdgeCheck edgeCheck = checkEdge(player, event, edgeDistance);
|
||||
if (edgeCheck.diagonalRescue() && shouldOverwriteInput(player)) {
|
||||
overwriteTicks = Math.max(overwriteTicks, DIAGONAL_RESCUE_TICKS);
|
||||
}
|
||||
|
||||
if (overwriteTicks <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
overwriteTicks--;
|
||||
applyInputTowardsCenter(player, event);
|
||||
event.setJump(false);
|
||||
event.setSneak(true);
|
||||
event.setSprint(false);
|
||||
|
||||
updateSafeCenter(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean handleOnEdge(
|
||||
LocalPlayer player,
|
||||
MovementInputEvent event,
|
||||
double edgeDistance,
|
||||
RecoveryMode mode,
|
||||
int keepTicks,
|
||||
int requestedSneakTicks,
|
||||
boolean jump
|
||||
) {
|
||||
if (player == null || event == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
updateSafeCenter(player);
|
||||
|
||||
double distance = Math.min(horizontalSpeed(player), Math.max(0.0, edgeDistance));
|
||||
EdgeCheck edgeCheck = checkEdge(player, event, distance);
|
||||
if (edgeCheck.closeToEdge() && shouldOverwriteInput(player)) {
|
||||
overwriteTicks = Math.max(overwriteTicks, Math.max(1, keepTicks));
|
||||
sneakTicks = Math.max(sneakTicks, Math.max(0, requestedSneakTicks));
|
||||
}
|
||||
|
||||
boolean applied = false;
|
||||
if (overwriteTicks > 0) {
|
||||
overwriteTicks--;
|
||||
applyRecoveryInput(player, event, mode);
|
||||
event.setJump(jump);
|
||||
event.setSprint(false);
|
||||
applied = true;
|
||||
}
|
||||
|
||||
if (sneakTicks > 0) {
|
||||
sneakTicks--;
|
||||
event.setSneak(true);
|
||||
applied = true;
|
||||
}
|
||||
|
||||
updateSafeCenter(player);
|
||||
return applied;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
center = null;
|
||||
overwriteTicks = 0;
|
||||
sneakTicks = 0;
|
||||
}
|
||||
|
||||
private boolean shouldOverwriteInput(LocalPlayer player) {
|
||||
Vec3 center = this.center;
|
||||
if (center == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Vec3 horizontalVelocity = new Vec3(player.getDeltaMovement().x, 0.0, player.getDeltaMovement().z);
|
||||
if (horizontalVelocity.horizontalDistanceSqr() <= 0.02 * 0.02) {
|
||||
return true;
|
||||
}
|
||||
|
||||
double currentDistance = horizontalDistanceSquared(center, player.position());
|
||||
double nextDistance = horizontalDistanceSquared(center, player.position().add(horizontalVelocity));
|
||||
return nextDistance > currentDistance;
|
||||
}
|
||||
|
||||
private void applyRecoveryInput(LocalPlayer player, MovementInputEvent event, RecoveryMode mode) {
|
||||
RecoveryMode resolvedMode = mode != null ? mode : RecoveryMode.CENTER;
|
||||
if (resolvedMode == RecoveryMode.INVERT) {
|
||||
boolean forward = event.isForward();
|
||||
boolean backward = event.isBackward();
|
||||
boolean left = event.isLeft();
|
||||
boolean right = event.isRight();
|
||||
event.setForward(backward);
|
||||
event.setBackward(forward);
|
||||
event.setLeft(right);
|
||||
event.setRight(left);
|
||||
event.setJump(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (resolvedMode == RecoveryMode.STOP && horizontalSpeed(player) <= 0.05) {
|
||||
event.setForward(false);
|
||||
event.setBackward(false);
|
||||
event.setLeft(false);
|
||||
event.setRight(false);
|
||||
event.setJump(false);
|
||||
return;
|
||||
}
|
||||
|
||||
applyInputTowardsCenter(player, event);
|
||||
}
|
||||
|
||||
private void applyInputTowardsCenter(LocalPlayer player, MovementInputEvent event) {
|
||||
Vec3 center = this.center != null ? this.center : blockBottomCenter(player);
|
||||
Vec3 toCenter = center.subtract(player.position());
|
||||
Vec3 horizontal = new Vec3(toCenter.x, 0.0, toCenter.z);
|
||||
|
||||
if (horizontal.lengthSqr() < 0.015 * 0.015) {
|
||||
event.setForward(false);
|
||||
event.setBackward(false);
|
||||
event.setLeft(false);
|
||||
event.setRight(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3 direction = horizontal.normalize();
|
||||
double rad = Math.toRadians(player.getYRot());
|
||||
double sin = Math.sin(rad);
|
||||
double cos = Math.cos(rad);
|
||||
double localForward = direction.z * cos - direction.x * sin;
|
||||
double localSideways = direction.x * cos + direction.z * sin;
|
||||
|
||||
boolean forward = localForward > CENTER_DEAD_ANGLE_COS;
|
||||
boolean backward = localForward < -CENTER_DEAD_ANGLE_COS;
|
||||
boolean left = localSideways < -CENTER_DEAD_ANGLE_COS;
|
||||
boolean right = localSideways > CENTER_DEAD_ANGLE_COS;
|
||||
|
||||
if (!forward && !backward && !left && !right) {
|
||||
if (Math.abs(localForward) >= Math.abs(localSideways)) {
|
||||
forward = localForward > 0.0;
|
||||
backward = localForward < 0.0;
|
||||
} else {
|
||||
left = localSideways < 0.0;
|
||||
right = localSideways > 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
event.setForward(forward);
|
||||
event.setBackward(backward);
|
||||
event.setLeft(left);
|
||||
event.setRight(right);
|
||||
}
|
||||
|
||||
private void updateSafeCenter(LocalPlayer player) {
|
||||
Vec3 blockCenter = blockBottomCenter(player);
|
||||
if (!wouldBeCloseToFallOff(player, blockCenter)) {
|
||||
center = blockCenter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record EdgeCheck(boolean closeToEdge, boolean diagonalRescue, Vec3 movementDirection) {
|
||||
private static EdgeCheck empty() {
|
||||
return new EdgeCheck(false, false, Vec3.ZERO);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,204 @@
|
|||
package dev.loki.lovisual.util.entity;
|
||||
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import dev.loki.lovisual.events.impl.movement.MovementInputEvent;
|
||||
|
||||
/**
|
||||
* Stateful edge-recovery controller extracted from {@link EagleUtil}. Tracks a safe block center and
|
||||
* the remaining overwrite/sneak ticks, and rewrites {@link MovementInputEvent} input to rescue the
|
||||
* player from walking off an edge. The pure geometry detection it consumes still lives in
|
||||
* {@link EagleUtil}; behaviour is identical to the original nested implementation.
|
||||
*/
|
||||
public final class EdgeRecovery {
|
||||
private static final double CENTER_DEAD_ANGLE_COS = 0.34;
|
||||
private static final int DIAGONAL_RESCUE_TICKS = 2;
|
||||
|
||||
public enum RecoveryMode {
|
||||
STOP,
|
||||
INVERT,
|
||||
CENTER
|
||||
}
|
||||
|
||||
private Vec3 center;
|
||||
private int overwriteTicks;
|
||||
private int sneakTicks;
|
||||
|
||||
private static Vec3 blockBottomCenter(LocalPlayer player) {
|
||||
return new Vec3(
|
||||
player.blockPosition().getX() + 0.5,
|
||||
player.blockPosition().getY(),
|
||||
player.blockPosition().getZ() + 0.5
|
||||
);
|
||||
}
|
||||
|
||||
private static double horizontalDistanceSquared(Vec3 a, Vec3 b) {
|
||||
double x = a.x - b.x;
|
||||
double z = a.z - b.z;
|
||||
return x * x + z * z;
|
||||
}
|
||||
|
||||
public boolean handleDiagonalRescue(LocalPlayer player, MovementInputEvent event, double edgeDistance) {
|
||||
if (player == null || event == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
updateSafeCenter(player);
|
||||
|
||||
EagleUtil.EdgeCheck edgeCheck = EagleUtil.checkEdge(player, event, edgeDistance);
|
||||
if (edgeCheck.diagonalRescue() && shouldOverwriteInput(player)) {
|
||||
overwriteTicks = Math.max(overwriteTicks, DIAGONAL_RESCUE_TICKS);
|
||||
}
|
||||
|
||||
if (overwriteTicks <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
overwriteTicks--;
|
||||
applyInputTowardsCenter(player, event);
|
||||
event.setJump(false);
|
||||
event.setSneak(true);
|
||||
event.setSprint(false);
|
||||
|
||||
updateSafeCenter(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean handleOnEdge(
|
||||
LocalPlayer player,
|
||||
MovementInputEvent event,
|
||||
double edgeDistance,
|
||||
RecoveryMode mode,
|
||||
int keepTicks,
|
||||
int requestedSneakTicks,
|
||||
boolean jump
|
||||
) {
|
||||
if (player == null || event == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
updateSafeCenter(player);
|
||||
|
||||
double distance = Math.min(EagleUtil.horizontalSpeed(player), Math.max(0.0, edgeDistance));
|
||||
EagleUtil.EdgeCheck edgeCheck = EagleUtil.checkEdge(player, event, distance);
|
||||
if (edgeCheck.closeToEdge() && shouldOverwriteInput(player)) {
|
||||
overwriteTicks = Math.max(overwriteTicks, Math.max(1, keepTicks));
|
||||
sneakTicks = Math.max(sneakTicks, Math.max(0, requestedSneakTicks));
|
||||
}
|
||||
|
||||
boolean applied = false;
|
||||
if (overwriteTicks > 0) {
|
||||
overwriteTicks--;
|
||||
applyRecoveryInput(player, event, mode);
|
||||
event.setJump(jump);
|
||||
event.setSprint(false);
|
||||
applied = true;
|
||||
}
|
||||
|
||||
if (sneakTicks > 0) {
|
||||
sneakTicks--;
|
||||
event.setSneak(true);
|
||||
applied = true;
|
||||
}
|
||||
|
||||
updateSafeCenter(player);
|
||||
return applied;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
center = null;
|
||||
overwriteTicks = 0;
|
||||
sneakTicks = 0;
|
||||
}
|
||||
|
||||
private boolean shouldOverwriteInput(LocalPlayer player) {
|
||||
Vec3 center = this.center;
|
||||
if (center == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Vec3 horizontalVelocity = new Vec3(player.getDeltaMovement().x, 0.0, player.getDeltaMovement().z);
|
||||
if (horizontalVelocity.horizontalDistanceSqr() <= 0.02 * 0.02) {
|
||||
return true;
|
||||
}
|
||||
|
||||
double currentDistance = horizontalDistanceSquared(center, player.position());
|
||||
double nextDistance = horizontalDistanceSquared(center, player.position().add(horizontalVelocity));
|
||||
return nextDistance > currentDistance;
|
||||
}
|
||||
|
||||
private void applyRecoveryInput(LocalPlayer player, MovementInputEvent event, RecoveryMode mode) {
|
||||
RecoveryMode resolvedMode = mode != null ? mode : RecoveryMode.CENTER;
|
||||
if (resolvedMode == RecoveryMode.INVERT) {
|
||||
boolean forward = event.isForward();
|
||||
boolean backward = event.isBackward();
|
||||
boolean left = event.isLeft();
|
||||
boolean right = event.isRight();
|
||||
event.setForward(backward);
|
||||
event.setBackward(forward);
|
||||
event.setLeft(right);
|
||||
event.setRight(left);
|
||||
event.setJump(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (resolvedMode == RecoveryMode.STOP && EagleUtil.horizontalSpeed(player) <= 0.05) {
|
||||
event.setForward(false);
|
||||
event.setBackward(false);
|
||||
event.setLeft(false);
|
||||
event.setRight(false);
|
||||
event.setJump(false);
|
||||
return;
|
||||
}
|
||||
|
||||
applyInputTowardsCenter(player, event);
|
||||
}
|
||||
|
||||
private void applyInputTowardsCenter(LocalPlayer player, MovementInputEvent event) {
|
||||
Vec3 center = this.center != null ? this.center : blockBottomCenter(player);
|
||||
Vec3 toCenter = center.subtract(player.position());
|
||||
Vec3 horizontal = new Vec3(toCenter.x, 0.0, toCenter.z);
|
||||
|
||||
if (horizontal.lengthSqr() < 0.015 * 0.015) {
|
||||
event.setForward(false);
|
||||
event.setBackward(false);
|
||||
event.setLeft(false);
|
||||
event.setRight(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3 direction = horizontal.normalize();
|
||||
double rad = Math.toRadians(player.getYRot());
|
||||
double sin = Math.sin(rad);
|
||||
double cos = Math.cos(rad);
|
||||
double localForward = direction.z * cos - direction.x * sin;
|
||||
double localSideways = direction.x * cos + direction.z * sin;
|
||||
|
||||
boolean forward = localForward > CENTER_DEAD_ANGLE_COS;
|
||||
boolean backward = localForward < -CENTER_DEAD_ANGLE_COS;
|
||||
boolean left = localSideways < -CENTER_DEAD_ANGLE_COS;
|
||||
boolean right = localSideways > CENTER_DEAD_ANGLE_COS;
|
||||
|
||||
if (!forward && !backward && !left && !right) {
|
||||
if (Math.abs(localForward) >= Math.abs(localSideways)) {
|
||||
forward = localForward > 0.0;
|
||||
backward = localForward < 0.0;
|
||||
} else {
|
||||
left = localSideways < 0.0;
|
||||
right = localSideways > 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
event.setForward(forward);
|
||||
event.setBackward(backward);
|
||||
event.setLeft(left);
|
||||
event.setRight(right);
|
||||
}
|
||||
|
||||
private void updateSafeCenter(LocalPlayer player) {
|
||||
Vec3 blockCenter = blockBottomCenter(player);
|
||||
if (!EagleUtil.wouldBeCloseToFallOff(player, blockCenter)) {
|
||||
center = blockCenter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.entity;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.entity.simulation;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.entity.simulation;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.entity.simulation;
|
||||
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.entity.simulation;
|
||||
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.input;
|
||||
|
||||
import dev.loki.lovisual.util.screen.ClientScreen;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.input;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.item.enchant;
|
||||
|
||||
import net.minecraft.client.resources.language.I18n;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.item.enchant;
|
||||
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.item.enchant;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.item.enchant;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.item.food;
|
||||
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.item.food;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.item.rarity;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.item.rarity;
|
||||
|
||||
import net.minecraft.world.item.Rarity;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.item.rarity;
|
||||
import dev.loki.lovisual.features.module.modules.visuals.esp.overlay.DropESP;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.logging;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.logging;
|
||||
|
||||
public enum DebugMode {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.logging;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
/*
|
||||
* This file is part of the LoVisual Client distribution.
|
||||
* Copyright (c) 2026 loki5512344.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.0.
|
||||
*/
|
||||
|
||||
package dev.loki.lovisual.util.map;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue