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.render.iris.compat;
|
||||
|
||||
public enum IrisCompatibilityFeature {
|
||||
|
|
|
|||
|
|
@ -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.render.iris.compat;
|
||||
|
||||
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.render.iris.compat;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
|
|
|||
|
|
@ -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.render.iris.compat;
|
||||
|
||||
import java.util.Locale;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,4 @@
|
|||
/*
|
||||
* 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.render.iris.patch;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.io.IOException;
|
||||
|
|
|
|||
|
|
@ -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.render.iris.patch;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
|
|
|||
|
|
@ -1,52 +1,37 @@
|
|||
/*
|
||||
* 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.render.iris.patch;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import dev.loki.lovisual.render.iris.patch.ShaderPatchRepo.Manifest;
|
||||
import dev.loki.lovisual.render.iris.patch.ShaderPatchRepo.Repository;
|
||||
import dev.loki.lovisual.render.iris.patch.ShaderPatchRepo.Target;
|
||||
import dev.loki.lovisual.util.logging.DebugLog;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import dev.loki.lovisual.render.iris.patch.ShaderPatchCompiler;
|
||||
|
||||
/**
|
||||
* Higher-level orchestrator for shader-pack patches: manages the global
|
||||
* {@link Repository}, per-pack {@link Session}s, manifest registration and
|
||||
* diagnostics. JSON loading logic lives in {@link ShaderPatchRepo}.
|
||||
*/
|
||||
public enum ShaderPatchEngine {
|
||||
;
|
||||
private static final String INDEX_RESOURCE = "assets/lovisual/shaders/iris-patches/index.json";
|
||||
private static final CopyOnWriteArrayList<String> EXTRA_MANIFEST_RESOURCES = new CopyOnWriteArrayList<>();
|
||||
private static final AtomicReference<Repository> REPOSITORY = new AtomicReference<>(Repository.load(List.of()));
|
||||
private static final Map<String, String> DIAGNOSTICS = new ConcurrentHashMap<>();
|
||||
private static final ThreadLocal<String> LOADING_SHADER_PACK_NAME = new ThreadLocal<>();
|
||||
private static final AtomicReference<String> GLOBAL_LOADING_SHADER_PACK_NAME = new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* Legacy validation session: all repository manifests are visible. Runtime Iris hooks should use
|
||||
* {@link #newSession(String)} so LoVisual does not probe unrelated shaderpacks.
|
||||
*/
|
||||
public static Session newSession() {
|
||||
Repository repository = repository();
|
||||
return new Session("<all>", repository.targetsByPath, Set.copyOf(repository.manifestsById.keySet()), false);
|
||||
}
|
||||
/** Legacy validation session: all repository manifests are visible. */
|
||||
public static Session newSession() { Repository r = repository(); return new Session("<all>", r.targetsByPath(), Set.copyOf(r.manifestsById().keySet()), false); }
|
||||
|
||||
public static Session newSession(String shaderPackName) {
|
||||
Repository.Selection selection = repository().select(shaderPackName);
|
||||
return new Session(shaderPackName, selection.targetsByPath(), selection.manifestIds(), selection.nameGated());
|
||||
ShaderPatchRepo.Selection sel = repository().select(shaderPackName);
|
||||
return new Session(shaderPackName, sel.targetsByPath(), sel.manifestIds(), sel.nameGated());
|
||||
}
|
||||
|
||||
public static boolean registerManifestResource(String manifestResourcePath) {
|
||||
|
|
@ -60,10 +45,7 @@ public enum ShaderPatchEngine {
|
|||
}
|
||||
|
||||
public static void beginShaderPackLoad(String shaderPackName) {
|
||||
if (shaderPackName == null || shaderPackName.isBlank()) {
|
||||
LOADING_SHADER_PACK_NAME.remove();
|
||||
return;
|
||||
}
|
||||
if (shaderPackName == null || shaderPackName.isBlank()) { LOADING_SHADER_PACK_NAME.remove(); return; }
|
||||
LOADING_SHADER_PACK_NAME.set(shaderPackName);
|
||||
GLOBAL_LOADING_SHADER_PACK_NAME.set(shaderPackName);
|
||||
DebugLog.info("[IrisPatch] shaderpack load begin: '%s'", shaderPackName);
|
||||
|
|
@ -71,79 +53,38 @@ public enum ShaderPatchEngine {
|
|||
|
||||
public static void endShaderPackLoad(String shaderPackName) {
|
||||
String active = LOADING_SHADER_PACK_NAME.get();
|
||||
if (active != null && (shaderPackName == null || active.equals(shaderPackName))) {
|
||||
LOADING_SHADER_PACK_NAME.remove();
|
||||
}
|
||||
if (active != null && (shaderPackName == null || active.equals(shaderPackName))) LOADING_SHADER_PACK_NAME.remove();
|
||||
String global = GLOBAL_LOADING_SHADER_PACK_NAME.get();
|
||||
if (global != null && (shaderPackName == null || global.equals(shaderPackName))) {
|
||||
GLOBAL_LOADING_SHADER_PACK_NAME.compareAndSet(global, null);
|
||||
}
|
||||
if (global != null && (shaderPackName == null || global.equals(shaderPackName))) GLOBAL_LOADING_SHADER_PACK_NAME.compareAndSet(global, null);
|
||||
DebugLog.info("[IrisPatch] shaderpack load end: '%s'", shaderPackName == null ? "" : shaderPackName);
|
||||
}
|
||||
|
||||
public static String loadingShaderPackName() {
|
||||
String threadLocal = LOADING_SHADER_PACK_NAME.get();
|
||||
if (threadLocal != null && !threadLocal.isBlank()) {
|
||||
return threadLocal;
|
||||
}
|
||||
return GLOBAL_LOADING_SHADER_PACK_NAME.get();
|
||||
String t = LOADING_SHADER_PACK_NAME.get();
|
||||
return (t != null && !t.isBlank()) ? t : GLOBAL_LOADING_SHADER_PACK_NAME.get();
|
||||
}
|
||||
|
||||
public static List<String> diagnostics() {
|
||||
return DIAGNOSTICS.entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByKey())
|
||||
.map(entry -> entry.getKey() + ": " + entry.getValue())
|
||||
.toList();
|
||||
return DIAGNOSTICS.entrySet().stream().sorted(Map.Entry.comparingByKey()).map(e -> e.getKey() + ": " + e.getValue()).toList();
|
||||
}
|
||||
|
||||
public static List<String> targetPaths() {
|
||||
return repository().targetsByPath.keySet().stream().sorted().toList();
|
||||
}
|
||||
|
||||
public static List<String> targetPaths(String shaderPackName) {
|
||||
return repository().select(shaderPackName).targetsByPath.keySet().stream().sorted().toList();
|
||||
}
|
||||
|
||||
private static Repository repository() {
|
||||
return REPOSITORY.get();
|
||||
}
|
||||
|
||||
private static void setDiagnostic(Target target, String value) {
|
||||
DIAGNOSTICS.put(diagnosticKey(target), value);
|
||||
}
|
||||
|
||||
private static boolean contains(List<String> lines, String marker) {
|
||||
if (marker == null || marker.isBlank()) {
|
||||
return false;
|
||||
}
|
||||
for (String line : lines) {
|
||||
if (line.contains(marker)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String diagnosticKey(Target target) {
|
||||
return target.manifestId + " " + target.path;
|
||||
}
|
||||
|
||||
private static String normalizePath(String path) {
|
||||
String normalized = path.replace('\\', '/');
|
||||
return normalized.startsWith("/") ? normalized : "/" + normalized;
|
||||
}
|
||||
public static List<String> targetPaths() { return repository().targetsByPath().keySet().stream().sorted().toList(); }
|
||||
public static List<String> targetPaths(String shaderPackName) { return repository().select(shaderPackName).targetsByPath().keySet().stream().sorted().toList(); }
|
||||
|
||||
private static Repository repository() { return REPOSITORY.get(); }
|
||||
private static void setDiagnostic(Target target, String value) { DIAGNOSTICS.put(target.manifestId() + " " + target.path(), value); }
|
||||
private static boolean contains(List<String> lines, String marker) { return marker != null && !marker.isBlank() && lines.stream().anyMatch(l -> l.contains(marker)); }
|
||||
|
||||
private static String normalizeResourcePath(String path) {
|
||||
if (path == null || path.isBlank()) return "";
|
||||
String normalized = path.trim().replace('\\', '/');
|
||||
return normalized.startsWith("/") ? normalized.substring(1) : normalized;
|
||||
String n = path.trim().replace('\\', '/');
|
||||
return n.startsWith("/") ? n.substring(1) : n;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SourceProvider {
|
||||
ImmutableList<String> load(String path);
|
||||
}
|
||||
public interface SourceProvider { ImmutableList<String> load(String path); }
|
||||
|
||||
/** Per-shaderpack patch session; holds a filtered view of the repository and applies patches to GLSL source. */
|
||||
public static final class Session {
|
||||
private final String shaderPackName;
|
||||
private final Map<String, List<Target>> targetsByPath;
|
||||
|
|
@ -153,354 +94,53 @@ public enum ShaderPatchEngine {
|
|||
private final boolean nameGated;
|
||||
private boolean announced;
|
||||
|
||||
private Session(String shaderPackName,
|
||||
Map<String, List<Target>> targetsByPath,
|
||||
Set<String> activeManifestIds,
|
||||
boolean nameGated) {
|
||||
private Session(String shaderPackName, Map<String, List<Target>> targetsByPath, Set<String> activeManifestIds, boolean nameGated) {
|
||||
this.shaderPackName = shaderPackName == null ? "" : shaderPackName;
|
||||
this.targetsByPath = targetsByPath;
|
||||
this.activeManifestIds = activeManifestIds;
|
||||
this.nameGated = nameGated;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return !targetsByPath.isEmpty();
|
||||
}
|
||||
|
||||
public ImmutableList<String> patch(String path, ImmutableList<String> source, SourceProvider sourceProvider) {
|
||||
if (path == null || source == null || preflighting.get()) {
|
||||
return source;
|
||||
}
|
||||
public boolean isActive() { return !targetsByPath.isEmpty(); }
|
||||
|
||||
public ImmutableList<String> patch(String path, ImmutableList<String> source, SourceProvider sp) {
|
||||
if (path == null || source == null || preflighting.get()) return source;
|
||||
announceOnce();
|
||||
List<Target> candidates = targetsByPath.get(normalizePath(path));
|
||||
if (candidates == null || candidates.isEmpty()) {
|
||||
return source;
|
||||
}
|
||||
|
||||
DebugLog.renderThread("[IrisPatch] path=%s candidates=%d sourceLines=%d", normalizePath(path), candidates.size(), source.size());
|
||||
List<Target> candidates = targetsByPath.get(ShaderPatchRepo.normalizePath(path));
|
||||
if (candidates == null || candidates.isEmpty()) return source;
|
||||
for (Target target : candidates) {
|
||||
if (contains(source, target.marker)) {
|
||||
setDiagnostic(target, "already applied");
|
||||
DebugLog.renderThread("[IrisPatch] %s %s already applied marker=%s", target.manifestId, target.path, target.marker);
|
||||
return source;
|
||||
}
|
||||
boolean applicable = manifestApplicability.computeIfAbsent(
|
||||
target.manifestId,
|
||||
ignored -> preflight(target.manifestId, sourceProvider)
|
||||
);
|
||||
if (!applicable) {
|
||||
DebugLog.renderThread("[IrisPatch] %s %s skipped: manifest preflight rejected earlier", target.manifestId, target.path);
|
||||
continue;
|
||||
}
|
||||
if (contains(source, target.marker())) { setDiagnostic(target, "already applied"); return source; }
|
||||
if (!manifestApplicability.computeIfAbsent(target.manifestId(), id -> preflight(id, sp))) continue;
|
||||
try {
|
||||
ShaderPatchCompiler.CompiledPatch compiled = ShaderPatchCompiler.compile(
|
||||
target.program,
|
||||
source,
|
||||
ShaderPatchCompiler.CompileMode.APPLICATION,
|
||||
target.stages
|
||||
);
|
||||
ImmutableList<String> patched = ShaderPatchCompiler.apply(compiled, source);
|
||||
ShaderPatchCompiler.CompiledPatch compiled = ShaderPatchCompiler.compile(target.program(), source, ShaderPatchCompiler.CompileMode.APPLICATION, target.stages());
|
||||
setDiagnostic(target, "applied edits=" + compiled.edits().size());
|
||||
DebugLog.info("[IrisPatch] %s %s applied: schema=%d stages=%s edits=%d marker=%s",
|
||||
target.manifestId,
|
||||
target.path,
|
||||
target.program.schemaVersion(),
|
||||
target.stages,
|
||||
compiled.edits().size(),
|
||||
target.marker);
|
||||
return patched;
|
||||
} catch (ShaderPatchCompiler.CompileException e) {
|
||||
// Do not poison the whole manifest here. Actual source can already contain LoVisual-owned
|
||||
// includes from earlier targets, while preflight is the compatibility decision point.
|
||||
setDiagnostic(target, "rejected after preflight: " + e.getMessage());
|
||||
DebugLog.warn("[IrisPatch] %s %s rejected after preflight: %s", target.manifestId, target.path, e.getMessage());
|
||||
}
|
||||
DebugLog.info("[IrisPatch] %s %s applied edits=%d", target.manifestId(), target.path(), compiled.edits().size());
|
||||
return ShaderPatchCompiler.apply(compiled, source);
|
||||
} catch (ShaderPatchCompiler.CompileException e) { setDiagnostic(target, "rejected: " + e.getMessage()); }
|
||||
}
|
||||
|
||||
DebugLog.renderThread("[IrisPatch] path=%s no candidate applied", normalizePath(path));
|
||||
return source;
|
||||
}
|
||||
|
||||
private void announceOnce() {
|
||||
if (announced) {
|
||||
return;
|
||||
}
|
||||
if (announced) return;
|
||||
announced = true;
|
||||
if (targetsByPath.isEmpty()) {
|
||||
DebugLog.info("[IrisPatch] session inactive: shaderPack='%s' nameGated=%s matchedManifests=0", shaderPackName, nameGated);
|
||||
} else {
|
||||
DebugLog.info("[IrisPatch] session active: shaderPack='%s' nameGated=%s manifests=%d targetPaths=%d targets=%d",
|
||||
shaderPackName,
|
||||
nameGated,
|
||||
activeManifestIds.size(),
|
||||
targetsByPath.size(),
|
||||
targetsByPath.values().stream().mapToInt(List::size).sum());
|
||||
}
|
||||
DebugLog.info("[IrisPatch] session %s: shaderPack='%s' nameGated=%s manifests=%d paths=%d",
|
||||
targetsByPath.isEmpty() ? "inactive" : "active", shaderPackName, nameGated, activeManifestIds.size(), targetsByPath.size());
|
||||
}
|
||||
|
||||
private boolean preflight(String manifestId, SourceProvider sourceProvider) {
|
||||
Manifest manifest = repository().manifestsById.get(manifestId);
|
||||
if (manifest == null) {
|
||||
DebugLog.warn("[IrisPatch] preflight rejected: missing manifest %s", manifestId);
|
||||
return false;
|
||||
}
|
||||
if (!activeManifestIds.contains(manifestId)) {
|
||||
DebugLog.renderThread("[IrisPatch] preflight skipped: manifest=%s not selected for shaderPack='%s'", manifestId, shaderPackName);
|
||||
return false;
|
||||
}
|
||||
|
||||
DebugLog.info("[IrisPatch] preflight start: manifest=%s shaderPack='%s' targets=%d", manifestId, shaderPackName, manifest.targets.size());
|
||||
private boolean preflight(String manifestId, SourceProvider sp) {
|
||||
Manifest manifest = repository().manifestsById().get(manifestId);
|
||||
if (manifest == null || !activeManifestIds.contains(manifestId)) return false;
|
||||
preflighting.set(true);
|
||||
try {
|
||||
for (Target target : manifest.targets) {
|
||||
ImmutableList<String> source = sourceProvider.load(target.path);
|
||||
if (source == null) {
|
||||
setDiagnostic(target, "preflight rejected: source unavailable");
|
||||
DebugLog.warn("[IrisPatch] %s %s preflight rejected: source unavailable", target.manifestId, target.path);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
ShaderPatchCompiler.CompiledPatch compiled = ShaderPatchCompiler.compile(
|
||||
target.program,
|
||||
source,
|
||||
ShaderPatchCompiler.CompileMode.PREFLIGHT,
|
||||
target.stages
|
||||
);
|
||||
setDiagnostic(target, "preflight passed edits=" + compiled.edits().size());
|
||||
DebugLog.renderThread("[IrisPatch] %s %s preflight passed: schema=%d stages=%s sourceLines=%d edits=%d",
|
||||
target.manifestId,
|
||||
target.path,
|
||||
target.program.schemaVersion(),
|
||||
target.stages,
|
||||
source.size(),
|
||||
compiled.edits().size());
|
||||
} catch (ShaderPatchCompiler.CompileException e) {
|
||||
setDiagnostic(target, "preflight rejected: " + e.getMessage());
|
||||
DebugLog.warn("[IrisPatch] %s %s preflight rejected: %s", target.manifestId, target.path, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
for (Target target : manifest.targets()) {
|
||||
ImmutableList<String> source = sp.load(target.path());
|
||||
if (source == null) { setDiagnostic(target, "preflight rejected: source unavailable"); return false; }
|
||||
try { ShaderPatchCompiler.compile(target.program(), source, ShaderPatchCompiler.CompileMode.PREFLIGHT, target.stages()); }
|
||||
catch (ShaderPatchCompiler.CompileException e) { setDiagnostic(target, "preflight rejected: " + e.getMessage()); return false; }
|
||||
}
|
||||
DebugLog.info("[IrisPatch] preflight accepted: manifest=%s shaderPack='%s'", manifestId, shaderPackName);
|
||||
return true;
|
||||
} finally {
|
||||
preflighting.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private record Target(
|
||||
String manifestId,
|
||||
int priority,
|
||||
String path,
|
||||
String marker,
|
||||
Set<ShaderPatchCompiler.ShaderStage> stages,
|
||||
ShaderPatchCompiler.PatchProgram program
|
||||
) {
|
||||
}
|
||||
|
||||
private record Manifest(String id, int priority, Identity identity, List<Target> targets) {
|
||||
}
|
||||
|
||||
private record Identity(String family, String profileId, String policy, Pattern packNamePattern) {
|
||||
private boolean matches(String shaderPackName) {
|
||||
if (shaderPackName == null || shaderPackName.isBlank()) {
|
||||
return false;
|
||||
}
|
||||
if (packNamePattern != null) {
|
||||
return packNamePattern.matcher(shaderPackName).matches();
|
||||
}
|
||||
String normalized = shaderPackName.toLowerCase(Locale.ROOT);
|
||||
return normalized.contains(family.toLowerCase(Locale.ROOT)) || normalized.contains(profileId.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
|
||||
private record Repository(Map<String, List<Target>> targetsByPath, Map<String, Manifest> manifestsById) {
|
||||
|
||||
private static Repository load(List<String> extraManifestResources) {
|
||||
Map<String, List<Target>> targets = new HashMap<>();
|
||||
Map<String, Manifest> manifests = new HashMap<>();
|
||||
try {
|
||||
JsonObject index = readObject(INDEX_RESOURCE);
|
||||
requireSchema(index, INDEX_RESOURCE);
|
||||
for (JsonElement element : requireArray(index, "manifests")) {
|
||||
addManifest(targets, manifests, element.getAsString());
|
||||
}
|
||||
if (extraManifestResources != null) {
|
||||
for (String manifestResource : extraManifestResources) {
|
||||
addManifest(targets, manifests, manifestResource);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
DebugLog.error("[IrisPatch] Failed to load shader patch repository", e);
|
||||
}
|
||||
targets.replaceAll((path, list) -> list.stream()
|
||||
.sorted(Comparator.comparingInt(Target::priority).reversed())
|
||||
.toList());
|
||||
return new Repository(Map.copyOf(targets), Map.copyOf(manifests));
|
||||
}
|
||||
|
||||
private static void addManifest(Map<String, List<Target>> targets,
|
||||
Map<String, Manifest> manifests,
|
||||
String manifestResource)
|
||||
throws IOException, ShaderPatchCompiler.CompileException {
|
||||
Manifest manifest = loadManifest(manifestResource);
|
||||
if (manifests.putIfAbsent(manifest.id, manifest) != null) {
|
||||
throw new IllegalArgumentException("Duplicate shader patch manifest " + manifest.id);
|
||||
}
|
||||
for (Target target : manifest.targets) {
|
||||
targets.computeIfAbsent(target.path, ignored -> new ArrayList<>()).add(target);
|
||||
}
|
||||
}
|
||||
|
||||
private static Manifest loadManifest(String manifestPath)
|
||||
throws IOException, ShaderPatchCompiler.CompileException {
|
||||
JsonObject manifestJson = readObject(manifestPath);
|
||||
requireSchema(manifestJson, manifestPath);
|
||||
String manifestId = requireString(manifestJson, "id");
|
||||
int priority = manifestJson.has("priority") ? manifestJson.get("priority").getAsInt() : 0;
|
||||
Identity identity = readIdentity(requireObject(manifestJson, "identity"));
|
||||
|
||||
// Compatibility is descriptive. Runtime patchability is decided by preflight against the active pack.
|
||||
requireObject(manifestJson, "compatibility");
|
||||
|
||||
String base = parent(manifestPath);
|
||||
ArrayList<Target> targets = new ArrayList<>();
|
||||
for (JsonElement element : requireArray(manifestJson, "targets")) {
|
||||
JsonObject targetJson = element.getAsJsonObject();
|
||||
String path = normalizePath(requireString(targetJson, "path"));
|
||||
String patchPath = resolve(base, requireString(targetJson, "patch"));
|
||||
ShaderPatchCompiler.PatchProgram program;
|
||||
try (InputStreamReader reader = readResource(patchPath)) {
|
||||
program = ShaderPatchCompiler.parse(reader);
|
||||
}
|
||||
targets.add(new Target(
|
||||
manifestId,
|
||||
priority,
|
||||
path,
|
||||
requireString(targetJson, "marker"),
|
||||
readStages(targetJson),
|
||||
program
|
||||
));
|
||||
}
|
||||
if (targets.isEmpty()) {
|
||||
throw new IllegalArgumentException("Shader patch manifest has no targets: " + manifestId);
|
||||
}
|
||||
return new Manifest(manifestId, priority, identity, List.copyOf(targets));
|
||||
}
|
||||
|
||||
private static Set<ShaderPatchCompiler.ShaderStage> readStages(JsonObject targetJson)
|
||||
throws ShaderPatchCompiler.CompileException {
|
||||
if (targetJson.has("stage")) {
|
||||
return Set.of(ShaderPatchCompiler.ShaderStage.parse(targetJson.get("stage").getAsString()));
|
||||
}
|
||||
if (!targetJson.has("stages")) {
|
||||
return Set.of();
|
||||
}
|
||||
HashSet<ShaderPatchCompiler.ShaderStage> stages = new HashSet<>();
|
||||
JsonArray array = requireArray(targetJson, "stages");
|
||||
for (JsonElement element : array) {
|
||||
stages.add(ShaderPatchCompiler.ShaderStage.parse(element.getAsString()));
|
||||
}
|
||||
return Set.copyOf(stages);
|
||||
}
|
||||
|
||||
private static Identity readIdentity(JsonObject identity) {
|
||||
String family = requireString(identity, "family");
|
||||
String profile = requireString(identity, "profile");
|
||||
String policy = requireString(identity, "policy");
|
||||
Pattern namePattern = null;
|
||||
if (identity.has("packNameRegex")) {
|
||||
try {
|
||||
namePattern = Pattern.compile(identity.get("packNameRegex").getAsString(), Pattern.CASE_INSENSITIVE);
|
||||
} catch (PatternSyntaxException e) {
|
||||
throw new IllegalArgumentException("Invalid shaderpack identity regex", e);
|
||||
}
|
||||
}
|
||||
return new Identity(family, profile, policy, namePattern);
|
||||
}
|
||||
|
||||
private static JsonObject readObject(String resource) throws IOException {
|
||||
try (InputStreamReader reader = readResource(resource)) {
|
||||
return JsonParser.parseReader(reader).getAsJsonObject();
|
||||
}
|
||||
}
|
||||
|
||||
private static InputStreamReader readResource(String resource) throws IOException {
|
||||
InputStream stream = ShaderPatchEngine.class.getClassLoader().getResourceAsStream(resource);
|
||||
if (stream == null) {
|
||||
throw new IOException("Missing resource " + resource);
|
||||
}
|
||||
return new InputStreamReader(stream, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static void requireSchema(JsonObject object, String resource) {
|
||||
if (!object.has("schemaVersion") || object.get("schemaVersion").getAsInt() != 1) {
|
||||
throw new IllegalArgumentException("Unsupported shader patch manifest schema in " + resource);
|
||||
}
|
||||
}
|
||||
|
||||
private static JsonObject requireObject(JsonObject object, String key) {
|
||||
if (!object.has(key) || !object.get(key).isJsonObject()) {
|
||||
throw new IllegalArgumentException("Missing object " + key);
|
||||
}
|
||||
return object.getAsJsonObject(key);
|
||||
}
|
||||
|
||||
private static JsonArray requireArray(JsonObject object, String key) {
|
||||
if (!object.has(key) || !object.get(key).isJsonArray()) {
|
||||
throw new IllegalArgumentException("Missing array " + key);
|
||||
}
|
||||
return object.getAsJsonArray(key);
|
||||
}
|
||||
|
||||
private static String requireString(JsonObject object, String key) {
|
||||
if (!object.has(key) || !object.get(key).isJsonPrimitive()) {
|
||||
throw new IllegalArgumentException("Missing string " + key);
|
||||
}
|
||||
return object.get(key).getAsString();
|
||||
}
|
||||
|
||||
private static String parent(String path) {
|
||||
int separator = path.lastIndexOf('/');
|
||||
return separator < 0 ? "" : path.substring(0, separator + 1);
|
||||
}
|
||||
|
||||
private static String resolve(String base, String path) {
|
||||
return path.startsWith("/") ? path.substring(1) : base + path;
|
||||
}
|
||||
|
||||
private Selection select(String shaderPackName) {
|
||||
if (shaderPackName == null || shaderPackName.isBlank()) {
|
||||
return new Selection(Map.of(), Set.of(), true);
|
||||
}
|
||||
|
||||
HashSet<String> selectedManifests = new HashSet<>();
|
||||
for (Manifest manifest : manifestsById.values()) {
|
||||
if (manifest.identity.matches(shaderPackName)) {
|
||||
selectedManifests.add(manifest.id);
|
||||
}
|
||||
}
|
||||
if (selectedManifests.isEmpty()) {
|
||||
return new Selection(Map.of(), Set.of(), true);
|
||||
}
|
||||
|
||||
Map<String, List<Target>> selectedTargets = new HashMap<>();
|
||||
for (Map.Entry<String, List<Target>> entry : targetsByPath.entrySet()) {
|
||||
ArrayList<Target> list = new ArrayList<>();
|
||||
for (Target target : entry.getValue()) {
|
||||
if (selectedManifests.contains(target.manifestId)) {
|
||||
list.add(target);
|
||||
}
|
||||
}
|
||||
if (!list.isEmpty()) {
|
||||
selectedTargets.put(entry.getKey(), List.copyOf(list));
|
||||
}
|
||||
}
|
||||
return new Selection(Map.copyOf(selectedTargets), Set.copyOf(selectedManifests), true);
|
||||
}
|
||||
|
||||
private record Selection(Map<String, List<Target>> targetsByPath, Set<String> manifestIds, boolean nameGated) {
|
||||
} finally { preflighting.set(false); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,4 @@
|
|||
/*
|
||||
* 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.render.iris.patch;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.security.MessageDigest;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,4 @@
|
|||
/*
|
||||
* 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.render.iris.patch;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.ArrayList;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,158 @@
|
|||
package dev.loki.lovisual.render.iris.patch;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import dev.loki.lovisual.util.logging.DebugLog;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
/**
|
||||
* Repository that loads and indexes shader-patch manifests from JSON resources.
|
||||
* Extracted from {@link ShaderPatchEngine} to keep the facade under the file-size cap.
|
||||
* Sibling folder sharing the parent's package.
|
||||
*/
|
||||
final class ShaderPatchRepo {
|
||||
|
||||
static final String INDEX_RESOURCE = "assets/lovisual/shaders/iris-patches/index.json";
|
||||
|
||||
private ShaderPatchRepo() { }
|
||||
|
||||
record Target(String manifestId, int priority, String path, String marker,
|
||||
Set<ShaderPatchCompiler.ShaderStage> stages, ShaderPatchCompiler.PatchProgram program) { }
|
||||
|
||||
record Manifest(String id, int priority, Identity identity, List<Target> targets) { }
|
||||
|
||||
record Identity(String family, String profileId, String policy, Pattern packNamePattern) {
|
||||
boolean matches(String shaderPackName) {
|
||||
if (shaderPackName == null || shaderPackName.isBlank()) return false;
|
||||
if (packNamePattern != null) return packNamePattern.matcher(shaderPackName).matches();
|
||||
String n = shaderPackName.toLowerCase(Locale.ROOT);
|
||||
return n.contains(family.toLowerCase(Locale.ROOT)) || n.contains(profileId.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
|
||||
record Selection(Map<String, List<Target>> targetsByPath, Set<String> manifestIds, boolean nameGated) { }
|
||||
|
||||
record Repository(Map<String, List<Target>> targetsByPath, Map<String, Manifest> manifestsById) {
|
||||
|
||||
static Repository load(List<String> extraManifestResources) {
|
||||
Map<String, List<Target>> targets = new HashMap<>();
|
||||
Map<String, Manifest> manifests = new HashMap<>();
|
||||
try {
|
||||
JsonObject index = readObject(INDEX_RESOURCE);
|
||||
requireSchema(index, INDEX_RESOURCE);
|
||||
for (JsonElement el : requireArray(index, "manifests")) addManifest(targets, manifests, el.getAsString());
|
||||
if (extraManifestResources != null) for (String r : extraManifestResources) addManifest(targets, manifests, r);
|
||||
} catch (Exception e) { DebugLog.error("[IrisPatch] Failed to load shader patch repository", e); }
|
||||
targets.replaceAll((path, list) -> list.stream().sorted(Comparator.comparingInt(Target::priority).reversed()).toList());
|
||||
return new Repository(Map.copyOf(targets), Map.copyOf(manifests));
|
||||
}
|
||||
|
||||
Selection select(String shaderPackName) {
|
||||
if (shaderPackName == null || shaderPackName.isBlank()) return new Selection(Map.of(), Set.of(), true);
|
||||
HashSet<String> selected = new HashSet<>();
|
||||
for (Manifest m : manifestsById.values()) if (m.identity.matches(shaderPackName)) selected.add(m.id);
|
||||
if (selected.isEmpty()) return new Selection(Map.of(), Set.of(), true);
|
||||
Map<String, List<Target>> filtered = new HashMap<>();
|
||||
for (Map.Entry<String, List<Target>> e : targetsByPath.entrySet()) {
|
||||
List<Target> list = e.getValue().stream().filter(t -> selected.contains(t.manifestId)).toList();
|
||||
if (!list.isEmpty()) filtered.put(e.getKey(), list);
|
||||
}
|
||||
return new Selection(Map.copyOf(filtered), Set.copyOf(selected), true);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- JSON loading helpers ----------------------------------------------------------------
|
||||
|
||||
static String normalizePath(String path) {
|
||||
String n = path.replace('\\', '/');
|
||||
return n.startsWith("/") ? n : "/" + n;
|
||||
}
|
||||
|
||||
private static void addManifest(Map<String, List<Target>> targets, Map<String, Manifest> manifests, String resource)
|
||||
throws IOException, ShaderPatchCompiler.CompileException {
|
||||
Manifest manifest = loadManifest(resource);
|
||||
if (manifests.putIfAbsent(manifest.id, manifest) != null) throw new IllegalArgumentException("Duplicate shader patch manifest " + manifest.id);
|
||||
for (Target t : manifest.targets) targets.computeIfAbsent(t.path, ignored -> new ArrayList<>()).add(t);
|
||||
}
|
||||
|
||||
private static Manifest loadManifest(String manifestPath) throws IOException, ShaderPatchCompiler.CompileException {
|
||||
JsonObject json = readObject(manifestPath);
|
||||
requireSchema(json, manifestPath);
|
||||
String id = requireString(json, "id");
|
||||
int priority = json.has("priority") ? json.get("priority").getAsInt() : 0;
|
||||
Identity identity = readIdentity(requireObject(json, "identity"));
|
||||
requireObject(json, "compatibility");
|
||||
String base = parent(manifestPath);
|
||||
ArrayList<Target> targets = new ArrayList<>();
|
||||
for (JsonElement el : requireArray(json, "targets")) {
|
||||
JsonObject tj = el.getAsJsonObject();
|
||||
String path = normalizePath(requireString(tj, "path"));
|
||||
String patchPath = resolve(base, requireString(tj, "patch"));
|
||||
ShaderPatchCompiler.PatchProgram program;
|
||||
try (InputStreamReader reader = readResource(patchPath)) { program = ShaderPatchCompiler.parse(reader); }
|
||||
targets.add(new Target(id, priority, path, requireString(tj, "marker"), readStages(tj), program));
|
||||
}
|
||||
if (targets.isEmpty()) throw new IllegalArgumentException("Shader patch manifest has no targets: " + id);
|
||||
return new Manifest(id, priority, identity, List.copyOf(targets));
|
||||
}
|
||||
|
||||
private static Set<ShaderPatchCompiler.ShaderStage> readStages(JsonObject tj) throws ShaderPatchCompiler.CompileException {
|
||||
if (tj.has("stage")) return Set.of(ShaderPatchCompiler.ShaderStage.parse(tj.get("stage").getAsString()));
|
||||
if (!tj.has("stages")) return Set.of();
|
||||
HashSet<ShaderPatchCompiler.ShaderStage> stages = new HashSet<>();
|
||||
for (JsonElement el : requireArray(tj, "stages")) stages.add(ShaderPatchCompiler.ShaderStage.parse(el.getAsString()));
|
||||
return Set.copyOf(stages);
|
||||
}
|
||||
|
||||
private static Identity readIdentity(JsonObject obj) {
|
||||
String family = requireString(obj, "family"), profile = requireString(obj, "profile"), policy = requireString(obj, "policy");
|
||||
Pattern namePattern = null;
|
||||
if (obj.has("packNameRegex")) {
|
||||
try { namePattern = Pattern.compile(obj.get("packNameRegex").getAsString(), Pattern.CASE_INSENSITIVE); }
|
||||
catch (PatternSyntaxException e) { throw new IllegalArgumentException("Invalid shaderpack identity regex", e); }
|
||||
}
|
||||
return new Identity(family, profile, policy, namePattern);
|
||||
}
|
||||
|
||||
private static JsonObject readObject(String resource) throws IOException {
|
||||
try (InputStreamReader reader = readResource(resource)) { return JsonParser.parseReader(reader).getAsJsonObject(); }
|
||||
}
|
||||
|
||||
private static InputStreamReader readResource(String resource) throws IOException {
|
||||
InputStream s = ShaderPatchRepo.class.getClassLoader().getResourceAsStream(resource);
|
||||
if (s == null) throw new IOException("Missing resource " + resource);
|
||||
return new InputStreamReader(s, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static void requireSchema(JsonObject obj, String resource) {
|
||||
if (!obj.has("schemaVersion") || obj.get("schemaVersion").getAsInt() != 1)
|
||||
throw new IllegalArgumentException("Unsupported shader patch manifest schema in " + resource);
|
||||
}
|
||||
|
||||
private static JsonObject requireObject(JsonObject obj, String key) {
|
||||
if (!obj.has(key) || !obj.get(key).isJsonObject()) throw new IllegalArgumentException("Missing object " + key);
|
||||
return obj.getAsJsonObject(key);
|
||||
}
|
||||
|
||||
private static JsonArray requireArray(JsonObject obj, String key) {
|
||||
if (!obj.has(key) || !obj.get(key).isJsonArray()) throw new IllegalArgumentException("Missing array " + key);
|
||||
return obj.getAsJsonArray(key);
|
||||
}
|
||||
|
||||
private static String requireString(JsonObject obj, String key) {
|
||||
if (!obj.has(key) || !obj.get(key).isJsonPrimitive()) throw new IllegalArgumentException("Missing string " + key);
|
||||
return obj.get(key).getAsString();
|
||||
}
|
||||
|
||||
private static String parent(String path) { int i = path.lastIndexOf('/'); return i < 0 ? "" : path.substring(0, i + 1); }
|
||||
private static String resolve(String base, String path) { return path.startsWith("/") ? path.substring(1) : base + path; }
|
||||
}
|
||||
|
|
@ -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.render.iris.patch;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
|
|
|||
|
|
@ -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.render.iris.patch;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
|
|
|||
|
|
@ -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.render.iris.runtime;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
|
|
|||
|
|
@ -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.render.iris.runtime;
|
||||
|
||||
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||
|
|
|
|||
|
|
@ -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.render.iris.runtime;
|
||||
import dev.loki.lovisual.render.iris.compat.IrisCompatibilityProfile;
|
||||
|
||||
|
|
|
|||
|
|
@ -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.render.iris.runtime;
|
||||
|
||||
import net.irisshaders.iris.gl.uniform.UniformHolder;
|
||||
|
|
|
|||
|
|
@ -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.render.iris.scene;
|
||||
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
|
|
|
|||
|
|
@ -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.render.iris.scene;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
|
|
|||
|
|
@ -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.render.iris.scene;
|
||||
|
||||
import net.irisshaders.iris.pipeline.WorldRenderingPipeline;
|
||||
|
|
|
|||
|
|
@ -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.render.iris.state;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
|
|
|||
|
|
@ -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.render.iris.state;
|
||||
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue