chore(history): squash 59 commit(s) from 2026-09-23

- refactor(hud/weather/render): Scoreboard 931→240 + Rain 903→159 + UiMeshGeometry 956→99 (8.5.2)
- refactor(chams): Chams 985 → 129 + 4×≤195 (8.5.2)
- refactor(module): Module 1031 → 139 + 4×≤134 (8.5.2)
- refactor(tooltips): BetterTooltips 960 → 181 + 4×≤199 (8.5.2)
- refactor(clickgui): ClickGuiPickerState 970→166 + ModulesMenuScreen 966→145 (8.5.2)
- refactor(clickgui): CombatProtocolHeuristicsEditorState 932→79 + 4×≤192 (8.5.2)
- refactor(hud): CompactHudStatModel 894 → 125 + 4×≤175 (8.5.2)
- refactor(iris): ShaderPatchCompiler 843→66 + 4×≤174 (8.5.2)
- refactor(tab): CustomTabList 834→136 + 4×≤166 (8.5.2)
- refactor(relations): OnlineRelationPlayerPickerComponent 837→74 + 4×≤192 (8.5.2)
- refactor(hits): HitEffect 770→120 + 4×≤176 (8.5.2)
- refactor(predict): Predictions 815→150 + 4×≤195 (8.5.2)
- refactor(config): ConfigProfilesComponent 799→125 + 4×≤195 (8.5.2)
- refactor(sim): PlayerMovementSimulation 757→157 + 4×≤194 (8.5.2)
- refactor(predict): ProjectilePuncher 747→104 + 3×≤134 (8.5.2)
- refactor(crosshair): Crosshair 743→143 + 4×≤167 (8.5.2)
- refactor(mediaplayer): MediaPlayer 743→174 + 4×≤196 (8.5.2)
- refactor(hud): Itemizer 699→193 + Cooldowns 707→151 (8.5.2)
- refactor(hud): Potions 617→176 + 4×≤166 (8.5.2)
- refactor(hud): Admins 702→118 + 4×≤138 (8.5.2)
- refactor(hud): Keybinds 611→157 + 4×≤160 (8.5.2)
- refactor(hud): ModuleList 499→181 + 3×≤150 (8.5.2)
- refactor(hud): Radar 392→161 + 2×≤124 (8.5.2)
- refactor(hud): Fps 309→168 + 3×≤107 (8.5.2)
- refactor(hud): Memory 304→151 + 3×≤144 (8.5.2)
- refactor(hud): Tps 339→154 + 3×≤143 (8.5.2)
- refactor(hud): Ping 309→145 + 3×≤125 (8.5.2)
- refactor(hud): SpeedBps 334→156 + 3×≤142 (8.5.2)
- refactor(hud): GameTime 314→150 + 3×≤127 (8.5.2)
- refactor(hud): SystemTime 300→136 + 3×≤130 (8.5.2)
- refactor(hud): Coordinates 337→174 + 2×≤172 (8.5.2)
- refactor(hud): Armor 324→162 + 2×≤148 (8.5.2)
- refactor(hud): Inventory 476→153 + 3×≤181 (8.5.2)
- docs(todo): обновлён 8.5.2 — отмечены готовые гиганты (BetterButtons/InventorySwap/Svg/Темы/WorldParticles/Module/Chams и хвост)
- docs(api): папка combatant-client-26.2/docs + addons.md (API можно ломать при рефакторе)
- refactor(visuals): BlockHighlight 692→271 + 4×≤200 (8.5.2)
- refactor(mixins): GameRendererMixin 830→344 (хуки) + 4 хелпера (8.5.2)
- refactor(visuals): WorldParticles 821→260 + 6×≤200, режимы добиты (8.5.2)
- docs(todo): 8.5.2 — WorldParticles/GameRendererMixin/BlockHighlight отмечены ГОТОВО
- refactor(render): MeshBuilder 738→447 (фасад write-API) + 3 хелпера, FrameStats снесён (8.5.2)
- docs(todo): Фаза 10 — дизайн платформы (аккаунты/конфиги/аватарки), backlog RPC-чата
- docs(todo): Подсистема 3 — Аддоны 2.0 (скрипты/версии) + витрина аддонов + админка
- docs(todo): Подсистема 2 — RPC-чат/друзья/виджеты-телеметрия + рейт-лимиты, доп. правки Подсистемы 3
- chore: переименование combatant-client-26.2 -> mod, добавлены backend/ и frontend/
- docs(backend): implementation plan for accounts-service (Подсистема 1, часть 1)
- chore: пересоздать backend/frontend через cargo new и bun create vite + tailwind; убрать таблицу компонентов из TODO.md
- docs(backend): edition 2024 в плане вместо 2021
- chore: обновить версии до реально актуальных (проверено компиляцией)
- docs: правила платформы (лимит 250 строк, антипаттерны backend/frontend по итогам ресёрча) + frontend/ARCHITECTURE.md
- docs: добавить правило ≤4 файла на папку в правила платформы (backend/frontend)
- docs: commit messages in English from now on
- chore: gitignore .superpowers/ scratch directory
- docs: commit messages in English from now on (mod)
- feat(backend): scaffold accounts-service with health check
- chore(backend): remove target/ build artifacts from git, add gitignore
- chore: track docs/ in git (was accidentally gitignored, never committed)
- chore(backend): convert to Cargo workspace, plan full microservice layout
- feat(backend): accounts/avatars/device_links schema + migration
- feat(backend): argon2id password hashing
This commit is contained in:
loki5512344 2026-09-23 22:38:08 +02:00
parent ec10395511
commit 9d08fa910a
2239 changed files with 35265 additions and 28110 deletions

View file

@ -0,0 +1,25 @@
/*
* 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.events.impl.entity;
import lombok.Getter;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import dev.loki.lovisual.events.Event;
@Getter
public final class AttackEntityEvent extends Event {
private final Player player;
private final Entity target;
public AttackEntityEvent(Player player, Entity target) {
this.player = player;
this.target = target;
}
}

View file

@ -0,0 +1,30 @@
/*
* 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.events.impl.entity;
import lombok.Getter;
import lombok.Setter;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.HitResult;
import dev.loki.lovisual.events.Event;
@Getter
public final class CrosshairTargetUpdateEvent extends Event {
private final float tickDelta;
@Setter
private HitResult hitResult;
@Setter
private Entity targetedEntity;
public CrosshairTargetUpdateEvent(float tickDelta, HitResult hitResult, Entity targetedEntity) {
this.tickDelta = tickDelta;
this.hitResult = hitResult;
this.targetedEntity = targetedEntity;
}
}

View file

@ -0,0 +1,32 @@
/*
* 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.events.impl.entity;
import net.minecraft.world.entity.LivingEntity;
import dev.loki.lovisual.events.Event;
import dev.loki.lovisual.util.target.TargetManager;
/**
* Fired when the centralized target changes.
*/
public class EventTargetChanged extends Event {
public final LivingEntity previous;
public final TargetManager.Source previousSource;
public final LivingEntity current;
public final TargetManager.Source currentSource;
public EventTargetChanged(LivingEntity previous,
TargetManager.Source previousSource,
LivingEntity current,
TargetManager.Source currentSource) {
this.previous = previous;
this.previousSource = previousSource;
this.current = current;
this.currentSource = currentSource;
}
}

View file

@ -0,0 +1,24 @@
/*
* 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.events.impl.entity;
import lombok.Getter;
import lombok.Setter;
import net.minecraft.world.phys.Vec3;
import dev.loki.lovisual.events.Event;
@Setter
@Getter
public final class FireworkEvent extends Event {
private Vec3 vector;
public FireworkEvent(Vec3 vector) {
this.vector = vector;
}
}

View file

@ -0,0 +1,24 @@
/*
* 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.events.impl.input;
import lombok.Getter;
import net.minecraft.client.input.KeyEvent;
import dev.loki.lovisual.events.Event;
@Getter
public final class KeyInputEvent extends Event {
private final int action;
private final KeyEvent input;
public KeyInputEvent(int action, KeyEvent input) {
this.action = action;
this.input = input;
}
}

View file

@ -0,0 +1,27 @@
/*
* 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.events.impl.input;
import lombok.Getter;
import lombok.Setter;
import net.minecraft.client.KeyMapping;
import dev.loki.lovisual.events.Event;
@Getter
public final class KeybindIsPressedEvent extends Event {
private final KeyMapping keyBinding;
@Setter
private boolean pressed;
public KeybindIsPressedEvent(KeyMapping keyBinding, boolean pressed) {
this.keyBinding = keyBinding;
this.pressed = pressed;
}
}

View file

@ -0,0 +1,28 @@
/*
* 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.events.impl.input;
import dev.loki.lovisual.events.Event;
import lombok.Getter;
/**
* Rotation lifecycle event fired each tick in two phases.
*/
@Getter
public final class RotationUpdateEvent extends Event {
private final Type type;
public RotationUpdateEvent(Type type) {
this.type = type == null ? Type.PRE : type;
}
public enum Type {
PRE,
POST
}
}

View file

@ -0,0 +1,43 @@
/*
* 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.events.impl.input;
import dev.loki.lovisual.events.Event;
import lombok.Getter;
import lombok.Setter;
public class SprintControlEvent extends Event {
@Getter
private final float forward;
@Getter
private final float sideways;
@Getter
private final Source source;
@Setter
private boolean sprint;
public SprintControlEvent(float forward, float sideways, boolean sprint, Source source) {
this.forward = forward;
this.sideways = sideways;
this.sprint = sprint;
this.source = source;
}
public boolean isMoving() {
return forward != 0.0f || sideways != 0.0f;
}
public boolean shouldSprint() {
return sprint;
}
public enum Source {
INPUT,
MOVEMENT_TICK,
NETWORK
}
}

View file

@ -0,0 +1,39 @@
/*
* 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.events.impl.movement;
import lombok.Getter;
import lombok.Setter;
import net.minecraft.world.entity.player.Input;
import dev.loki.lovisual.events.Event;
@Setter
@Getter
public final class MovementInputEvent extends Event {
private boolean forward;
private boolean backward;
private boolean left;
private boolean right;
private boolean jump;
private boolean sneak;
private boolean sprint;
public MovementInputEvent(Input input) {
this.forward = input.forward();
this.backward = input.backward();
this.left = input.left();
this.right = input.right();
this.jump = input.jump();
this.sneak = input.shift();
this.sprint = input.sprint();
}
public Input toPlayerInput() {
return new Input(forward, backward, left, right, jump, sneak, sprint);
}
}

View file

@ -0,0 +1,19 @@
/*
* 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.events.impl.movement;
import dev.loki.lovisual.events.Event;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class PlayerSafeWalkEvent extends Event {
private boolean safeWalk;
}

View file

@ -0,0 +1,23 @@
/*
* 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.events.impl.movement;
import dev.loki.lovisual.events.Event;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public final class PlayerStepEvent extends Event {
private float height;
public PlayerStepEvent(float height) {
this.height = height;
}
}

View file

@ -0,0 +1,22 @@
/*
* 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.events.impl.movement;
import lombok.Getter;
import net.minecraft.world.phys.Vec3;
import dev.loki.lovisual.events.Event;
@Getter
public final class PlayerStepSuccessEvent extends Event {
private final Vec3 adjustedVec;
public PlayerStepSuccessEvent(Vec3 adjustedVec) {
this.adjustedVec = adjustedVec;
}
}

View file

@ -0,0 +1,39 @@
/*
* 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.events.impl.network;
import lombok.Getter;
import net.minecraft.network.protocol.Packet;
import dev.loki.lovisual.events.Event;
import dev.loki.lovisual.util.network.control.BlinkManager;
import dev.loki.lovisual.util.network.packet.TransferOrigin;
public class BlinkPacketEvent extends Event {
private final Packet<?> packet;
@Getter
private final TransferOrigin origin;
@Getter
private BlinkManager.Action action = BlinkManager.Action.FLUSH;
public BlinkPacketEvent(Packet<?> packet, TransferOrigin origin) {
this.packet = packet;
this.origin = origin;
}
@SuppressWarnings("unchecked")
public <T extends Packet<?>> T getPacket() {
return (T) packet;
}
public void setAction(BlinkManager.Action action) {
if (action == null || this.action == action || this.action.getPriority() >= action.getPriority()) {
return;
}
this.action = action;
}
}

View file

@ -0,0 +1,15 @@
/*
* 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.events.impl.network;
import dev.loki.lovisual.events.Event;
public class EventPostSync extends Event {
public EventPostSync() {
}
}

View file

@ -0,0 +1,69 @@
/*
* 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.events.impl.network;
import dev.loki.lovisual.events.Event;
import lombok.Getter;
public class EventSync extends Event {
@Getter
private final float originalYaw;
@Getter
private final float originalPitch;
@Getter
private float yaw;
@Getter
private float pitch;
private boolean rotationOverride;
@Getter
private boolean silentRotation;
@Getter
private Runnable postAction;
public EventSync(float yaw, float pitch) {
this.originalYaw = yaw;
this.originalPitch = pitch;
this.yaw = yaw;
this.pitch = pitch;
}
public void setYaw(float yaw) {
this.yaw = yaw;
this.rotationOverride = true;
}
public void setPitch(float pitch) {
this.pitch = pitch;
this.rotationOverride = true;
}
public void setRotation(float yaw, float pitch, boolean silent) {
this.yaw = yaw;
this.pitch = pitch;
this.rotationOverride = true;
this.silentRotation = silent;
}
public boolean hasRotationOverride() {
return rotationOverride;
}
public void addPostAction(Runnable r) {
if (r == null) return;
if (postAction == null) {
postAction = r;
} else {
Runnable prev = postAction;
postAction = () -> {
prev.run();
r.run();
};
}
}
}

View file

@ -0,0 +1,76 @@
/*
* 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.events.impl.network;
import lombok.Getter;
import net.minecraft.network.protocol.Packet;
import dev.loki.lovisual.events.Event;
import dev.loki.lovisual.util.network.packet.TransferOrigin;
public class PacketEvent extends Event {
private final Packet<?> packet;
@Getter
private final TransferOrigin origin;
@Getter
private final boolean original;
public PacketEvent(Packet<?> packet) {
this(packet, null, true);
}
public PacketEvent(Packet<?> packet, TransferOrigin origin, boolean original) {
this.packet = packet;
this.origin = origin;
this.original = original;
}
@SuppressWarnings("unchecked")
public <T extends Packet<?>> T getPacket() {
return (T) this.packet;
}
public static class Send extends PacketEvent {
public Send(Packet<?> packet) {
super(packet, TransferOrigin.OUTGOING, true);
}
public Send(Packet<?> packet, boolean original) {
super(packet, TransferOrigin.OUTGOING, original);
}
}
public static class Receive extends PacketEvent {
public Receive(Packet<?> packet) {
super(packet, TransferOrigin.INCOMING, true);
}
public Receive(Packet<?> packet, boolean original) {
super(packet, TransferOrigin.INCOMING, original);
}
}
public static class SendPost extends PacketEvent {
public SendPost(Packet<?> packet) {
super(packet, TransferOrigin.OUTGOING, true);
}
@SuppressWarnings("unused")
public SendPost(Packet<?> packet, boolean original) {
super(packet, TransferOrigin.OUTGOING, original);
}
}
public static class ReceivePost extends PacketEvent {
public ReceivePost(Packet<?> packet) {
super(packet, TransferOrigin.INCOMING, true);
}
@SuppressWarnings("unused")
public ReceivePost(Packet<?> packet, boolean original) {
super(packet, TransferOrigin.INCOMING, original);
}
}
}

View file

@ -0,0 +1,94 @@
/*
* 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.events.impl.player;
import dev.loki.lovisual.config.definition.SettingDef;
import dev.loki.lovisual.config.definition.SettingOwner;
import dev.loki.lovisual.events.Event;
import dev.loki.lovisual.features.gui.clickgui.settings.core.Setting;
import dev.loki.lovisual.features.gui.clickgui.settings.core.SettingFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Collects setting-backed i18n keys after language resources are loaded.
*/
public final class I18nPreflightCollectEvent extends Event {
private final String reason;
private final ArrayList<Entry> entries = new ArrayList<>();
public I18nPreflightCollectEvent(String reason) {
this.reason = reason != null && !reason.isBlank() ? reason : "i18n preflight";
}
public String reason() {
return reason;
}
public I18nPreflightCollectEvent setting(Setting setting) {
return setting("settings", setting);
}
public I18nPreflightCollectEvent setting(String path, Setting setting) {
if (setting != null) {
entries.add(new Entry(normalizePath(path), setting));
}
return this;
}
public I18nPreflightCollectEvent settings(Iterable<? extends Setting> values) {
return settings("settings", values);
}
public I18nPreflightCollectEvent settings(String path, Iterable<? extends Setting> values) {
if (values == null) return this;
for (Setting setting : values) {
setting(path, setting);
}
return this;
}
public I18nPreflightCollectEvent settingDefs(SettingOwner owner, Iterable<SettingDef> defs) {
return settingDefs(owner != null ? owner.name() : "settings", owner, defs);
}
public I18nPreflightCollectEvent settingDefs(String path, SettingOwner owner, Iterable<SettingDef> defs) {
if (owner == null || defs == null) return this;
for (SettingDef def : defs) {
Setting setting = SettingFactory.fromDef(def);
if (setting == null) continue;
setting.setParent(owner);
setting(path, setting);
}
return this;
}
public List<Entry> entries() {
return Collections.unmodifiableList(entries);
}
public boolean isEmpty() {
return entries.isEmpty();
}
private static String normalizePath(String path) {
if (path == null || path.isBlank()) return "settings";
String normalized = path.trim().replace('\\', '/');
while (normalized.contains("//")) {
normalized = normalized.replace("//", "/");
}
if (normalized.startsWith("/")) normalized = normalized.substring(1);
if (normalized.endsWith("/")) normalized = normalized.substring(0, normalized.length() - 1);
return normalized.isBlank() ? "settings" : normalized;
}
public record Entry(String path, Setting setting) {
}
}

View file

@ -0,0 +1,25 @@
/*
* 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.events.impl.player;
import dev.loki.lovisual.events.Event;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public final class PlayerJumpEvent extends Event {
private float yaw;
private float motion;
public PlayerJumpEvent(float yaw, float motion) {
this.yaw = yaw;
this.motion = motion;
}
}

View file

@ -0,0 +1,27 @@
/*
* 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.events.impl.player;
import lombok.Getter;
import lombok.Setter;
import net.minecraft.world.entity.MoverType;
import net.minecraft.world.phys.Vec3;
import dev.loki.lovisual.events.Event;
@Getter
public class PlayerMoveEvent extends Event {
private final MoverType type;
@Setter
private Vec3 movement;
public PlayerMoveEvent(MoverType type, Vec3 movement) {
this.type = type;
this.movement = movement;
}
}

View file

@ -0,0 +1,19 @@
/*
* 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.events.impl.player;
import dev.loki.lovisual.events.Event;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class PostPlayerUpdateEvent extends Event {
private int iterations;
}

View file

@ -0,0 +1,26 @@
/*
* 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.events.impl.pvp;
import dev.loki.lovisual.events.Event;
import java.util.List;
public class CombatProtocolBossbarEvent extends Event {
public final List<String> names;
public final long timeMs;
public CombatProtocolBossbarEvent(List<String> names) {
this(names, System.currentTimeMillis());
}
public CombatProtocolBossbarEvent(List<String> names, long timeMs) {
this.names = names == null ? List.of() : List.copyOf(names);
this.timeMs = timeMs;
}
}

View file

@ -0,0 +1,33 @@
/*
* 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.events.impl.pvp;
import dev.loki.lovisual.events.Event;
/**
* Fired when a PvP-related chat or game message is received.
*/
public class PvpChatEvent extends Event {
public final String message;
public final Source source;
public final long timeMs;
public PvpChatEvent(String message, Source source) {
this(message, source, System.currentTimeMillis());
}
public PvpChatEvent(String message, Source source, long timeMs) {
this.message = message;
this.source = source;
this.timeMs = timeMs;
}
public enum Source {
GAME_MESSAGE,
CHAT_MESSAGE
}
}

View file

@ -0,0 +1,30 @@
/*
* 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.events.impl.pvp;
import net.minecraft.network.chat.Component;
import dev.loki.lovisual.events.Event;
/**
* Fired when an in-game HUD overlay message is shown (action bar).
*/
public class PvpOverlayEvent extends Event {
public final Component message;
public final boolean tinted;
public final long timeMs;
public PvpOverlayEvent(Component message, boolean tinted) {
this(message, tinted, System.currentTimeMillis());
}
public PvpOverlayEvent(Component message, boolean tinted, long timeMs) {
this.message = message;
this.tinted = tinted;
this.timeMs = timeMs;
}
}

View file

@ -0,0 +1,35 @@
/*
* 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.events.impl.pvp;
import dev.loki.lovisual.events.Event;
/**
* Fired when the server updates tab-list header/footer text.
*/
public class PvpTabEvent extends Event {
public final String header;
public final String footer;
public final long timeMs;
public PvpTabEvent(String header, String footer) {
this(header, footer, System.currentTimeMillis());
}
public PvpTabEvent(String header, String footer, long timeMs) {
this.header = header == null ? "" : header;
this.footer = footer == null ? "" : footer;
this.timeMs = timeMs;
}
public String combinedText() {
if (header.isBlank()) return footer;
if (footer.isBlank()) return header;
return header + "\n" + footer;
}
}

View file

@ -0,0 +1,16 @@
/*
* 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.events.impl.render;
import dev.loki.lovisual.events.Event;
/**
* Fired at the start of each client tick.
*/
public final class GameTickEvent extends Event {
}

View file

@ -0,0 +1,34 @@
/*
* 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.events.impl.render;
import dev.loki.lovisual.events.Event;
import lombok.Getter;
import lombok.Setter;
@Getter
public class LightmapEvent extends Event {
private final float originalAmbient;
@Setter
private float ambientLight;
public LightmapEvent(float ambientLight) {
this.originalAmbient = ambientLight;
this.ambientLight = ambientLight;
}
public void raiseAmbientLight(float ambientLight) {
if (ambientLight > this.ambientLight) {
this.ambientLight = ambientLight;
}
}
public boolean isModified() {
return Math.abs(ambientLight - originalAmbient) > 1.0e-4f;
}
}

View file

@ -0,0 +1,82 @@
/*
* 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.events.impl.render;
import lombok.Getter;
import net.minecraft.client.renderer.state.LightmapRenderState;
import net.minecraft.util.Mth;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import dev.loki.lovisual.events.Event;
import dev.loki.lovisual.features.module.modules.visuals.player.FullBright;
public class LightmapModifyEvent extends Event {
private static final float EPSILON = 1.0e-4f;
private final LightmapRenderState state;
private final float originalBrightness;
@Getter
private boolean modified;
public LightmapModifyEvent(LightmapRenderState state) {
this.state = state;
this.originalBrightness = state != null ? state.brightness : 0.0f;
}
public LightmapRenderState state() {
return state;
}
public float originalBrightness() {
return originalBrightness;
}
public void raiseMinimumLight(float minLight) {
if (state == null) return;
float strength = Mth.clamp(minLight, 0.0f, 1.0f);
if (strength <= EPSILON) return;
state.needsUpdate = true;
// Do not emulate FullBright by forcing brightness/night vision to 1.0.
// In the 1.21+ UBO lightmap path that behaves like global exposure and blows out the scene.
float exposureFloor = 0.08f + 0.18f * strength;
state.brightness = Math.max(state.brightness, exposureFloor);
state.nightVisionEffectIntensity = Math.max(state.nightVisionEffectIntensity, 0.10f * strength);
// Lift the generated lightmap itself, but keep vanilla color response instead of whitening it.
state.skyFactor = Math.max(state.skyFactor, 0.55f + 0.35f * strength);
state.blockFactor = Math.max(state.blockFactor, 1.4f + 0.25f * strength);
// FullBright must not be attenuated by darkness/boss-world darkening.
float attenuation = 1.0f - strength;
state.darknessEffectScale *= attenuation;
state.bossOverlayWorldDarkening *= attenuation;
float colorFloor = 0.10f + 0.28f * strength;
state.blockLightTint = raiseColorFloor(state.blockLightTint, colorFloor);
state.skyLightColor = raiseColorFloor(state.skyLightColor, colorFloor);
state.ambientColor = raiseColorFloor(state.ambientColor, colorFloor);
state.nightVisionColor = raiseColorFloor(state.nightVisionColor, colorFloor);
modified = true;
}
private static Vector3fc raiseColorFloor(Vector3fc color, float floor) {
float min = Mth.clamp(floor, 0.0f, 1.0f);
if (color == null) {
return new Vector3f(min, min, min);
}
return new Vector3f(
Math.max(color.x(), min),
Math.max(color.y(), min),
Math.max(color.z(), min)
);
}
}

View file

@ -0,0 +1,81 @@
/*
* 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.events.impl.render;
import dev.loki.lovisual.events.Event;
import dev.loki.lovisual.render.engine.svg.parser.SvgRegistry;
import dev.loki.lovisual.render.engine.text.font.info.FontInfo;
import net.minecraft.resources.Identifier;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Collects render resources that are known to be needed before the first GUI/HUD draw.
* Producers should add only resources implied by current runtime state/config: enabled
* modules, enabled HUD elements, and UI surfaces that can be opened immediately.
*/
public final class RenderPrewarmCollectEvent extends Event {
private final String reason;
private final LinkedHashSet<FontInfo> fonts = new LinkedHashSet<>();
private final LinkedHashSet<Identifier> svgMsdfIcons = new LinkedHashSet<>();
public RenderPrewarmCollectEvent(String reason) {
this.reason = reason != null ? reason : "render prewarm";
}
public String reason() {
return reason;
}
public RenderPrewarmCollectEvent font(String family) {
return font(family, FontInfo.Type.Regular);
}
public RenderPrewarmCollectEvent font(String family, FontInfo.Type type) {
if (family == null || family.isBlank()) return this;
fonts.add(new FontInfo(family.trim(), type != null ? type : FontInfo.Type.Regular));
return this;
}
public RenderPrewarmCollectEvent font(@Nullable FontInfo info) {
if (info != null && info.family() != null && !info.family().isBlank()) {
fonts.add(info);
}
return this;
}
public RenderPrewarmCollectEvent svg(String nameOrPath) {
Identifier id = SvgRegistry.resolve(nameOrPath);
if (id != null) {
svgMsdfIcons.add(id);
}
return this;
}
public RenderPrewarmCollectEvent svg(@Nullable Identifier id) {
if (id != null) {
svgMsdfIcons.add(id);
}
return this;
}
public Set<FontInfo> fonts() {
return Collections.unmodifiableSet(fonts);
}
public Set<Identifier> svgMsdfIcons() {
return Collections.unmodifiableSet(svgMsdfIcons);
}
public boolean isEmpty() {
return fonts.isEmpty() && svgMsdfIcons.isEmpty();
}
}

View file

@ -0,0 +1,41 @@
/*
* 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.events.impl.render.particles;
import net.minecraft.core.particles.ParticleOptions;
import dev.loki.lovisual.events.Event;
public class ParticleSpawnEvent extends Event {
private final ParticleOptions options;
private final double x;
private final double y;
private final double z;
public ParticleSpawnEvent(ParticleOptions options, double x, double y, double z) {
this.options = options;
this.x = x;
this.y = y;
this.z = z;
}
public ParticleOptions options() {
return options;
}
public double x() {
return x;
}
public double y() {
return y;
}
public double z() {
return z;
}
}

View file

@ -0,0 +1,22 @@
/*
* 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.events.impl.world;
import lombok.Getter;
import net.minecraft.core.BlockPos;
import dev.loki.lovisual.events.Event;
@Getter
public class EventBreakBlock extends Event {
private final BlockPos pos;
public EventBreakBlock(BlockPos pos) {
this.pos = pos;
}
}

View file

@ -0,0 +1,27 @@
/*
* 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.events.impl.world;
import lombok.Getter;
import lombok.Setter;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
import dev.loki.lovisual.events.Event;
@Getter
public class EventCollision extends Event {
private final BlockPos pos;
@Setter
private BlockState state;
public EventCollision(BlockState state, BlockPos pos) {
this.state = state;
this.pos = pos;
}
}

View file

@ -0,0 +1,23 @@
/*
* 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.events.impl.world;
import dev.loki.lovisual.events.Event;
import lombok.Getter;
@Getter
public class EventPushOutOfBlocks extends Event {
private final double x;
private final double z;
public EventPushOutOfBlocks(double x, double z) {
this.x = x;
this.z = z;
}
}

View file

@ -0,0 +1,31 @@
/*
* 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.events.impl.world;
import lombok.Getter;
import lombok.Setter;
import net.minecraft.world.phys.Vec3;
import dev.loki.lovisual.events.Event;
@Getter
public class PlayerVelocityStrafe extends Event {
private final Vec3 movementInput;
private final float speed;
private final float yaw;
@Setter
private Vec3 velocity;
public PlayerVelocityStrafe(Vec3 movementInput, float speed, float yaw, Vec3 velocity) {
this.movementInput = movementInput;
this.speed = speed;
this.yaw = yaw;
this.velocity = velocity;
}
}