- feat: Фаза 1 ребрендинг combatant → lovisual + восстановление config - refactor: Фаза 2 — выкинуть Runtime/JarReplacement, заменить на Lifecycle - refactor: Фаза 3.5 — удалить читерские модули, ESP под легит - refactor: Фаза 3 — разбить Renderer2D (3379→2150 фасад + 14 хелперов ≤200) - refactor: Фаза 3 — разбить BetterChatRenderer (2870→210 фасад + 21 хелпер ≤200) - refactor: Фаза 3 — разбить UnifiedSettingRenderer (2798→208 фасад + 24 хелпера ≤200) - refactor: Фаза 3 — разбить ClickGuiRenderer (1887→542 фасад + 15 хелперов ≤200) - refactor: Фаза 3 — разбить NameTags (1791→438 фасад + 11 хелперов ≤200) - refactor: Фаза 3 — разбить TargetHud (1655→340 фасад + 11 хелперов ≤200) - refactor: Фаза 3 — разбить ESP (1538→269 фасад + 11 хелперов ≤200)
171 lines
6.7 KiB
Java
171 lines
6.7 KiB
Java
/*
|
|
* This file is part of the LoVisual Client distribution.
|
|
* Copyright (c) 2026 pivosos2007.
|
|
*
|
|
* Licensed under the GNU General Public License v3.0.
|
|
*/
|
|
|
|
package dev.loki.lovisual.addon;
|
|
|
|
import dev.loki.lovisual.api.v0.module.LoVisualModuleExtension;
|
|
import dev.loki.lovisual.features.module.Module;
|
|
import dev.loki.lovisual.features.module.ModuleManager;
|
|
import dev.loki.lovisual.render.engine.renderer.Renderer2D;
|
|
import dev.loki.lovisual.render.engine.renderer.Renderer3D;
|
|
import dev.loki.lovisual.render.engine.text.TextRenderer;
|
|
import dev.loki.lovisual.util.logging.DebugLog;
|
|
import net.minecraft.client.gui.GuiGraphicsExtractor;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Map;
|
|
|
|
public enum ModuleExtensionManager {
|
|
;
|
|
|
|
private static final Map<String, List<RegisteredExtension>> EXTENSIONS = new LinkedHashMap<>();
|
|
|
|
public static boolean register(String addonId, String moduleId, LoVisualModuleExtension extension) {
|
|
if (extension == null || moduleId == null || moduleId.isBlank()) return false;
|
|
Module module = ModuleManager.get(moduleId);
|
|
if (module == null) {
|
|
DebugLog.warn("[Addons] Module extension target missing: addon=%s module=%s", addonId, moduleId);
|
|
return false;
|
|
}
|
|
String normalized = normalize(moduleId);
|
|
RegisteredExtension registered = new RegisteredExtension(addonId, extension);
|
|
EXTENSIONS.computeIfAbsent(normalized, ignored -> new ArrayList<>()).add(registered);
|
|
try {
|
|
extension.onRegister(new ModuleExtensionContextImpl(addonId, module));
|
|
} catch (Throwable t) {
|
|
DebugLog.error("[Addons] Module extension registration failed: %s", t, normalized);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static int count() {
|
|
int count = 0;
|
|
for (List<RegisteredExtension> list : EXTENSIONS.values()) {
|
|
count += list.size();
|
|
}
|
|
return count;
|
|
}
|
|
|
|
public static boolean beforeEnable(Module module) {
|
|
return all(module, extension -> extension.beforeEnable(module));
|
|
}
|
|
|
|
public static void afterEnable(Module module) {
|
|
each(module, extension -> extension.afterEnable(module));
|
|
}
|
|
|
|
public static boolean beforeDisable(Module module) {
|
|
return all(module, extension -> extension.beforeDisable(module));
|
|
}
|
|
|
|
public static void afterDisable(Module module) {
|
|
each(module, extension -> extension.afterDisable(module));
|
|
}
|
|
|
|
public static boolean beforeTick(Module module) {
|
|
return all(module, extension -> extension.beforeTick(module));
|
|
}
|
|
|
|
public static void afterTick(Module module) {
|
|
each(module, extension -> extension.afterTick(module));
|
|
}
|
|
|
|
public static boolean beforeFrame(Module module, float frameDeltaTicks) {
|
|
return all(module, extension -> extension.beforeFrame(module, frameDeltaTicks));
|
|
}
|
|
|
|
public static void afterFrame(Module module, float frameDeltaTicks) {
|
|
each(module, extension -> extension.afterFrame(module, frameDeltaTicks));
|
|
}
|
|
|
|
public static boolean beforeHudRender(Module module,
|
|
Renderer2D renderer,
|
|
TextRenderer textRenderer,
|
|
GuiGraphicsExtractor ctx,
|
|
float tickDelta) {
|
|
return all(module, extension -> extension.beforeHudRender(module, renderer, textRenderer, ctx, tickDelta));
|
|
}
|
|
|
|
public static void afterHudRender(Module module,
|
|
Renderer2D renderer,
|
|
TextRenderer textRenderer,
|
|
GuiGraphicsExtractor ctx,
|
|
float tickDelta) {
|
|
each(module, extension -> extension.afterHudRender(module, renderer, textRenderer, ctx, tickDelta));
|
|
}
|
|
|
|
public static boolean beforeWorldRender(Module module,
|
|
Renderer3D renderer,
|
|
Renderer3D depthRenderer,
|
|
float tickDelta) {
|
|
return all(module, extension -> extension.beforeWorldRender(module, renderer, depthRenderer, tickDelta));
|
|
}
|
|
|
|
public static void afterWorldRender(Module module,
|
|
Renderer3D renderer,
|
|
Renderer3D depthRenderer,
|
|
float tickDelta) {
|
|
each(module, extension -> extension.afterWorldRender(module, renderer, depthRenderer, tickDelta));
|
|
}
|
|
|
|
private static boolean all(Module module, ExtensionBooleanCall call) {
|
|
List<RegisteredExtension> extensions = extensions(module);
|
|
if (extensions.isEmpty()) return true;
|
|
boolean proceed = true;
|
|
for (RegisteredExtension registered : extensions) {
|
|
if (!AddonManager.isActive(registered.addonId())) continue;
|
|
try {
|
|
proceed &= call.invoke(registered.extension());
|
|
} catch (Throwable t) {
|
|
DebugLog.error("[Addons] Module extension hook failed: addon=%s module=%s",
|
|
t, registered.addonId(), module == null ? "" : module.name());
|
|
}
|
|
}
|
|
return proceed;
|
|
}
|
|
|
|
private static void each(Module module, ExtensionVoidCall call) {
|
|
List<RegisteredExtension> extensions = extensions(module);
|
|
if (extensions.isEmpty()) return;
|
|
for (RegisteredExtension registered : extensions) {
|
|
if (!AddonManager.isActive(registered.addonId())) continue;
|
|
try {
|
|
call.invoke(registered.extension());
|
|
} catch (Throwable t) {
|
|
DebugLog.error("[Addons] Module extension hook failed: addon=%s module=%s",
|
|
t, registered.addonId(), module == null ? "" : module.name());
|
|
}
|
|
}
|
|
}
|
|
|
|
private static List<RegisteredExtension> extensions(Module module) {
|
|
if (module == null) return List.of();
|
|
List<RegisteredExtension> list = EXTENSIONS.get(normalize(module.name()));
|
|
return list == null ? List.of() : List.copyOf(list);
|
|
}
|
|
|
|
private static String normalize(String id) {
|
|
return id == null ? "" : id.trim().toLowerCase(Locale.ROOT);
|
|
}
|
|
|
|
@FunctionalInterface
|
|
private interface ExtensionBooleanCall {
|
|
boolean invoke(LoVisualModuleExtension extension);
|
|
}
|
|
|
|
@FunctionalInterface
|
|
private interface ExtensionVoidCall {
|
|
void invoke(LoVisualModuleExtension extension);
|
|
}
|
|
|
|
private record RegisteredExtension(String addonId, LoVisualModuleExtension extension) {
|
|
}
|
|
}
|